2 * handles.c: Generic and internal operations on handles
5 * Dick Porter (dick@ximian.com)
7 * (C) 2002-2011 Novell, Inc.
8 * Copyright 2011 Xamarin Inc
20 #include <sys/types.h>
21 #ifdef HAVE_SYS_SOCKET_H
22 # include <sys/socket.h>
27 #ifdef HAVE_SYS_MMAN_H
28 # include <sys/mman.h>
34 #ifdef HAVE_SYS_RESOURCE_H
35 # include <sys/resource.h>
38 #include <mono/io-layer/wapi.h>
39 #include <mono/io-layer/wapi-private.h>
40 #include <mono/io-layer/handles-private.h>
41 #include <mono/io-layer/misc-private.h>
42 #include <mono/io-layer/shared.h>
43 #include <mono/io-layer/collection.h>
44 #include <mono/io-layer/process-private.h>
46 #include <mono/utils/mono-mutex.h>
47 #include <mono/utils/mono-proclib.h>
51 #define DEBUG(...) g_message(__VA_ARGS__)
56 static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer);
58 static WapiHandleCapability handle_caps[WAPI_HANDLE_COUNT]={0};
59 static struct _WapiHandleOps *handle_ops[WAPI_HANDLE_COUNT]={
67 #ifndef DISABLE_SOCKETS
73 &_wapi_namedmutex_ops,
75 &_wapi_namedevent_ops,
78 static void _wapi_shared_details (gpointer handle_info);
80 static void (*handle_details[WAPI_HANDLE_COUNT])(gpointer) = {
83 _wapi_console_details,
84 _wapi_shared_details, /* thread */
88 NULL, /* Nothing useful to see in a socket handle */
89 NULL, /* Nothing useful to see in a find handle */
90 _wapi_shared_details, /* process */
92 _wapi_shared_details, /* namedmutex */
93 _wapi_shared_details, /* namedsem */
94 _wapi_shared_details, /* namedevent */
97 const char *_wapi_handle_typename[] = {
116 * We can hold _WAPI_PRIVATE_MAX_SLOTS * _WAPI_HANDLE_INITIAL_COUNT handles.
117 * If 4M handles are not enough... Oh, well... we will crash.
119 #define SLOT_INDEX(x) (x / _WAPI_HANDLE_INITIAL_COUNT)
120 #define SLOT_OFFSET(x) (x % _WAPI_HANDLE_INITIAL_COUNT)
122 struct _WapiHandleUnshared *_wapi_private_handles [_WAPI_PRIVATE_MAX_SLOTS];
123 static guint32 _wapi_private_handle_count = 0;
124 static guint32 _wapi_private_handle_slot_count = 0;
126 struct _WapiHandleSharedLayout *_wapi_shared_layout = NULL;
129 * If SHM is enabled, this will point to shared memory, otherwise it will be NULL.
131 struct _WapiFileShareLayout *_wapi_fileshare_layout = NULL;
134 * If SHM is disabled, this will point to a hash of _WapiFileShare structures, otherwise
135 * it will be NULL. We use this instead of _wapi_fileshare_layout to avoid allocating a
138 static GHashTable *file_share_hash;
139 static mono_mutex_t file_share_hash_mutex;
141 #define file_share_hash_lock() mono_mutex_lock (&file_share_hash_mutex)
142 #define file_share_hash_unlock() mono_mutex_unlock (&file_share_hash_mutex)
144 guint32 _wapi_fd_reserve;
147 * This is an internal handle which is used for handling waiting for multiple handles.
148 * Threads which wait for multiple handles wait on this one handle, and when a handle
149 * is signalled, this handle is signalled too.
151 static gpointer _wapi_global_signal_handle;
153 /* Point to the mutex/cond inside _wapi_global_signal_handle */
154 mono_mutex_t *_wapi_global_signal_mutex;
155 pthread_cond_t *_wapi_global_signal_cond;
158 gboolean _wapi_has_shut_down = FALSE;
160 /* Use this instead of getpid(), to cope with linuxthreads. It's a
161 * function rather than a variable lookup because we need to get at
162 * this before share_init() might have been called.
164 static pid_t _wapi_pid;
165 static mono_once_t pid_init_once = MONO_ONCE_INIT;
167 static void _wapi_handle_unref_full (gpointer handle, gboolean ignore_private_busy_handles);
169 static void pid_init (void)
171 _wapi_pid = getpid ();
174 pid_t _wapi_getpid (void)
176 mono_once (&pid_init_once, pid_init);
182 static mono_mutex_t scan_mutex;
184 static void handle_cleanup (void)
188 /* Every shared handle we were using ought really to be closed
189 * by now, but to make sure just blow them all away. The
190 * exiting finalizer thread in particular races us to the
191 * program exit and doesn't always win, so it can be left
192 * cluttering up the shared file. Anything else left over is
195 for(i = SLOT_INDEX (0); _wapi_private_handles[i] != NULL; i++) {
196 for(j = SLOT_OFFSET (0); j < _WAPI_HANDLE_INITIAL_COUNT; j++) {
197 struct _WapiHandleUnshared *handle_data = &_wapi_private_handles[i][j];
198 gpointer handle = GINT_TO_POINTER (i*_WAPI_HANDLE_INITIAL_COUNT+j);
200 for(k = handle_data->ref; k > 0; k--) {
201 DEBUG ("%s: unreffing %s handle %p", __func__, _wapi_handle_typename[type], handle);
203 _wapi_handle_unref_full (handle, TRUE);
208 _wapi_shm_semaphores_remove ();
210 _wapi_shm_detach (WAPI_SHM_DATA);
211 _wapi_shm_detach (WAPI_SHM_FILESHARE);
213 if (file_share_hash) {
214 g_hash_table_destroy (file_share_hash);
215 mono_mutex_destroy (&file_share_hash_mutex);
218 for (i = 0; i < _WAPI_PRIVATE_MAX_SLOTS; ++i)
219 g_free (_wapi_private_handles [i]);
223 wapi_getdtablesize (void)
225 return eg_getdtablesize ();
231 * Initialize the io-layer.
236 g_assert ((sizeof (handle_ops) / sizeof (handle_ops[0]))
237 == WAPI_HANDLE_COUNT);
239 _wapi_fd_reserve = wapi_getdtablesize ();
241 /* This is needed by the code in _wapi_handle_new_internal */
242 _wapi_fd_reserve = (_wapi_fd_reserve + (_WAPI_HANDLE_INITIAL_COUNT - 1)) & ~(_WAPI_HANDLE_INITIAL_COUNT - 1);
246 * The entries in _wapi_private_handles reserved for fds are allocated lazily to
250 _wapi_private_handles [idx++] = g_new0 (struct _WapiHandleUnshared,
251 _WAPI_HANDLE_INITIAL_COUNT);
254 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
255 _wapi_private_handle_slot_count ++;
256 } while(_wapi_fd_reserve > _wapi_private_handle_count);
258 _wapi_shm_semaphores_init ();
260 _wapi_shared_layout = _wapi_shm_attach (WAPI_SHM_DATA);
261 g_assert (_wapi_shared_layout != NULL);
263 if (_wapi_shm_enabled ()) {
264 /* This allocates a 4mb array, so do it only if SHM is enabled */
265 _wapi_fileshare_layout = _wapi_shm_attach (WAPI_SHM_FILESHARE);
266 g_assert (_wapi_fileshare_layout != NULL);
269 #if !defined (DISABLE_SHARED_HANDLES)
270 if (_wapi_shm_enabled ())
271 _wapi_collection_init ();
274 mono_mutex_init (&scan_mutex);
276 _wapi_global_signal_handle = _wapi_handle_new (WAPI_HANDLE_EVENT, NULL);
278 _wapi_global_signal_cond = &_WAPI_PRIVATE_HANDLES (GPOINTER_TO_UINT (_wapi_global_signal_handle)).signal_cond;
279 _wapi_global_signal_mutex = &_WAPI_PRIVATE_HANDLES (GPOINTER_TO_UINT (_wapi_global_signal_handle)).signal_mutex;
281 wapi_processes_init ();
283 /* Using atexit here instead of an explicit function call in
284 * a cleanup routine lets us cope when a third-party library
285 * calls exit (eg if an X client loses the connection to its
288 mono_atexit (handle_cleanup);
294 g_assert (_wapi_has_shut_down == FALSE);
296 _wapi_has_shut_down = TRUE;
298 _wapi_error_cleanup ();
299 _wapi_thread_cleanup ();
300 wapi_processes_cleanup ();
303 static void _wapi_handle_init_shared (struct _WapiHandleShared *handle,
305 gpointer handle_specific)
307 g_assert (_wapi_has_shut_down == FALSE);
310 handle->timestamp = (guint32)(time (NULL) & 0xFFFFFFFF);
311 handle->signalled = FALSE;
312 handle->handle_refs = 1;
314 if (handle_specific != NULL) {
315 memcpy (&handle->u, handle_specific, sizeof (handle->u));
319 static size_t _wapi_handle_struct_size (WapiHandleType type)
324 case WAPI_HANDLE_FILE: case WAPI_HANDLE_CONSOLE: case WAPI_HANDLE_PIPE:
325 type_size = sizeof (struct _WapiHandle_file);
327 case WAPI_HANDLE_THREAD:
328 type_size = sizeof (struct _WapiHandle_thread);
330 case WAPI_HANDLE_SEM:
331 type_size = sizeof (struct _WapiHandle_sem);
333 case WAPI_HANDLE_MUTEX:
334 type_size = sizeof (struct _WapiHandle_mutex);
336 case WAPI_HANDLE_EVENT:
337 type_size = sizeof (struct _WapiHandle_event);
339 case WAPI_HANDLE_SOCKET:
340 type_size = sizeof (struct _WapiHandle_socket);
342 case WAPI_HANDLE_FIND:
343 type_size = sizeof (struct _WapiHandle_find);
345 case WAPI_HANDLE_PROCESS:
346 type_size = sizeof (struct _WapiHandle_process);
348 case WAPI_HANDLE_NAMEDMUTEX:
349 type_size = sizeof (struct _WapiHandle_namedmutex);
351 case WAPI_HANDLE_NAMEDSEM:
352 type_size = sizeof (struct _WapiHandle_namedsem);
354 case WAPI_HANDLE_NAMEDEVENT:
355 type_size = sizeof (struct _WapiHandle_namedevent);
359 g_error ("Unknown WapiHandleType: %d\n", type);
365 static void _wapi_handle_init (struct _WapiHandleUnshared *handle,
366 WapiHandleType type, gpointer handle_specific)
371 g_assert (_wapi_has_shut_down == FALSE);
374 handle->signalled = FALSE;
377 if (!_WAPI_SHARED_HANDLE(type)) {
378 thr_ret = pthread_cond_init (&handle->signal_cond, NULL);
379 g_assert (thr_ret == 0);
381 thr_ret = mono_mutex_init (&handle->signal_mutex);
382 g_assert (thr_ret == 0);
384 if (handle_specific != NULL) {
385 type_size = _wapi_handle_struct_size (type);
386 memcpy (&handle->u, handle_specific,
392 static guint32 _wapi_handle_new_shared (WapiHandleType type,
393 gpointer handle_specific)
396 static guint32 last = 1;
399 g_assert (_wapi_has_shut_down == FALSE);
401 /* Leave the first slot empty as a guard */
403 /* FIXME: expandable array */
404 for(offset = last; offset <_WAPI_HANDLE_INITIAL_COUNT; offset++) {
405 struct _WapiHandleShared *handle = &_wapi_shared_layout->handles[offset];
407 if(handle->type == WAPI_HANDLE_UNUSED) {
408 thr_ret = _wapi_handle_lock_shared_handles ();
409 g_assert (thr_ret == 0);
411 if (InterlockedCompareExchange ((gint32 *)&handle->type, type, WAPI_HANDLE_UNUSED) == WAPI_HANDLE_UNUSED) {
414 _wapi_handle_init_shared (handle, type,
417 _wapi_handle_unlock_shared_handles ();
421 /* Someone else beat us to it, just
426 _wapi_handle_unlock_shared_handles ();
431 /* Try again from the beginning */
436 /* Will need to expand the array. The caller will sort it out */
442 * _wapi_handle_new_internal:
443 * @type: Init handle to this type
445 * Search for a free handle and initialize it. Return the handle on
446 * success and 0 on failure. This is only called from
447 * _wapi_handle_new, and scan_mutex must be held.
449 static guint32 _wapi_handle_new_internal (WapiHandleType type,
450 gpointer handle_specific)
453 static guint32 last = 0;
454 gboolean retry = FALSE;
456 g_assert (_wapi_has_shut_down == FALSE);
458 /* A linear scan should be fast enough. Start from the last
459 * allocation, assuming that handles are allocated more often
460 * than they're freed. Leave the space reserved for file
464 if (last < _wapi_fd_reserve) {
465 last = _wapi_fd_reserve;
472 for(i = SLOT_INDEX (count); i < _wapi_private_handle_slot_count; i++) {
473 if (_wapi_private_handles [i]) {
474 for (k = SLOT_OFFSET (count); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
475 struct _WapiHandleUnshared *handle = &_wapi_private_handles [i][k];
477 if(handle->type == WAPI_HANDLE_UNUSED) {
480 _wapi_handle_init (handle, type, handle_specific);
488 if(retry && last > _wapi_fd_reserve) {
489 /* Try again from the beginning */
490 last = _wapi_fd_reserve;
494 /* Will need to expand the array. The caller will sort it out */
500 _wapi_handle_new (WapiHandleType type, gpointer handle_specific)
502 guint32 handle_idx = 0;
506 g_assert (_wapi_has_shut_down == FALSE);
508 DEBUG ("%s: Creating new handle of type %s", __func__,
509 _wapi_handle_typename[type]);
511 g_assert(!_WAPI_FD_HANDLE(type));
513 thr_ret = mono_mutex_lock (&scan_mutex);
514 g_assert (thr_ret == 0);
516 while ((handle_idx = _wapi_handle_new_internal (type, handle_specific)) == 0) {
517 /* Try and expand the array, and have another go */
518 int idx = SLOT_INDEX (_wapi_private_handle_count);
519 if (idx >= _WAPI_PRIVATE_MAX_SLOTS) {
523 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
524 _WAPI_HANDLE_INITIAL_COUNT);
526 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
527 _wapi_private_handle_slot_count ++;
530 thr_ret = mono_mutex_unlock (&scan_mutex);
531 g_assert (thr_ret == 0);
533 if (handle_idx == 0) {
534 /* We ran out of slots */
535 handle = _WAPI_HANDLE_INVALID;
539 /* Make sure we left the space for fd mappings */
540 g_assert (handle_idx >= _wapi_fd_reserve);
542 handle = GUINT_TO_POINTER (handle_idx);
544 DEBUG ("%s: Allocated new handle %p", __func__, handle);
546 if (_WAPI_SHARED_HANDLE(type)) {
547 /* Add the shared section too */
550 ref = _wapi_handle_new_shared (type, handle_specific);
552 _wapi_handle_collect ();
553 ref = _wapi_handle_new_shared (type, handle_specific);
555 /* FIXME: grow the arrays */
556 handle = _WAPI_HANDLE_INVALID;
561 _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = ref;
562 DEBUG ("%s: New shared handle at offset 0x%x", __func__,
570 gpointer _wapi_handle_new_from_offset (WapiHandleType type, guint32 offset,
573 guint32 handle_idx = 0;
574 gpointer handle = INVALID_HANDLE_VALUE;
576 struct _WapiHandleShared *shared;
578 g_assert (_wapi_has_shut_down == FALSE);
580 DEBUG ("%s: Creating new handle of type %s to offset %d", __func__,
581 _wapi_handle_typename[type], offset);
583 g_assert(!_WAPI_FD_HANDLE(type));
584 g_assert(_WAPI_SHARED_HANDLE(type));
585 g_assert(offset != 0);
587 shared = &_wapi_shared_layout->handles[offset];
589 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
590 /* Bump up the timestamp for this offset */
591 InterlockedExchange ((gint32 *)&shared->timestamp, now);
594 thr_ret = mono_mutex_lock (&scan_mutex);
595 g_assert (thr_ret == 0);
597 for (i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
598 if (_wapi_private_handles [i]) {
599 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
600 struct _WapiHandleUnshared *handle_data = &_wapi_private_handles [i][k];
602 if (handle_data->type == type &&
603 handle_data->u.shared.offset == offset) {
604 handle = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
605 goto first_pass_done;
612 thr_ret = mono_mutex_unlock (&scan_mutex);
613 g_assert (thr_ret == 0);
615 if (handle != INVALID_HANDLE_VALUE) {
616 _wapi_handle_ref (handle);
618 DEBUG ("%s: Returning old handle %p referencing 0x%x",
619 __func__, handle, offset);
623 /* Prevent entries expiring under us as we search */
624 thr_ret = _wapi_handle_lock_shared_handles ();
625 g_assert (thr_ret == 0);
627 if (shared->type == WAPI_HANDLE_UNUSED) {
628 /* Someone deleted this handle while we were working */
629 DEBUG ("%s: Handle at 0x%x unused", __func__, offset);
633 if (shared->type != type) {
634 DEBUG ("%s: Wrong type at %d 0x%x! Found %s wanted %s",
635 __func__, offset, offset,
636 _wapi_handle_typename[shared->type],
637 _wapi_handle_typename[type]);
641 thr_ret = mono_mutex_lock (&scan_mutex);
642 g_assert (thr_ret == 0);
644 while ((handle_idx = _wapi_handle_new_internal (type, NULL)) == 0) {
645 /* Try and expand the array, and have another go */
646 int idx = SLOT_INDEX (_wapi_private_handle_count);
647 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
648 _WAPI_HANDLE_INITIAL_COUNT);
650 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
651 _wapi_private_handle_slot_count ++;
654 thr_ret = mono_mutex_unlock (&scan_mutex);
655 g_assert (thr_ret == 0);
657 /* Make sure we left the space for fd mappings */
658 g_assert (handle_idx >= _wapi_fd_reserve);
660 handle = GUINT_TO_POINTER (handle_idx);
662 _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = offset;
663 InterlockedIncrement ((gint32 *)&shared->handle_refs);
665 DEBUG ("%s: Allocated new handle %p referencing 0x%x (shared refs %d)", __func__, handle, offset, shared->handle_refs);
668 _wapi_handle_unlock_shared_handles ();
674 init_handles_slot (int idx)
678 thr_ret = mono_mutex_lock (&scan_mutex);
679 g_assert (thr_ret == 0);
681 if (_wapi_private_handles [idx] == NULL) {
682 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
683 _WAPI_HANDLE_INITIAL_COUNT);
684 g_assert (_wapi_private_handles [idx]);
687 thr_ret = mono_mutex_unlock (&scan_mutex);
688 g_assert (thr_ret == 0);
691 gpointer _wapi_handle_new_fd (WapiHandleType type, int fd,
692 gpointer handle_specific)
694 struct _WapiHandleUnshared *handle;
697 g_assert (_wapi_has_shut_down == FALSE);
699 DEBUG ("%s: Creating new handle of type %s", __func__,
700 _wapi_handle_typename[type]);
702 g_assert(_WAPI_FD_HANDLE(type));
703 g_assert(!_WAPI_SHARED_HANDLE(type));
705 if (fd >= _wapi_fd_reserve) {
706 DEBUG ("%s: fd %d is too big", __func__, fd);
708 return(GUINT_TO_POINTER (_WAPI_HANDLE_INVALID));
711 /* Initialize the array entries on demand */
712 if (_wapi_private_handles [SLOT_INDEX (fd)] == NULL)
713 init_handles_slot (SLOT_INDEX (fd));
715 handle = &_WAPI_PRIVATE_HANDLES(fd);
717 if (handle->type != WAPI_HANDLE_UNUSED) {
718 DEBUG ("%s: fd %d is already in use!", __func__, fd);
719 /* FIXME: clean up this handle? We can't do anything
720 * with the fd, cos thats the new one
724 DEBUG ("%s: Assigning new fd handle %d", __func__, fd);
726 /* Prevent file share entries racing with us, when the file
727 * handle is only half initialised
729 thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
730 g_assert(thr_ret == 0);
732 _wapi_handle_init (handle, type, handle_specific);
734 thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
736 return(GUINT_TO_POINTER(fd));
739 gboolean _wapi_lookup_handle (gpointer handle, WapiHandleType type,
740 gpointer *handle_specific)
742 struct _WapiHandleUnshared *handle_data;
743 guint32 handle_idx = GPOINTER_TO_UINT(handle);
745 if (!_WAPI_PRIVATE_VALID_SLOT (handle_idx)) {
749 /* Initialize the array entries on demand */
750 if (_wapi_private_handles [SLOT_INDEX (handle_idx)] == NULL)
751 init_handles_slot (SLOT_INDEX (handle_idx));
753 handle_data = &_WAPI_PRIVATE_HANDLES(handle_idx);
755 if (handle_data->type != type) {
759 if (handle_specific == NULL) {
763 if (_WAPI_SHARED_HANDLE(type)) {
764 struct _WapiHandle_shared_ref *ref;
765 struct _WapiHandleShared *shared_handle_data;
767 ref = &handle_data->u.shared;
768 shared_handle_data = &_wapi_shared_layout->handles[ref->offset];
770 if (shared_handle_data->type != type) {
771 /* The handle must have been deleted on us
776 *handle_specific = &shared_handle_data->u;
778 *handle_specific = &handle_data->u;
785 _wapi_handle_foreach (WapiHandleType type,
786 gboolean (*on_each)(gpointer test, gpointer user),
789 struct _WapiHandleUnshared *handle_data = NULL;
794 thr_ret = mono_mutex_lock (&scan_mutex);
795 g_assert (thr_ret == 0);
797 for (i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
798 if (_wapi_private_handles [i]) {
799 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
800 handle_data = &_wapi_private_handles [i][k];
802 if (handle_data->type == type) {
803 ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
804 if (on_each (ret, user_data) == TRUE)
811 thr_ret = mono_mutex_unlock (&scan_mutex);
812 g_assert (thr_ret == 0);
815 /* This might list some shared handles twice if they are already
816 * opened by this process, and the check function returns FALSE the
817 * first time. Shared handles that are created during the search are
818 * unreffed if the check function returns FALSE, so callers must not
819 * rely on the handle persisting (unless the check function returns
821 * The caller owns the returned handle.
823 gpointer _wapi_search_handle (WapiHandleType type,
824 gboolean (*check)(gpointer test, gpointer user),
826 gpointer *handle_specific,
827 gboolean search_shared)
829 struct _WapiHandleUnshared *handle_data = NULL;
830 struct _WapiHandleShared *shared = NULL;
833 gboolean found = FALSE;
836 thr_ret = mono_mutex_lock (&scan_mutex);
837 g_assert (thr_ret == 0);
839 for (i = SLOT_INDEX (0); !found && i < _wapi_private_handle_slot_count; i++) {
840 if (_wapi_private_handles [i]) {
841 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
842 handle_data = &_wapi_private_handles [i][k];
844 if (handle_data->type == type) {
845 ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
846 if (check (ret, user_data) == TRUE) {
847 _wapi_handle_ref (ret);
850 if (_WAPI_SHARED_HANDLE (type)) {
851 shared = &_wapi_shared_layout->handles[i];
861 thr_ret = mono_mutex_unlock (&scan_mutex);
862 g_assert (thr_ret == 0);
864 if (!found && search_shared && _WAPI_SHARED_HANDLE (type)) {
865 /* Not found yet, so search the shared memory too */
866 DEBUG ("%s: Looking at other shared handles...", __func__);
868 for (i = 0; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
869 shared = &_wapi_shared_layout->handles[i];
871 if (shared->type == type) {
872 /* Tell new_from_offset to not
873 * timestamp this handle, because
874 * otherwise it will ping every handle
875 * in the list and they will never
878 ret = _wapi_handle_new_from_offset (type, i,
880 if (ret == INVALID_HANDLE_VALUE) {
881 /* This handle was deleted
882 * while we were looking at it
887 DEBUG ("%s: Opened tmp handle %p (type %s) from offset %d", __func__, ret, _wapi_handle_typename[type], i);
889 /* It's possible that the shared part
890 * of this handle has now been blown
891 * away (after new_from_offset
892 * successfully opened it,) if its
893 * timestamp is too old. The check
894 * function needs to be aware of this,
895 * and cope if the handle has
898 if (check (ret, user_data) == TRUE) {
899 /* Timestamp this handle, but make
900 * sure it still exists first
902 thr_ret = _wapi_handle_lock_shared_handles ();
903 g_assert (thr_ret == 0);
905 if (shared->type == type) {
906 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
907 InterlockedExchange ((gint32 *)&shared->timestamp, now);
910 handle_data = &_WAPI_PRIVATE_HANDLES(GPOINTER_TO_UINT(ret));
912 _wapi_handle_unlock_shared_handles ();
915 /* It's been deleted,
919 _wapi_handle_unlock_shared_handles ();
923 /* This isn't the handle we're looking
924 * for, so drop the reference we took
925 * in _wapi_handle_new_from_offset ()
927 _wapi_handle_unref (ret);
937 if(handle_specific != NULL) {
938 if (_WAPI_SHARED_HANDLE(type)) {
939 g_assert(shared->type == type);
941 *handle_specific = &shared->u;
943 *handle_specific = &handle_data->u;
951 /* Returns the offset of the metadata array, or -1 on error, or 0 for
952 * not found (0 is not a valid offset)
954 gint32 _wapi_search_handle_namespace (WapiHandleType type,
957 struct _WapiHandleShared *shared_handle_data;
962 g_assert(_WAPI_SHARED_HANDLE(type));
964 DEBUG ("%s: Lookup for handle named [%s] type %s", __func__,
965 utf8_name, _wapi_handle_typename[type]);
967 /* Do a handle collection before starting to look, so that any
968 * stale cruft gets removed
970 _wapi_handle_collect ();
972 thr_ret = _wapi_handle_lock_shared_handles ();
973 g_assert (thr_ret == 0);
975 for(i = 1; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
976 WapiSharedNamespace *sharedns;
978 shared_handle_data = &_wapi_shared_layout->handles[i];
980 /* Check mutex, event, semaphore, timer, job and
981 * file-mapping object names. So far only mutex,
982 * semaphore and event are implemented.
984 if (!_WAPI_SHARED_NAMESPACE (shared_handle_data->type)) {
988 DEBUG ("%s: found a shared namespace handle at 0x%x (type %s)", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
990 sharedns=(WapiSharedNamespace *)&shared_handle_data->u;
992 DEBUG ("%s: name is [%s]", __func__, sharedns->name);
994 if (strcmp (sharedns->name, utf8_name) == 0) {
995 if (shared_handle_data->type != type) {
996 /* Its the wrong type, so fail now */
997 DEBUG ("%s: handle 0x%x matches name but is wrong type: %s", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
1001 DEBUG ("%s: handle 0x%x matches name and type", __func__, i);
1009 _wapi_handle_unlock_shared_handles ();
1014 void _wapi_handle_ref (gpointer handle)
1016 guint32 idx = GPOINTER_TO_UINT(handle);
1017 struct _WapiHandleUnshared *handle_data;
1019 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1023 if (_wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) {
1024 g_warning ("%s: Attempting to ref unused handle %p", __func__,
1029 handle_data = &_WAPI_PRIVATE_HANDLES(idx);
1031 InterlockedIncrement ((gint32 *)&handle_data->ref);
1033 /* It's possible for processes to exit before getting around
1034 * to updating timestamps in the collection thread, so if a
1035 * shared handle is reffed do the timestamp here as well just
1038 if (_WAPI_SHARED_HANDLE(handle_data->type)) {
1039 struct _WapiHandleShared *shared_data = &_wapi_shared_layout->handles[handle_data->u.shared.offset];
1040 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
1041 InterlockedExchange ((gint32 *)&shared_data->timestamp, now);
1045 g_message ("%s: %s handle %p ref now %d", __func__,
1046 _wapi_handle_typename[_WAPI_PRIVATE_HANDLES (idx).type],
1048 _WAPI_PRIVATE_HANDLES(idx).ref);
1052 /* The handle must not be locked on entry to this function */
1053 static void _wapi_handle_unref_full (gpointer handle, gboolean ignore_private_busy_handles)
1055 guint32 idx = GPOINTER_TO_UINT(handle);
1056 gboolean destroy = FALSE, early_exit = FALSE;
1059 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1063 if (_wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) {
1064 g_warning ("%s: Attempting to unref unused handle %p",
1069 /* Possible race condition here if another thread refs the
1070 * handle between here and setting the type to UNUSED. I
1071 * could lock a mutex, but I'm not sure that allowing a handle
1072 * reference to reach 0 isn't an application bug anyway.
1074 destroy = (InterlockedDecrement ((gint32 *)&_WAPI_PRIVATE_HANDLES(idx).ref) ==0);
1077 g_message ("%s: %s handle %p ref now %d (destroy %s)", __func__,
1078 _wapi_handle_typename[_WAPI_PRIVATE_HANDLES (idx).type],
1080 _WAPI_PRIVATE_HANDLES(idx).ref, destroy?"TRUE":"FALSE");
1084 /* Need to copy the handle info, reset the slot in the
1085 * array, and _only then_ call the close function to
1086 * avoid race conditions (eg file descriptors being
1087 * closed, and another file being opened getting the
1088 * same fd racing the memset())
1090 struct _WapiHandleUnshared handle_data;
1091 struct _WapiHandleShared shared_handle_data;
1092 WapiHandleType type = _WAPI_PRIVATE_HANDLES(idx).type;
1093 void (*close_func)(gpointer, gpointer) = _wapi_handle_ops_get_close_func (type);
1094 gboolean is_shared = _WAPI_SHARED_HANDLE(type);
1097 /* If this is a shared handle we need to take
1098 * the shared lock outside of the scan_mutex
1099 * lock to avoid deadlocks
1101 thr_ret = _wapi_handle_lock_shared_handles ();
1102 g_assert (thr_ret == 0);
1105 thr_ret = mono_mutex_lock (&scan_mutex);
1107 DEBUG ("%s: Destroying handle %p", __func__, handle);
1109 memcpy (&handle_data, &_WAPI_PRIVATE_HANDLES(idx),
1110 sizeof (struct _WapiHandleUnshared));
1112 memset (&_WAPI_PRIVATE_HANDLES(idx).u, '\0',
1113 sizeof(_WAPI_PRIVATE_HANDLES(idx).u));
1115 _WAPI_PRIVATE_HANDLES(idx).type = WAPI_HANDLE_UNUSED;
1118 /* Destroy the mutex and cond var. We hope nobody
1119 * tried to grab them between the handle unlock and
1120 * now, but pthreads doesn't have a
1121 * "unlock_and_destroy" atomic function.
1123 thr_ret = mono_mutex_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_mutex);
1124 /*WARNING gross hack to make cleanup not crash when exiting without the whole runtime teardown.*/
1125 if (thr_ret == EBUSY && ignore_private_busy_handles) {
1129 g_error ("Error destroying handle %p mutex due to %d\n", handle, thr_ret);
1131 thr_ret = pthread_cond_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_cond);
1132 if (thr_ret == EBUSY && ignore_private_busy_handles)
1134 else if (thr_ret != 0)
1135 g_error ("Error destroying handle %p cond var due to %d\n", handle, thr_ret);
1138 struct _WapiHandleShared *shared = &_wapi_shared_layout->handles[handle_data.u.shared.offset];
1140 memcpy (&shared_handle_data, shared,
1141 sizeof (struct _WapiHandleShared));
1143 /* It's possible that this handle is already
1144 * pointing at a deleted shared section
1147 g_message ("%s: %s handle %p shared refs before dec %d", __func__, _wapi_handle_typename[type], handle, shared->handle_refs);
1150 if (shared->handle_refs > 0) {
1151 shared->handle_refs--;
1152 if (shared->handle_refs == 0) {
1153 memset (shared, '\0', sizeof (struct _WapiHandleShared));
1158 thr_ret = mono_mutex_unlock (&scan_mutex);
1159 g_assert (thr_ret == 0);
1164 _wapi_handle_unlock_shared_handles ();
1167 if (close_func != NULL) {
1169 close_func (handle, &shared_handle_data.u);
1171 close_func (handle, &handle_data.u);
1177 void _wapi_handle_unref (gpointer handle)
1179 _wapi_handle_unref_full (handle, FALSE);
1182 void _wapi_handle_register_capabilities (WapiHandleType type,
1183 WapiHandleCapability caps)
1185 handle_caps[type] = caps;
1188 gboolean _wapi_handle_test_capabilities (gpointer handle,
1189 WapiHandleCapability caps)
1191 guint32 idx = GPOINTER_TO_UINT(handle);
1192 WapiHandleType type;
1194 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1198 type = _WAPI_PRIVATE_HANDLES(idx).type;
1200 DEBUG ("%s: testing 0x%x against 0x%x (%d)", __func__,
1201 handle_caps[type], caps, handle_caps[type] & caps);
1203 return((handle_caps[type] & caps) != 0);
1206 static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer)
1208 if (handle_ops[type] != NULL &&
1209 handle_ops[type]->close != NULL) {
1210 return (handle_ops[type]->close);
1216 void _wapi_handle_ops_close (gpointer handle, gpointer data)
1218 guint32 idx = GPOINTER_TO_UINT(handle);
1219 WapiHandleType type;
1221 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1225 type = _WAPI_PRIVATE_HANDLES(idx).type;
1227 if (handle_ops[type] != NULL &&
1228 handle_ops[type]->close != NULL) {
1229 handle_ops[type]->close (handle, data);
1233 void _wapi_handle_ops_signal (gpointer handle)
1235 guint32 idx = GPOINTER_TO_UINT(handle);
1236 WapiHandleType type;
1238 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1242 type = _WAPI_PRIVATE_HANDLES(idx).type;
1244 if (handle_ops[type] != NULL && handle_ops[type]->signal != NULL) {
1245 handle_ops[type]->signal (handle);
1249 gboolean _wapi_handle_ops_own (gpointer handle)
1251 guint32 idx = GPOINTER_TO_UINT(handle);
1252 WapiHandleType type;
1254 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1258 type = _WAPI_PRIVATE_HANDLES(idx).type;
1260 if (handle_ops[type] != NULL && handle_ops[type]->own_handle != NULL) {
1261 return(handle_ops[type]->own_handle (handle));
1267 gboolean _wapi_handle_ops_isowned (gpointer handle)
1269 guint32 idx = GPOINTER_TO_UINT(handle);
1270 WapiHandleType type;
1272 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1276 type = _WAPI_PRIVATE_HANDLES(idx).type;
1278 if (handle_ops[type] != NULL && handle_ops[type]->is_owned != NULL) {
1279 return(handle_ops[type]->is_owned (handle));
1285 guint32 _wapi_handle_ops_special_wait (gpointer handle, guint32 timeout, gboolean alertable)
1287 guint32 idx = GPOINTER_TO_UINT(handle);
1288 WapiHandleType type;
1290 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1291 return(WAIT_FAILED);
1294 type = _WAPI_PRIVATE_HANDLES(idx).type;
1296 if (handle_ops[type] != NULL &&
1297 handle_ops[type]->special_wait != NULL) {
1298 return(handle_ops[type]->special_wait (handle, timeout, alertable));
1300 return(WAIT_FAILED);
1304 void _wapi_handle_ops_prewait (gpointer handle)
1306 guint32 idx = GPOINTER_TO_UINT (handle);
1307 WapiHandleType type;
1309 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1313 type = _WAPI_PRIVATE_HANDLES (idx).type;
1315 if (handle_ops[type] != NULL &&
1316 handle_ops[type]->prewait != NULL) {
1317 handle_ops[type]->prewait (handle);
1324 * @handle: The handle to release
1326 * Closes and invalidates @handle, releasing any resources it
1327 * consumes. When the last handle to a temporary or non-persistent
1328 * object is closed, that object can be deleted. Closing the same
1329 * handle twice is an error.
1331 * Return value: %TRUE on success, %FALSE otherwise.
1333 gboolean CloseHandle(gpointer handle)
1335 if (handle == NULL) {
1336 /* Problem: because we map file descriptors to the
1337 * same-numbered handle we can't tell the difference
1338 * between a bogus handle and the handle to stdin.
1339 * Assume that it's the console handle if that handle
1342 if (_WAPI_PRIVATE_HANDLES (0).type != WAPI_HANDLE_CONSOLE) {
1343 SetLastError (ERROR_INVALID_PARAMETER);
1347 if (handle == _WAPI_HANDLE_INVALID){
1348 SetLastError (ERROR_INVALID_PARAMETER);
1352 _wapi_handle_unref (handle);
1357 /* Lots more to implement here, but this is all we need at the moment */
1358 gboolean DuplicateHandle (gpointer srcprocess, gpointer src,
1359 gpointer targetprocess, gpointer *target,
1360 guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, guint32 options G_GNUC_UNUSED)
1362 if (srcprocess != _WAPI_PROCESS_CURRENT ||
1363 targetprocess != _WAPI_PROCESS_CURRENT) {
1364 /* Duplicating other process's handles is not supported */
1365 SetLastError (ERROR_INVALID_HANDLE);
1369 if (src == _WAPI_PROCESS_CURRENT) {
1370 *target = _wapi_process_duplicate ();
1371 } else if (src == _WAPI_THREAD_CURRENT) {
1372 g_assert_not_reached ();
1374 _wapi_handle_ref (src);
1381 gboolean _wapi_handle_count_signalled_handles (guint32 numhandles,
1387 guint32 count, i, iter=0;
1390 WapiHandleType type;
1392 /* Lock all the handles, with backoff */
1394 thr_ret = _wapi_handle_lock_shared_handles ();
1395 g_assert (thr_ret == 0);
1397 for(i=0; i<numhandles; i++) {
1398 gpointer handle = handles[i];
1399 guint32 idx = GPOINTER_TO_UINT(handle);
1401 DEBUG ("%s: attempting to lock %p", __func__, handle);
1403 type = _WAPI_PRIVATE_HANDLES(idx).type;
1405 thr_ret = _wapi_handle_trylock_handle (handle);
1410 DEBUG ("%s: attempt failed for %p: %s", __func__,
1411 handle, strerror (thr_ret));
1413 thr_ret = _wapi_handle_unlock_shared_handles ();
1414 g_assert (thr_ret == 0);
1417 handle = handles[i];
1418 idx = GPOINTER_TO_UINT(handle);
1420 thr_ret = _wapi_handle_unlock_handle (handle);
1421 g_assert (thr_ret == 0);
1424 /* If iter ever reaches 100 the nanosleep will
1425 * return EINVAL immediately, but we have a
1426 * design flaw if that happens.
1430 g_warning ("%s: iteration overflow!",
1435 DEBUG ("%s: Backing off for %d ms", __func__,
1437 _wapi_handle_spin (10 * iter);
1443 DEBUG ("%s: Locked all handles", __func__);
1448 for(i=0; i<numhandles; i++) {
1449 gpointer handle = handles[i];
1450 guint32 idx = GPOINTER_TO_UINT(handle);
1452 type = _WAPI_PRIVATE_HANDLES(idx).type;
1454 DEBUG ("%s: Checking handle %p", __func__, handle);
1456 if(((_wapi_handle_test_capabilities (handle, WAPI_HANDLE_CAP_OWN)==TRUE) &&
1457 (_wapi_handle_ops_isowned (handle) == TRUE)) ||
1458 (_WAPI_SHARED_HANDLE(type) &&
1459 WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) ||
1460 (!_WAPI_SHARED_HANDLE(type) &&
1461 _WAPI_PRIVATE_HANDLES(idx).signalled == TRUE)) {
1464 DEBUG ("%s: Handle %p signalled", __func__,
1472 DEBUG ("%s: %d event handles signalled", __func__, count);
1474 if ((waitall == TRUE && count == numhandles) ||
1475 (waitall == FALSE && count > 0)) {
1481 DEBUG ("%s: Returning %d", __func__, ret);
1488 void _wapi_handle_unlock_handles (guint32 numhandles, gpointer *handles)
1493 thr_ret = _wapi_handle_unlock_shared_handles ();
1494 g_assert (thr_ret == 0);
1496 for(i=0; i<numhandles; i++) {
1497 gpointer handle = handles[i];
1499 DEBUG ("%s: unlocking handle %p", __func__, handle);
1501 thr_ret = _wapi_handle_unlock_handle (handle);
1502 g_assert (thr_ret == 0);
1506 static int timedwait_signal_poll_cond (pthread_cond_t *cond, mono_mutex_t *mutex, struct timespec *timeout, gboolean alertable)
1508 struct timespec fake_timeout;
1513 ret=mono_cond_timedwait (cond, mutex, timeout);
1515 ret=mono_cond_wait (cond, mutex);
1517 _wapi_calc_timeout (&fake_timeout, 100);
1519 if (timeout != NULL && ((fake_timeout.tv_sec > timeout->tv_sec) ||
1520 (fake_timeout.tv_sec == timeout->tv_sec &&
1521 fake_timeout.tv_nsec > timeout->tv_nsec))) {
1522 /* Real timeout is less than 100ms time */
1523 ret=mono_cond_timedwait (cond, mutex, timeout);
1525 ret=mono_cond_timedwait (cond, mutex, &fake_timeout);
1527 /* Mask the fake timeout, this will cause
1528 * another poll if the cond was not really signaled
1530 if (ret==ETIMEDOUT) {
1539 int _wapi_handle_wait_signal (gboolean poll)
1541 return _wapi_handle_timedwait_signal_handle (_wapi_global_signal_handle, NULL, TRUE, poll);
1544 int _wapi_handle_timedwait_signal (struct timespec *timeout, gboolean poll)
1546 return _wapi_handle_timedwait_signal_handle (_wapi_global_signal_handle, timeout, TRUE, poll);
1549 int _wapi_handle_wait_signal_handle (gpointer handle, gboolean alertable)
1551 DEBUG ("%s: waiting for %p", __func__, handle);
1553 return _wapi_handle_timedwait_signal_handle (handle, NULL, alertable, FALSE);
1556 int _wapi_handle_timedwait_signal_handle (gpointer handle,
1557 struct timespec *timeout, gboolean alertable, gboolean poll)
1559 DEBUG ("%s: waiting for %p (type %s)", __func__, handle,
1560 _wapi_handle_typename[_wapi_handle_type (handle)]);
1562 if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
1563 if (WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) {
1566 if (timeout != NULL) {
1567 struct timespec fake_timeout;
1568 _wapi_calc_timeout (&fake_timeout, 100);
1570 if ((fake_timeout.tv_sec > timeout->tv_sec) ||
1571 (fake_timeout.tv_sec == timeout->tv_sec &&
1572 fake_timeout.tv_nsec > timeout->tv_nsec)) {
1573 /* FIXME: Real timeout is less than
1574 * 100ms time, but is it really worth
1575 * calculating to the exact ms?
1577 _wapi_handle_spin (100);
1579 if (WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) {
1586 _wapi_handle_spin (100);
1590 guint32 idx = GPOINTER_TO_UINT(handle);
1592 pthread_cond_t *cond;
1593 mono_mutex_t *mutex;
1595 if (alertable && !wapi_thread_set_wait_handle (handle))
1598 cond = &_WAPI_PRIVATE_HANDLES (idx).signal_cond;
1599 mutex = &_WAPI_PRIVATE_HANDLES (idx).signal_mutex;
1602 /* This is needed when waiting for process handles */
1603 res = timedwait_signal_poll_cond (cond, mutex, timeout, alertable);
1606 res = mono_cond_timedwait (cond, mutex, timeout);
1608 res = mono_cond_wait (cond, mutex);
1612 wapi_thread_clear_wait_handle (handle);
1619 _wapi_free_share_info (_WapiFileShare *share_info)
1621 if (!_wapi_shm_enabled ()) {
1622 file_share_hash_lock ();
1623 g_hash_table_remove (file_share_hash, share_info);
1624 file_share_hash_unlock ();
1625 /* The hashtable dtor frees share_info */
1627 memset (share_info, '\0', sizeof(struct _WapiFileShare));
1632 wapi_share_info_equal (gconstpointer ka, gconstpointer kb)
1634 const _WapiFileShare *s1 = ka;
1635 const _WapiFileShare *s2 = kb;
1637 return (s1->device == s2->device && s1->inode == s2->inode) ? 1 : 0;
1641 wapi_share_info_hash (gconstpointer data)
1643 const _WapiFileShare *s = data;
1648 gboolean _wapi_handle_get_or_set_share (guint64 device, guint64 inode,
1649 guint32 new_sharemode,
1651 guint32 *old_sharemode,
1652 guint32 *old_access,
1653 struct _WapiFileShare **share_info)
1655 struct _WapiFileShare *file_share;
1656 guint32 now = (guint32)(time(NULL) & 0xFFFFFFFF);
1657 int thr_ret, i, first_unused = -1;
1658 gboolean exists = FALSE;
1660 /* Prevents entries from expiring under us as we search
1662 thr_ret = _wapi_handle_lock_shared_handles ();
1663 g_assert (thr_ret == 0);
1665 /* Prevent new entries racing with us */
1666 thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1667 g_assert (thr_ret == 0);
1669 if (!_wapi_shm_enabled ()) {
1673 * Instead of allocating a 4MB array, we use a hash table to keep track of this
1674 * info. This is needed even if SHM is disabled, to track sharing inside
1675 * the current process.
1677 if (!file_share_hash) {
1678 file_share_hash = g_hash_table_new_full (wapi_share_info_hash, wapi_share_info_equal, NULL, g_free);
1679 mono_mutex_init_recursive (&file_share_hash_mutex);
1682 tmp.device = device;
1685 file_share_hash_lock ();
1687 file_share = g_hash_table_lookup (file_share_hash, &tmp);
1689 *old_sharemode = file_share->sharemode;
1690 *old_access = file_share->access;
1691 *share_info = file_share;
1693 InterlockedIncrement ((gint32 *)&file_share->handle_refs);
1696 file_share = g_new0 (_WapiFileShare, 1);
1698 file_share->device = device;
1699 file_share->inode = inode;
1700 file_share->opened_by_pid = _wapi_getpid ();
1701 file_share->sharemode = new_sharemode;
1702 file_share->access = new_access;
1703 file_share->handle_refs = 1;
1704 *share_info = file_share;
1706 g_hash_table_insert (file_share_hash, file_share, file_share);
1709 file_share_hash_unlock ();
1711 /* If a linear scan gets too slow we'll have to fit a hash
1712 * table onto the shared mem backing store
1715 for (i = 0; i <= _wapi_fileshare_layout->hwm; i++) {
1716 file_share = &_wapi_fileshare_layout->share_info[i];
1718 /* Make a note of an unused slot, in case we need to
1721 if (first_unused == -1 && file_share->handle_refs == 0) {
1726 if (file_share->handle_refs == 0) {
1730 if (file_share->device == device &&
1731 file_share->inode == inode) {
1732 *old_sharemode = file_share->sharemode;
1733 *old_access = file_share->access;
1734 *share_info = file_share;
1736 /* Increment the reference count while we
1737 * still have sole access to the shared area.
1738 * This makes the increment atomic wrt
1741 InterlockedIncrement ((gint32 *)&file_share->handle_refs);
1749 if (i == _WAPI_FILESHARE_SIZE && first_unused == -1) {
1752 if (first_unused == -1) {
1753 file_share = &_wapi_fileshare_layout->share_info[++i];
1754 _wapi_fileshare_layout->hwm = i;
1756 file_share = &_wapi_fileshare_layout->share_info[first_unused];
1759 file_share->device = device;
1760 file_share->inode = inode;
1761 file_share->opened_by_pid = _wapi_getpid ();
1762 file_share->sharemode = new_sharemode;
1763 file_share->access = new_access;
1764 file_share->handle_refs = 1;
1765 *share_info = file_share;
1769 if (*share_info != NULL) {
1770 InterlockedExchange ((gint32 *)&(*share_info)->timestamp, now);
1774 thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1776 _wapi_handle_unlock_shared_handles ();
1781 /* If we don't have the info in /proc, check if the process that
1782 * opened this share info is still there (it's not a perfect method,
1785 static void _wapi_handle_check_share_by_pid (struct _WapiFileShare *share_info)
1787 #if defined(__native_client__)
1788 g_assert_not_reached ();
1790 if (kill (share_info->opened_by_pid, 0) == -1 &&
1793 /* It's gone completely (or there's a new process
1794 * owned by someone else) so mark this share info as
1797 DEBUG ("%s: Didn't find it, destroying entry", __func__);
1799 _wapi_free_share_info (share_info);
1805 /* Scan /proc/<pids>/fd/ for open file descriptors to the file in
1806 * question. If there are none, reset the share info.
1808 * This implementation is Linux-specific; legacy systems will have to
1809 * implement their own ways of finding out if a particular file is
1810 * open by a process.
1812 void _wapi_handle_check_share (struct _WapiFileShare *share_info, int fd)
1814 gboolean found = FALSE, proc_fds = FALSE;
1817 /* Prevents entries from expiring under us if we remove this
1820 thr_ret = _wapi_handle_lock_shared_handles ();
1821 g_assert (thr_ret == 0);
1823 /* Prevent new entries racing with us */
1824 thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1825 g_assert (thr_ret == 0);
1827 /* If there is no /proc, there's nothing more we can do here */
1828 if (access ("/proc", F_OK) == -1) {
1829 _wapi_handle_check_share_by_pid (share_info);
1833 /* If there's another handle that thinks it owns this fd, then even
1834 * if the fd has been closed behind our back consider it still owned.
1835 * See bugs 75764 and 75891
1837 for (i = 0; i < _wapi_fd_reserve; i++) {
1838 if (_wapi_private_handles [SLOT_INDEX (i)]) {
1839 struct _WapiHandleUnshared *handle = &_WAPI_PRIVATE_HANDLES(i);
1842 handle->type == WAPI_HANDLE_FILE) {
1843 struct _WapiHandle_file *file_handle = &handle->u.file;
1845 if (file_handle->share_info == share_info) {
1846 DEBUG ("%s: handle 0x%x has this file open!",
1855 if (proc_fds == FALSE) {
1856 _wapi_handle_check_share_by_pid (share_info);
1857 } else if (found == FALSE) {
1858 /* Blank out this entry, as it is stale */
1859 DEBUG ("%s: Didn't find it, destroying entry", __func__);
1861 _wapi_free_share_info (share_info);
1865 thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1867 _wapi_handle_unlock_shared_handles ();
1871 // Other implementations (non-Linux)
1873 void _wapi_handle_check_share (struct _WapiFileShare *share_info, int fd)
1877 /* Prevents entries from expiring under us if we remove this
1879 thr_ret = _wapi_handle_lock_shared_handles ();
1880 g_assert (thr_ret == 0);
1882 /* Prevent new entries racing with us */
1883 thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1884 g_assert (thr_ret == 0);
1886 _wapi_handle_check_share_by_pid (share_info);
1888 thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1889 _wapi_handle_unlock_shared_handles ();
1893 void _wapi_handle_dump (void)
1895 struct _WapiHandleUnshared *handle_data;
1899 thr_ret = mono_mutex_lock (&scan_mutex);
1900 g_assert (thr_ret == 0);
1902 for(i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
1903 if (_wapi_private_handles [i]) {
1904 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
1905 handle_data = &_wapi_private_handles [i][k];
1907 if (handle_data->type == WAPI_HANDLE_UNUSED) {
1911 g_print ("%3x [%7s] %s %d ",
1912 i * _WAPI_HANDLE_INITIAL_COUNT + k,
1913 _wapi_handle_typename[handle_data->type],
1914 handle_data->signalled?"Sg":"Un",
1916 handle_details[handle_data->type](&handle_data->u);
1922 thr_ret = mono_mutex_unlock (&scan_mutex);
1923 g_assert (thr_ret == 0);
1926 static void _wapi_shared_details (gpointer handle_info)
1928 struct _WapiHandle_shared_ref *shared = (struct _WapiHandle_shared_ref *)handle_info;
1930 g_print ("offset: 0x%x", shared->offset);
1933 void _wapi_handle_update_refs (void)
1937 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
1939 thr_ret = _wapi_handle_lock_shared_handles ();
1940 g_assert (thr_ret == 0);
1942 /* Prevent file share entries racing with us */
1943 thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1944 g_assert(thr_ret == 0);
1946 thr_ret = mono_mutex_lock (&scan_mutex);
1948 for(i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
1949 if (_wapi_private_handles [i]) {
1950 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
1951 struct _WapiHandleUnshared *handle = &_wapi_private_handles [i][k];
1953 if (_WAPI_SHARED_HANDLE(handle->type)) {
1954 struct _WapiHandleShared *shared_data;
1956 DEBUG ("%s: (%d) handle 0x%x is SHARED (%s)", __func__, _wapi_getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k, _wapi_handle_typename[handle->type]);
1958 shared_data = &_wapi_shared_layout->handles[handle->u.shared.offset];
1960 DEBUG ("%s: (%d) Updating timestamp of handle 0x%x", __func__, _wapi_getpid (), handle->u.shared.offset);
1962 InterlockedExchange ((gint32 *)&shared_data->timestamp, now);
1963 } else if (handle->type == WAPI_HANDLE_FILE) {
1964 struct _WapiHandle_file *file_handle = &handle->u.file;
1966 DEBUG ("%s: (%d) handle 0x%x is FILE", __func__, _wapi_getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k);
1968 g_assert (file_handle->share_info != NULL);
1970 DEBUG ("%s: (%d) Inc refs on fileshare 0x%x", __func__, _wapi_getpid (), (file_handle->share_info - &_wapi_fileshare_layout->share_info[0]) / sizeof(struct _WapiFileShare));
1972 InterlockedExchange ((gint32 *)&file_handle->share_info->timestamp, now);
1978 thr_ret = mono_mutex_unlock (&scan_mutex);
1979 g_assert (thr_ret == 0);
1981 thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1983 _wapi_handle_unlock_shared_handles ();