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/shared.h>
42 #include <mono/io-layer/process-private.h>
44 #include <mono/utils/mono-os-mutex.h>
45 #include <mono/utils/mono-proclib.h>
46 #include <mono/utils/mono-threads.h>
47 #include <mono/utils/mono-once.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] = { (WapiHandleCapability)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 disabled, this will point to a hash of _WapiFileShare structures, otherwise
130 * it will be NULL. We use this instead of _wapi_fileshare_layout to avoid allocating a
133 static GHashTable *file_share_hash;
134 static mono_mutex_t file_share_hash_mutex;
136 #define file_share_hash_lock() mono_os_mutex_lock (&file_share_hash_mutex)
137 #define file_share_hash_unlock() mono_os_mutex_unlock (&file_share_hash_mutex)
139 guint32 _wapi_fd_reserve;
142 * This is an internal handle which is used for handling waiting for multiple handles.
143 * Threads which wait for multiple handles wait on this one handle, and when a handle
144 * is signalled, this handle is signalled too.
146 static gpointer _wapi_global_signal_handle;
148 /* Point to the mutex/cond inside _wapi_global_signal_handle */
149 mono_mutex_t *_wapi_global_signal_mutex;
150 pthread_cond_t *_wapi_global_signal_cond;
153 gboolean _wapi_has_shut_down = FALSE;
155 /* Use this instead of getpid(), to cope with linuxthreads. It's a
156 * function rather than a variable lookup because we need to get at
157 * this before share_init() might have been called.
159 static pid_t _wapi_pid;
160 static mono_once_t pid_init_once = MONO_ONCE_INIT;
162 static void _wapi_handle_unref_full (gpointer handle, gboolean ignore_private_busy_handles);
164 static void pid_init (void)
166 _wapi_pid = getpid ();
169 pid_t _wapi_getpid (void)
171 mono_once (&pid_init_once, pid_init);
177 static mono_mutex_t scan_mutex;
179 static void handle_cleanup (void)
183 /* Every shared handle we were using ought really to be closed
184 * by now, but to make sure just blow them all away. The
185 * exiting finalizer thread in particular races us to the
186 * program exit and doesn't always win, so it can be left
187 * cluttering up the shared file. Anything else left over is
190 for(i = SLOT_INDEX (0); _wapi_private_handles[i] != NULL; i++) {
191 for(j = SLOT_OFFSET (0); j < _WAPI_HANDLE_INITIAL_COUNT; j++) {
192 struct _WapiHandleUnshared *handle_data = &_wapi_private_handles[i][j];
193 gpointer handle = GINT_TO_POINTER (i*_WAPI_HANDLE_INITIAL_COUNT+j);
195 for(k = handle_data->ref; k > 0; k--) {
196 DEBUG ("%s: unreffing %s handle %p", __func__, _wapi_handle_typename[type], handle);
198 _wapi_handle_unref_full (handle, TRUE);
203 _wapi_shm_semaphores_remove ();
205 g_free (_wapi_shared_layout);
207 if (file_share_hash) {
208 g_hash_table_destroy (file_share_hash);
209 mono_os_mutex_destroy (&file_share_hash_mutex);
212 for (i = 0; i < _WAPI_PRIVATE_MAX_SLOTS; ++i)
213 g_free (_wapi_private_handles [i]);
217 wapi_getdtablesize (void)
219 return eg_getdtablesize ();
225 * Initialize the io-layer.
230 g_assert ((sizeof (handle_ops) / sizeof (handle_ops[0]))
231 == WAPI_HANDLE_COUNT);
233 _wapi_fd_reserve = wapi_getdtablesize ();
235 /* This is needed by the code in _wapi_handle_new_internal */
236 _wapi_fd_reserve = (_wapi_fd_reserve + (_WAPI_HANDLE_INITIAL_COUNT - 1)) & ~(_WAPI_HANDLE_INITIAL_COUNT - 1);
240 * The entries in _wapi_private_handles reserved for fds are allocated lazily to
244 _wapi_private_handles [idx++] = g_new0 (struct _WapiHandleUnshared,
245 _WAPI_HANDLE_INITIAL_COUNT);
248 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
249 _wapi_private_handle_slot_count ++;
250 } while(_wapi_fd_reserve > _wapi_private_handle_count);
252 _wapi_shm_semaphores_init ();
254 _wapi_shared_layout = (_WapiHandleSharedLayout *)g_malloc0 (sizeof (_WapiHandleSharedLayout));
255 g_assert (_wapi_shared_layout != NULL);
258 mono_os_mutex_init (&scan_mutex);
260 _wapi_global_signal_handle = _wapi_handle_new (WAPI_HANDLE_EVENT, NULL);
262 _wapi_global_signal_cond = &_WAPI_PRIVATE_HANDLES (GPOINTER_TO_UINT (_wapi_global_signal_handle)).signal_cond;
263 _wapi_global_signal_mutex = &_WAPI_PRIVATE_HANDLES (GPOINTER_TO_UINT (_wapi_global_signal_handle)).signal_mutex;
265 wapi_processes_init ();
271 g_assert (_wapi_has_shut_down == FALSE);
273 _wapi_has_shut_down = TRUE;
275 _wapi_error_cleanup ();
276 _wapi_thread_cleanup ();
277 wapi_processes_cleanup ();
281 static void _wapi_handle_init_shared (struct _WapiHandleShared *handle,
283 gpointer handle_specific)
285 g_assert (_wapi_has_shut_down == FALSE);
288 handle->timestamp = (guint32)(time (NULL) & 0xFFFFFFFF);
289 handle->signalled = FALSE;
290 handle->handle_refs = 1;
292 if (handle_specific != NULL) {
293 memcpy (&handle->u, handle_specific, sizeof (handle->u));
297 static size_t _wapi_handle_struct_size (WapiHandleType type)
302 case WAPI_HANDLE_FILE: case WAPI_HANDLE_CONSOLE: case WAPI_HANDLE_PIPE:
303 type_size = sizeof (struct _WapiHandle_file);
305 case WAPI_HANDLE_THREAD:
306 type_size = sizeof (struct _WapiHandle_thread);
308 case WAPI_HANDLE_SEM:
309 type_size = sizeof (struct _WapiHandle_sem);
311 case WAPI_HANDLE_MUTEX:
312 type_size = sizeof (struct _WapiHandle_mutex);
314 case WAPI_HANDLE_EVENT:
315 type_size = sizeof (struct _WapiHandle_event);
317 case WAPI_HANDLE_SOCKET:
318 type_size = sizeof (struct _WapiHandle_socket);
320 case WAPI_HANDLE_FIND:
321 type_size = sizeof (struct _WapiHandle_find);
323 case WAPI_HANDLE_PROCESS:
324 type_size = sizeof (struct _WapiHandle_process);
326 case WAPI_HANDLE_NAMEDMUTEX:
327 type_size = sizeof (struct _WapiHandle_namedmutex);
329 case WAPI_HANDLE_NAMEDSEM:
330 type_size = sizeof (struct _WapiHandle_namedsem);
332 case WAPI_HANDLE_NAMEDEVENT:
333 type_size = sizeof (struct _WapiHandle_namedevent);
337 g_error ("Unknown WapiHandleType: %d\n", type);
343 static void _wapi_handle_init (struct _WapiHandleUnshared *handle,
344 WapiHandleType type, gpointer handle_specific)
349 g_assert (_wapi_has_shut_down == FALSE);
352 handle->signalled = FALSE;
355 if (!_WAPI_SHARED_HANDLE(type)) {
356 thr_ret = pthread_cond_init (&handle->signal_cond, NULL);
357 g_assert (thr_ret == 0);
359 thr_ret = mono_os_mutex_init (&handle->signal_mutex);
360 g_assert (thr_ret == 0);
362 if (handle_specific != NULL) {
363 type_size = _wapi_handle_struct_size (type);
364 memcpy (&handle->u, handle_specific,
370 static guint32 _wapi_handle_new_shared (WapiHandleType type,
371 gpointer handle_specific)
374 static guint32 last = 1;
377 g_assert (_wapi_has_shut_down == FALSE);
379 /* Leave the first slot empty as a guard */
381 /* FIXME: expandable array */
382 for(offset = last; offset <_WAPI_HANDLE_INITIAL_COUNT; offset++) {
383 struct _WapiHandleShared *handle = &_wapi_shared_layout->handles[offset];
385 if(handle->type == WAPI_HANDLE_UNUSED) {
386 thr_ret = _wapi_handle_lock_shared_handles ();
387 g_assert (thr_ret == 0);
389 if (InterlockedCompareExchange ((gint32 *)&handle->type, type, WAPI_HANDLE_UNUSED) == WAPI_HANDLE_UNUSED) {
392 _wapi_handle_init_shared (handle, type,
395 _wapi_handle_unlock_shared_handles ();
399 /* Someone else beat us to it, just
404 _wapi_handle_unlock_shared_handles ();
409 /* Try again from the beginning */
414 /* Will need to expand the array. The caller will sort it out */
420 * _wapi_handle_new_internal:
421 * @type: Init handle to this type
423 * Search for a free handle and initialize it. Return the handle on
424 * success and 0 on failure. This is only called from
425 * _wapi_handle_new, and scan_mutex must be held.
427 static guint32 _wapi_handle_new_internal (WapiHandleType type,
428 gpointer handle_specific)
431 static guint32 last = 0;
432 gboolean retry = FALSE;
434 g_assert (_wapi_has_shut_down == FALSE);
436 /* A linear scan should be fast enough. Start from the last
437 * allocation, assuming that handles are allocated more often
438 * than they're freed. Leave the space reserved for file
442 if (last < _wapi_fd_reserve) {
443 last = _wapi_fd_reserve;
450 for(i = SLOT_INDEX (count); i < _wapi_private_handle_slot_count; i++) {
451 if (_wapi_private_handles [i]) {
452 for (k = SLOT_OFFSET (count); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
453 struct _WapiHandleUnshared *handle = &_wapi_private_handles [i][k];
455 if(handle->type == WAPI_HANDLE_UNUSED) {
458 _wapi_handle_init (handle, type, handle_specific);
466 if(retry && last > _wapi_fd_reserve) {
467 /* Try again from the beginning */
468 last = _wapi_fd_reserve;
472 /* Will need to expand the array. The caller will sort it out */
478 _wapi_handle_new (WapiHandleType type, gpointer handle_specific)
480 guint32 handle_idx = 0;
484 g_assert (_wapi_has_shut_down == FALSE);
486 DEBUG ("%s: Creating new handle of type %s", __func__,
487 _wapi_handle_typename[type]);
489 g_assert(!_WAPI_FD_HANDLE(type));
491 thr_ret = mono_os_mutex_lock (&scan_mutex);
492 g_assert (thr_ret == 0);
494 while ((handle_idx = _wapi_handle_new_internal (type, handle_specific)) == 0) {
495 /* Try and expand the array, and have another go */
496 int idx = SLOT_INDEX (_wapi_private_handle_count);
497 if (idx >= _WAPI_PRIVATE_MAX_SLOTS) {
501 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
502 _WAPI_HANDLE_INITIAL_COUNT);
504 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
505 _wapi_private_handle_slot_count ++;
508 thr_ret = mono_os_mutex_unlock (&scan_mutex);
509 g_assert (thr_ret == 0);
511 if (handle_idx == 0) {
512 /* We ran out of slots */
513 handle = _WAPI_HANDLE_INVALID;
517 /* Make sure we left the space for fd mappings */
518 g_assert (handle_idx >= _wapi_fd_reserve);
520 handle = GUINT_TO_POINTER (handle_idx);
522 DEBUG ("%s: Allocated new handle %p", __func__, handle);
524 if (_WAPI_SHARED_HANDLE(type)) {
525 /* Add the shared section too */
528 ref = _wapi_handle_new_shared (type, handle_specific);
530 ref = _wapi_handle_new_shared (type, handle_specific);
532 /* FIXME: grow the arrays */
533 handle = _WAPI_HANDLE_INVALID;
538 _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = ref;
539 DEBUG ("%s: New shared handle at offset 0x%x", __func__,
547 gpointer _wapi_handle_new_from_offset (WapiHandleType type, guint32 offset,
550 guint32 handle_idx = 0;
551 gpointer handle = INVALID_HANDLE_VALUE;
553 struct _WapiHandleShared *shared;
555 g_assert (_wapi_has_shut_down == FALSE);
557 DEBUG ("%s: Creating new handle of type %s to offset %d", __func__,
558 _wapi_handle_typename[type], offset);
560 g_assert(!_WAPI_FD_HANDLE(type));
561 g_assert(_WAPI_SHARED_HANDLE(type));
562 g_assert(offset != 0);
564 shared = &_wapi_shared_layout->handles[offset];
566 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
567 /* Bump up the timestamp for this offset */
568 InterlockedExchange ((gint32 *)&shared->timestamp, now);
571 thr_ret = mono_os_mutex_lock (&scan_mutex);
572 g_assert (thr_ret == 0);
574 for (i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
575 if (_wapi_private_handles [i]) {
576 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
577 struct _WapiHandleUnshared *handle_data = &_wapi_private_handles [i][k];
579 if (handle_data->type == type &&
580 handle_data->u.shared.offset == offset) {
581 handle = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
582 goto first_pass_done;
589 thr_ret = mono_os_mutex_unlock (&scan_mutex);
590 g_assert (thr_ret == 0);
592 if (handle != INVALID_HANDLE_VALUE) {
593 _wapi_handle_ref (handle);
595 DEBUG ("%s: Returning old handle %p referencing 0x%x",
596 __func__, handle, offset);
600 /* Prevent entries expiring under us as we search */
601 thr_ret = _wapi_handle_lock_shared_handles ();
602 g_assert (thr_ret == 0);
604 if (shared->type == WAPI_HANDLE_UNUSED) {
605 /* Someone deleted this handle while we were working */
606 DEBUG ("%s: Handle at 0x%x unused", __func__, offset);
610 if (shared->type != type) {
611 DEBUG ("%s: Wrong type at %d 0x%x! Found %s wanted %s",
612 __func__, offset, offset,
613 _wapi_handle_typename[shared->type],
614 _wapi_handle_typename[type]);
618 thr_ret = mono_os_mutex_lock (&scan_mutex);
619 g_assert (thr_ret == 0);
621 while ((handle_idx = _wapi_handle_new_internal (type, NULL)) == 0) {
622 /* Try and expand the array, and have another go */
623 int idx = SLOT_INDEX (_wapi_private_handle_count);
624 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
625 _WAPI_HANDLE_INITIAL_COUNT);
627 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
628 _wapi_private_handle_slot_count ++;
631 thr_ret = mono_os_mutex_unlock (&scan_mutex);
632 g_assert (thr_ret == 0);
634 /* Make sure we left the space for fd mappings */
635 g_assert (handle_idx >= _wapi_fd_reserve);
637 handle = GUINT_TO_POINTER (handle_idx);
639 _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = offset;
640 InterlockedIncrement ((gint32 *)&shared->handle_refs);
642 DEBUG ("%s: Allocated new handle %p referencing 0x%x (shared refs %d)", __func__, handle, offset, shared->handle_refs);
645 _wapi_handle_unlock_shared_handles ();
651 init_handles_slot (int idx)
655 thr_ret = mono_os_mutex_lock (&scan_mutex);
656 g_assert (thr_ret == 0);
658 if (_wapi_private_handles [idx] == NULL) {
659 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
660 _WAPI_HANDLE_INITIAL_COUNT);
661 g_assert (_wapi_private_handles [idx]);
664 thr_ret = mono_os_mutex_unlock (&scan_mutex);
665 g_assert (thr_ret == 0);
668 gpointer _wapi_handle_new_fd (WapiHandleType type, int fd,
669 gpointer handle_specific)
671 struct _WapiHandleUnshared *handle;
674 g_assert (_wapi_has_shut_down == FALSE);
676 DEBUG ("%s: Creating new handle of type %s", __func__,
677 _wapi_handle_typename[type]);
679 g_assert(_WAPI_FD_HANDLE(type));
680 g_assert(!_WAPI_SHARED_HANDLE(type));
682 if (fd >= _wapi_fd_reserve) {
683 DEBUG ("%s: fd %d is too big", __func__, fd);
685 return(GUINT_TO_POINTER (_WAPI_HANDLE_INVALID));
688 /* Initialize the array entries on demand */
689 if (_wapi_private_handles [SLOT_INDEX (fd)] == NULL)
690 init_handles_slot (SLOT_INDEX (fd));
692 handle = &_WAPI_PRIVATE_HANDLES(fd);
694 if (handle->type != WAPI_HANDLE_UNUSED) {
695 DEBUG ("%s: fd %d is already in use!", __func__, fd);
696 /* FIXME: clean up this handle? We can't do anything
697 * with the fd, cos thats the new one
701 DEBUG ("%s: Assigning new fd handle %d", __func__, fd);
703 /* Prevent file share entries racing with us, when the file
704 * handle is only half initialised
706 thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
707 g_assert(thr_ret == 0);
709 _wapi_handle_init (handle, type, handle_specific);
711 thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
713 return(GUINT_TO_POINTER(fd));
716 gboolean _wapi_lookup_handle (gpointer handle, WapiHandleType type,
717 gpointer *handle_specific)
719 struct _WapiHandleUnshared *handle_data;
720 guint32 handle_idx = GPOINTER_TO_UINT(handle);
722 if (!_WAPI_PRIVATE_VALID_SLOT (handle_idx)) {
726 /* Initialize the array entries on demand */
727 if (_wapi_private_handles [SLOT_INDEX (handle_idx)] == NULL)
728 init_handles_slot (SLOT_INDEX (handle_idx));
730 handle_data = &_WAPI_PRIVATE_HANDLES(handle_idx);
732 if (handle_data->type != type) {
736 if (handle_specific == NULL) {
740 if (_WAPI_SHARED_HANDLE(type)) {
741 struct _WapiHandle_shared_ref *ref;
742 struct _WapiHandleShared *shared_handle_data;
744 ref = &handle_data->u.shared;
745 shared_handle_data = &_wapi_shared_layout->handles[ref->offset];
747 if (shared_handle_data->type != type) {
748 /* The handle must have been deleted on us
753 *handle_specific = &shared_handle_data->u;
755 *handle_specific = &handle_data->u;
762 _wapi_handle_foreach (WapiHandleType type,
763 gboolean (*on_each)(gpointer test, gpointer user),
766 struct _WapiHandleUnshared *handle_data = NULL;
771 thr_ret = mono_os_mutex_lock (&scan_mutex);
772 g_assert (thr_ret == 0);
774 for (i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
775 if (_wapi_private_handles [i]) {
776 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
777 handle_data = &_wapi_private_handles [i][k];
779 if (handle_data->type == type) {
780 ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
781 if (on_each (ret, user_data) == TRUE)
788 thr_ret = mono_os_mutex_unlock (&scan_mutex);
789 g_assert (thr_ret == 0);
792 /* This might list some shared handles twice if they are already
793 * opened by this process, and the check function returns FALSE the
794 * first time. Shared handles that are created during the search are
795 * unreffed if the check function returns FALSE, so callers must not
796 * rely on the handle persisting (unless the check function returns
798 * The caller owns the returned handle.
800 gpointer _wapi_search_handle (WapiHandleType type,
801 gboolean (*check)(gpointer test, gpointer user),
803 gpointer *handle_specific,
804 gboolean search_shared)
806 struct _WapiHandleUnshared *handle_data = NULL;
807 struct _WapiHandleShared *shared = NULL;
810 gboolean found = FALSE;
813 thr_ret = mono_os_mutex_lock (&scan_mutex);
814 g_assert (thr_ret == 0);
816 for (i = SLOT_INDEX (0); !found && i < _wapi_private_handle_slot_count; i++) {
817 if (_wapi_private_handles [i]) {
818 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
819 handle_data = &_wapi_private_handles [i][k];
821 if (handle_data->type == type) {
822 ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
823 if (check (ret, user_data) == TRUE) {
824 _wapi_handle_ref (ret);
827 if (_WAPI_SHARED_HANDLE (type)) {
828 shared = &_wapi_shared_layout->handles[i];
838 thr_ret = mono_os_mutex_unlock (&scan_mutex);
839 g_assert (thr_ret == 0);
841 if (!found && search_shared && _WAPI_SHARED_HANDLE (type)) {
842 /* Not found yet, so search the shared memory too */
843 DEBUG ("%s: Looking at other shared handles...", __func__);
845 for (i = 0; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
846 shared = &_wapi_shared_layout->handles[i];
848 if (shared->type == type) {
849 /* Tell new_from_offset to not
850 * timestamp this handle, because
851 * otherwise it will ping every handle
852 * in the list and they will never
855 ret = _wapi_handle_new_from_offset (type, i,
857 if (ret == INVALID_HANDLE_VALUE) {
858 /* This handle was deleted
859 * while we were looking at it
864 DEBUG ("%s: Opened tmp handle %p (type %s) from offset %d", __func__, ret, _wapi_handle_typename[type], i);
866 /* It's possible that the shared part
867 * of this handle has now been blown
868 * away (after new_from_offset
869 * successfully opened it,) if its
870 * timestamp is too old. The check
871 * function needs to be aware of this,
872 * and cope if the handle has
875 if (check (ret, user_data) == TRUE) {
876 /* Timestamp this handle, but make
877 * sure it still exists first
879 thr_ret = _wapi_handle_lock_shared_handles ();
880 g_assert (thr_ret == 0);
882 if (shared->type == type) {
883 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
884 InterlockedExchange ((gint32 *)&shared->timestamp, now);
887 handle_data = &_WAPI_PRIVATE_HANDLES(GPOINTER_TO_UINT(ret));
889 _wapi_handle_unlock_shared_handles ();
892 /* It's been deleted,
896 _wapi_handle_unlock_shared_handles ();
900 /* This isn't the handle we're looking
901 * for, so drop the reference we took
902 * in _wapi_handle_new_from_offset ()
904 _wapi_handle_unref (ret);
914 if(handle_specific != NULL) {
915 if (_WAPI_SHARED_HANDLE(type)) {
916 g_assert(shared->type == type);
918 *handle_specific = &shared->u;
920 *handle_specific = &handle_data->u;
928 /* Returns the offset of the metadata array, or -1 on error, or 0 for
929 * not found (0 is not a valid offset)
931 gint32 _wapi_search_handle_namespace (WapiHandleType type,
934 struct _WapiHandleShared *shared_handle_data;
939 g_assert(_WAPI_SHARED_HANDLE(type));
941 DEBUG ("%s: Lookup for handle named [%s] type %s", __func__,
942 utf8_name, _wapi_handle_typename[type]);
944 thr_ret = _wapi_handle_lock_shared_handles ();
945 g_assert (thr_ret == 0);
947 for(i = 1; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
948 WapiSharedNamespace *sharedns;
950 shared_handle_data = &_wapi_shared_layout->handles[i];
952 /* Check mutex, event, semaphore, timer, job and
953 * file-mapping object names. So far only mutex,
954 * semaphore and event are implemented.
956 if (!_WAPI_SHARED_NAMESPACE (shared_handle_data->type)) {
960 DEBUG ("%s: found a shared namespace handle at 0x%x (type %s)", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
962 sharedns=(WapiSharedNamespace *)&shared_handle_data->u;
964 DEBUG ("%s: name is [%s]", __func__, sharedns->name);
966 if (strcmp (sharedns->name, utf8_name) == 0) {
967 if (shared_handle_data->type != type) {
968 /* Its the wrong type, so fail now */
969 DEBUG ("%s: handle 0x%x matches name but is wrong type: %s", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
973 DEBUG ("%s: handle 0x%x matches name and type", __func__, i);
981 _wapi_handle_unlock_shared_handles ();
986 void _wapi_handle_ref (gpointer handle)
988 guint32 idx = GPOINTER_TO_UINT(handle);
989 struct _WapiHandleUnshared *handle_data;
991 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
995 if (_wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) {
996 g_warning ("%s: Attempting to ref unused handle %p", __func__,
1001 handle_data = &_WAPI_PRIVATE_HANDLES(idx);
1003 InterlockedIncrement ((gint32 *)&handle_data->ref);
1005 /* It's possible for processes to exit before getting around
1006 * to updating timestamps in the collection thread, so if a
1007 * shared handle is reffed do the timestamp here as well just
1010 if (_WAPI_SHARED_HANDLE(handle_data->type)) {
1011 struct _WapiHandleShared *shared_data = &_wapi_shared_layout->handles[handle_data->u.shared.offset];
1012 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
1013 InterlockedExchange ((gint32 *)&shared_data->timestamp, now);
1017 g_message ("%s: %s handle %p ref now %d", __func__,
1018 _wapi_handle_typename[_WAPI_PRIVATE_HANDLES (idx).type],
1020 _WAPI_PRIVATE_HANDLES(idx).ref);
1024 /* The handle must not be locked on entry to this function */
1025 static void _wapi_handle_unref_full (gpointer handle, gboolean ignore_private_busy_handles)
1027 guint32 idx = GPOINTER_TO_UINT(handle);
1028 gboolean destroy = FALSE, early_exit = FALSE;
1031 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1035 if (_wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) {
1036 g_warning ("%s: Attempting to unref unused handle %p",
1041 /* Possible race condition here if another thread refs the
1042 * handle between here and setting the type to UNUSED. I
1043 * could lock a mutex, but I'm not sure that allowing a handle
1044 * reference to reach 0 isn't an application bug anyway.
1046 destroy = (InterlockedDecrement ((gint32 *)&_WAPI_PRIVATE_HANDLES(idx).ref) ==0);
1049 g_message ("%s: %s handle %p ref now %d (destroy %s)", __func__,
1050 _wapi_handle_typename[_WAPI_PRIVATE_HANDLES (idx).type],
1052 _WAPI_PRIVATE_HANDLES(idx).ref, destroy?"TRUE":"FALSE");
1056 /* Need to copy the handle info, reset the slot in the
1057 * array, and _only then_ call the close function to
1058 * avoid race conditions (eg file descriptors being
1059 * closed, and another file being opened getting the
1060 * same fd racing the memset())
1062 struct _WapiHandleUnshared handle_data;
1063 struct _WapiHandleShared shared_handle_data;
1064 WapiHandleType type = _WAPI_PRIVATE_HANDLES(idx).type;
1065 void (*close_func)(gpointer, gpointer) = _wapi_handle_ops_get_close_func (type);
1066 gboolean is_shared = _WAPI_SHARED_HANDLE(type);
1069 /* If this is a shared handle we need to take
1070 * the shared lock outside of the scan_mutex
1071 * lock to avoid deadlocks
1073 thr_ret = _wapi_handle_lock_shared_handles ();
1074 g_assert (thr_ret == 0);
1077 thr_ret = mono_os_mutex_lock (&scan_mutex);
1079 DEBUG ("%s: Destroying handle %p", __func__, handle);
1081 memcpy (&handle_data, &_WAPI_PRIVATE_HANDLES(idx),
1082 sizeof (struct _WapiHandleUnshared));
1084 memset (&_WAPI_PRIVATE_HANDLES(idx).u, '\0',
1085 sizeof(_WAPI_PRIVATE_HANDLES(idx).u));
1087 _WAPI_PRIVATE_HANDLES(idx).type = WAPI_HANDLE_UNUSED;
1090 /* Destroy the mutex and cond var. We hope nobody
1091 * tried to grab them between the handle unlock and
1092 * now, but pthreads doesn't have a
1093 * "unlock_and_destroy" atomic function.
1095 thr_ret = mono_os_mutex_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_mutex);
1096 /*WARNING gross hack to make cleanup not crash when exiting without the whole runtime teardown.*/
1097 if (thr_ret == EBUSY && ignore_private_busy_handles) {
1101 g_error ("Error destroying handle %p mutex due to %d\n", handle, thr_ret);
1103 thr_ret = pthread_cond_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_cond);
1104 if (thr_ret == EBUSY && ignore_private_busy_handles)
1106 else if (thr_ret != 0)
1107 g_error ("Error destroying handle %p cond var due to %d\n", handle, thr_ret);
1110 struct _WapiHandleShared *shared = &_wapi_shared_layout->handles[handle_data.u.shared.offset];
1112 memcpy (&shared_handle_data, shared,
1113 sizeof (struct _WapiHandleShared));
1115 /* It's possible that this handle is already
1116 * pointing at a deleted shared section
1119 g_message ("%s: %s handle %p shared refs before dec %d", __func__, _wapi_handle_typename[type], handle, shared->handle_refs);
1122 if (shared->handle_refs > 0) {
1123 shared->handle_refs--;
1124 if (shared->handle_refs == 0) {
1125 memset (shared, '\0', sizeof (struct _WapiHandleShared));
1130 thr_ret = mono_os_mutex_unlock (&scan_mutex);
1131 g_assert (thr_ret == 0);
1136 _wapi_handle_unlock_shared_handles ();
1139 if (close_func != NULL) {
1141 close_func (handle, &shared_handle_data.u);
1143 close_func (handle, &handle_data.u);
1149 void _wapi_handle_unref (gpointer handle)
1151 _wapi_handle_unref_full (handle, FALSE);
1154 void _wapi_handle_register_capabilities (WapiHandleType type,
1155 WapiHandleCapability caps)
1157 handle_caps[type] = caps;
1160 gboolean _wapi_handle_test_capabilities (gpointer handle,
1161 WapiHandleCapability caps)
1163 guint32 idx = GPOINTER_TO_UINT(handle);
1164 WapiHandleType type;
1166 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1170 type = _WAPI_PRIVATE_HANDLES(idx).type;
1172 DEBUG ("%s: testing 0x%x against 0x%x (%d)", __func__,
1173 handle_caps[type], caps, handle_caps[type] & caps);
1175 return((handle_caps[type] & caps) != 0);
1178 static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer)
1180 if (handle_ops[type] != NULL &&
1181 handle_ops[type]->close != NULL) {
1182 return (handle_ops[type]->close);
1188 void _wapi_handle_ops_close (gpointer handle, gpointer data)
1190 guint32 idx = GPOINTER_TO_UINT(handle);
1191 WapiHandleType type;
1193 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1197 type = _WAPI_PRIVATE_HANDLES(idx).type;
1199 if (handle_ops[type] != NULL &&
1200 handle_ops[type]->close != NULL) {
1201 handle_ops[type]->close (handle, data);
1205 void _wapi_handle_ops_signal (gpointer handle)
1207 guint32 idx = GPOINTER_TO_UINT(handle);
1208 WapiHandleType type;
1210 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1214 type = _WAPI_PRIVATE_HANDLES(idx).type;
1216 if (handle_ops[type] != NULL && handle_ops[type]->signal != NULL) {
1217 handle_ops[type]->signal (handle);
1221 gboolean _wapi_handle_ops_own (gpointer handle)
1223 guint32 idx = GPOINTER_TO_UINT(handle);
1224 WapiHandleType type;
1226 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1230 type = _WAPI_PRIVATE_HANDLES(idx).type;
1232 if (handle_ops[type] != NULL && handle_ops[type]->own_handle != NULL) {
1233 return(handle_ops[type]->own_handle (handle));
1239 gboolean _wapi_handle_ops_isowned (gpointer handle)
1241 guint32 idx = GPOINTER_TO_UINT(handle);
1242 WapiHandleType type;
1244 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1248 type = _WAPI_PRIVATE_HANDLES(idx).type;
1250 if (handle_ops[type] != NULL && handle_ops[type]->is_owned != NULL) {
1251 return(handle_ops[type]->is_owned (handle));
1257 guint32 _wapi_handle_ops_special_wait (gpointer handle, guint32 timeout, gboolean alertable)
1259 guint32 idx = GPOINTER_TO_UINT(handle);
1260 WapiHandleType type;
1262 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1263 return(WAIT_FAILED);
1266 type = _WAPI_PRIVATE_HANDLES(idx).type;
1268 if (handle_ops[type] != NULL &&
1269 handle_ops[type]->special_wait != NULL) {
1270 return(handle_ops[type]->special_wait (handle, timeout, alertable));
1272 return(WAIT_FAILED);
1276 void _wapi_handle_ops_prewait (gpointer handle)
1278 guint32 idx = GPOINTER_TO_UINT (handle);
1279 WapiHandleType type;
1281 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1285 type = _WAPI_PRIVATE_HANDLES (idx).type;
1287 if (handle_ops[type] != NULL &&
1288 handle_ops[type]->prewait != NULL) {
1289 handle_ops[type]->prewait (handle);
1296 * @handle: The handle to release
1298 * Closes and invalidates @handle, releasing any resources it
1299 * consumes. When the last handle to a temporary or non-persistent
1300 * object is closed, that object can be deleted. Closing the same
1301 * handle twice is an error.
1303 * Return value: %TRUE on success, %FALSE otherwise.
1305 gboolean CloseHandle(gpointer handle)
1307 if (handle == NULL) {
1308 /* Problem: because we map file descriptors to the
1309 * same-numbered handle we can't tell the difference
1310 * between a bogus handle and the handle to stdin.
1311 * Assume that it's the console handle if that handle
1314 if (_WAPI_PRIVATE_HANDLES (0).type != WAPI_HANDLE_CONSOLE) {
1315 SetLastError (ERROR_INVALID_PARAMETER);
1319 if (handle == _WAPI_HANDLE_INVALID){
1320 SetLastError (ERROR_INVALID_PARAMETER);
1324 _wapi_handle_unref (handle);
1329 /* Lots more to implement here, but this is all we need at the moment */
1330 gboolean DuplicateHandle (gpointer srcprocess, gpointer src,
1331 gpointer targetprocess, gpointer *target,
1332 guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, guint32 options G_GNUC_UNUSED)
1334 if (srcprocess != _WAPI_PROCESS_CURRENT ||
1335 targetprocess != _WAPI_PROCESS_CURRENT) {
1336 /* Duplicating other process's handles is not supported */
1337 SetLastError (ERROR_INVALID_HANDLE);
1341 if (src == _WAPI_PROCESS_CURRENT) {
1342 *target = _wapi_process_duplicate ();
1343 } else if (src == _WAPI_THREAD_CURRENT) {
1344 g_assert_not_reached ();
1346 _wapi_handle_ref (src);
1353 gboolean _wapi_handle_count_signalled_handles (guint32 numhandles,
1359 guint32 count, i, iter=0;
1362 WapiHandleType type;
1364 /* Lock all the handles, with backoff */
1366 thr_ret = _wapi_handle_lock_shared_handles ();
1367 g_assert (thr_ret == 0);
1369 for(i=0; i<numhandles; i++) {
1370 gpointer handle = handles[i];
1371 guint32 idx = GPOINTER_TO_UINT(handle);
1373 DEBUG ("%s: attempting to lock %p", __func__, handle);
1375 type = _WAPI_PRIVATE_HANDLES(idx).type;
1377 thr_ret = _wapi_handle_trylock_handle (handle);
1382 DEBUG ("%s: attempt failed for %p: %s", __func__,
1383 handle, strerror (thr_ret));
1385 thr_ret = _wapi_handle_unlock_shared_handles ();
1386 g_assert (thr_ret == 0);
1389 handle = handles[i];
1390 idx = GPOINTER_TO_UINT(handle);
1392 thr_ret = _wapi_handle_unlock_handle (handle);
1393 g_assert (thr_ret == 0);
1396 /* If iter ever reaches 100 the nanosleep will
1397 * return EINVAL immediately, but we have a
1398 * design flaw if that happens.
1402 g_warning ("%s: iteration overflow!",
1407 DEBUG ("%s: Backing off for %d ms", __func__,
1409 _wapi_handle_spin (10 * iter);
1415 DEBUG ("%s: Locked all handles", __func__);
1420 for(i=0; i<numhandles; i++) {
1421 gpointer handle = handles[i];
1422 guint32 idx = GPOINTER_TO_UINT(handle);
1424 type = _WAPI_PRIVATE_HANDLES(idx).type;
1426 DEBUG ("%s: Checking handle %p", __func__, handle);
1428 if(((_wapi_handle_test_capabilities (handle, WAPI_HANDLE_CAP_OWN)==TRUE) &&
1429 (_wapi_handle_ops_isowned (handle) == TRUE)) ||
1430 (_WAPI_SHARED_HANDLE(type) &&
1431 WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) ||
1432 (!_WAPI_SHARED_HANDLE(type) &&
1433 _WAPI_PRIVATE_HANDLES(idx).signalled == TRUE)) {
1436 DEBUG ("%s: Handle %p signalled", __func__,
1444 DEBUG ("%s: %d event handles signalled", __func__, count);
1446 if ((waitall == TRUE && count == numhandles) ||
1447 (waitall == FALSE && count > 0)) {
1453 DEBUG ("%s: Returning %d", __func__, ret);
1460 void _wapi_handle_unlock_handles (guint32 numhandles, gpointer *handles)
1465 thr_ret = _wapi_handle_unlock_shared_handles ();
1466 g_assert (thr_ret == 0);
1468 for(i=0; i<numhandles; i++) {
1469 gpointer handle = handles[i];
1471 DEBUG ("%s: unlocking handle %p", __func__, handle);
1473 thr_ret = _wapi_handle_unlock_handle (handle);
1474 g_assert (thr_ret == 0);
1479 _wapi_handle_timedwait_signal (guint32 timeout, gboolean poll, gboolean *alerted)
1481 return _wapi_handle_timedwait_signal_handle (_wapi_global_signal_handle, timeout, TRUE, poll, alerted);
1485 signal_handle_and_unref (gpointer handle)
1487 pthread_cond_t *cond;
1488 mono_mutex_t *mutex;
1493 /* If we reach here, then interrupt token is set to the flag value, which
1494 * means that the target thread is either
1495 * - before the first CAS in timedwait, which means it won't enter the wait.
1496 * - it is after the first CAS, so it is already waiting, or it will enter
1497 * the wait, and it will be interrupted by the broadcast. */
1498 idx = GPOINTER_TO_UINT (handle);
1499 cond = &_WAPI_PRIVATE_HANDLES (idx).signal_cond;
1500 mutex = &_WAPI_PRIVATE_HANDLES (idx).signal_mutex;
1502 mono_os_mutex_lock (mutex);
1503 mono_os_cond_broadcast (cond);
1504 mono_os_mutex_unlock (mutex);
1506 _wapi_handle_unref (handle);
1510 _wapi_handle_timedwait_signal_handle (gpointer handle, guint32 timeout, gboolean alertable, gboolean poll, gboolean *alerted)
1512 DEBUG ("%s: waiting for %p (type %s)", __func__, handle,
1513 _wapi_handle_typename[_wapi_handle_type (handle)]);
1521 if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
1522 if (WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) {
1525 if (timeout != INFINITE) {
1526 if (timeout < 100) {
1527 /* FIXME: Real timeout is less than
1528 * 100ms time, but is it really worth
1529 * calculating to the exact ms?
1531 _wapi_handle_spin (100);
1533 if (WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) {
1540 _wapi_handle_spin (100);
1544 guint32 idx = GPOINTER_TO_UINT(handle);
1546 pthread_cond_t *cond;
1547 mono_mutex_t *mutex;
1550 mono_thread_info_install_interrupt (signal_handle_and_unref, handle, alerted);
1553 _wapi_handle_ref (handle);
1556 cond = &_WAPI_PRIVATE_HANDLES (idx).signal_cond;
1557 mutex = &_WAPI_PRIVATE_HANDLES (idx).signal_mutex;
1560 res = mono_os_cond_timedwait (cond, mutex, timeout);
1562 /* This is needed when waiting for process handles */
1565 * pthread_cond_(timed)wait() can return 0 even if the condition was not
1566 * signalled. This happens at least on Darwin. We surface this, i.e., we
1567 * get spurious wake-ups.
1569 * http://pubs.opengroup.org/onlinepubs/007908775/xsh/pthread_cond_wait.html
1571 res = mono_os_cond_timedwait (cond, mutex, timeout);
1573 if (timeout < 100) {
1574 /* Real timeout is less than 100ms time */
1575 res = mono_os_cond_timedwait (cond, mutex, timeout);
1577 res = mono_os_cond_timedwait (cond, mutex, 100);
1579 /* Mask the fake timeout, this will cause
1580 * another poll if the cond was not really signaled
1582 if (res == ETIMEDOUT)
1589 mono_thread_info_uninstall_interrupt (alerted);
1591 /* if it is alerted, then the handle is unref in the interrupt callback */
1592 _wapi_handle_unref (handle);
1601 _wapi_free_share_info (_WapiFileShare *share_info)
1603 file_share_hash_lock ();
1604 g_hash_table_remove (file_share_hash, share_info);
1605 file_share_hash_unlock ();
1606 /* The hashtable dtor frees share_info */
1610 wapi_share_info_equal (gconstpointer ka, gconstpointer kb)
1612 const _WapiFileShare *s1 = (const _WapiFileShare *)ka;
1613 const _WapiFileShare *s2 = (const _WapiFileShare *)kb;
1615 return (s1->device == s2->device && s1->inode == s2->inode) ? 1 : 0;
1619 wapi_share_info_hash (gconstpointer data)
1621 const _WapiFileShare *s = (const _WapiFileShare *)data;
1626 gboolean _wapi_handle_get_or_set_share (guint64 device, guint64 inode,
1627 guint32 new_sharemode,
1629 guint32 *old_sharemode,
1630 guint32 *old_access,
1631 struct _WapiFileShare **share_info)
1633 struct _WapiFileShare *file_share;
1635 gboolean exists = FALSE;
1637 /* Prevents entries from expiring under us as we search
1639 thr_ret = _wapi_handle_lock_shared_handles ();
1640 g_assert (thr_ret == 0);
1642 /* Prevent new entries racing with us */
1643 thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1644 g_assert (thr_ret == 0);
1649 * Instead of allocating a 4MB array, we use a hash table to keep track of this
1650 * info. This is needed even if SHM is disabled, to track sharing inside
1651 * the current process.
1653 if (!file_share_hash) {
1654 file_share_hash = g_hash_table_new_full (wapi_share_info_hash, wapi_share_info_equal, NULL, g_free);
1655 mono_os_mutex_init_recursive (&file_share_hash_mutex);
1658 tmp.device = device;
1661 file_share_hash_lock ();
1663 file_share = (_WapiFileShare *)g_hash_table_lookup (file_share_hash, &tmp);
1665 *old_sharemode = file_share->sharemode;
1666 *old_access = file_share->access;
1667 *share_info = file_share;
1669 InterlockedIncrement ((gint32 *)&file_share->handle_refs);
1672 file_share = g_new0 (_WapiFileShare, 1);
1674 file_share->device = device;
1675 file_share->inode = inode;
1676 file_share->opened_by_pid = _wapi_getpid ();
1677 file_share->sharemode = new_sharemode;
1678 file_share->access = new_access;
1679 file_share->handle_refs = 1;
1680 *share_info = file_share;
1682 g_hash_table_insert (file_share_hash, file_share, file_share);
1685 file_share_hash_unlock ();
1687 thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1689 _wapi_handle_unlock_shared_handles ();
1694 /* If we don't have the info in /proc, check if the process that
1695 * opened this share info is still there (it's not a perfect method,
1698 static void _wapi_handle_check_share_by_pid (struct _WapiFileShare *share_info)
1700 #if defined(__native_client__)
1701 g_assert_not_reached ();
1702 #elif defined(HAVE_KILL)
1703 if (kill (share_info->opened_by_pid, 0) == -1 &&
1706 /* It's gone completely (or there's a new process
1707 * owned by someone else) so mark this share info as
1710 DEBUG ("%s: Didn't find it, destroying entry", __func__);
1712 _wapi_free_share_info (share_info);
1718 /* Scan /proc/<pids>/fd/ for open file descriptors to the file in
1719 * question. If there are none, reset the share info.
1721 * This implementation is Linux-specific; legacy systems will have to
1722 * implement their own ways of finding out if a particular file is
1723 * open by a process.
1725 void _wapi_handle_check_share (struct _WapiFileShare *share_info, int fd)
1727 gboolean found = FALSE, proc_fds = FALSE;
1730 /* Prevents entries from expiring under us if we remove this
1733 thr_ret = _wapi_handle_lock_shared_handles ();
1734 g_assert (thr_ret == 0);
1736 /* Prevent new entries racing with us */
1737 thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1738 g_assert (thr_ret == 0);
1740 /* If there is no /proc, there's nothing more we can do here */
1741 if (access ("/proc", F_OK) == -1) {
1742 _wapi_handle_check_share_by_pid (share_info);
1746 /* If there's another handle that thinks it owns this fd, then even
1747 * if the fd has been closed behind our back consider it still owned.
1748 * See bugs 75764 and 75891
1750 for (i = 0; i < _wapi_fd_reserve; i++) {
1751 if (_wapi_private_handles [SLOT_INDEX (i)]) {
1752 struct _WapiHandleUnshared *handle = &_WAPI_PRIVATE_HANDLES(i);
1755 handle->type == WAPI_HANDLE_FILE) {
1756 struct _WapiHandle_file *file_handle = &handle->u.file;
1758 if (file_handle->share_info == share_info) {
1759 DEBUG ("%s: handle 0x%x has this file open!",
1768 if (proc_fds == FALSE) {
1769 _wapi_handle_check_share_by_pid (share_info);
1770 } else if (found == FALSE) {
1771 /* Blank out this entry, as it is stale */
1772 DEBUG ("%s: Didn't find it, destroying entry", __func__);
1774 _wapi_free_share_info (share_info);
1778 thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1780 _wapi_handle_unlock_shared_handles ();
1784 // Other implementations (non-Linux)
1786 void _wapi_handle_check_share (struct _WapiFileShare *share_info, int fd)
1790 /* Prevents entries from expiring under us if we remove this
1792 thr_ret = _wapi_handle_lock_shared_handles ();
1793 g_assert (thr_ret == 0);
1795 /* Prevent new entries racing with us */
1796 thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1797 g_assert (thr_ret == 0);
1799 _wapi_handle_check_share_by_pid (share_info);
1801 thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1802 _wapi_handle_unlock_shared_handles ();
1806 void _wapi_handle_dump (void)
1808 struct _WapiHandleUnshared *handle_data;
1812 thr_ret = mono_os_mutex_lock (&scan_mutex);
1813 g_assert (thr_ret == 0);
1815 for(i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
1816 if (_wapi_private_handles [i]) {
1817 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
1818 handle_data = &_wapi_private_handles [i][k];
1820 if (handle_data->type == WAPI_HANDLE_UNUSED) {
1824 g_print ("%3x [%7s] %s %d ",
1825 i * _WAPI_HANDLE_INITIAL_COUNT + k,
1826 _wapi_handle_typename[handle_data->type],
1827 handle_data->signalled?"Sg":"Un",
1829 if (handle_details[handle_data->type])
1830 handle_details[handle_data->type](&handle_data->u);
1836 thr_ret = mono_os_mutex_unlock (&scan_mutex);
1837 g_assert (thr_ret == 0);
1840 static void _wapi_shared_details (gpointer handle_info)
1842 struct _WapiHandle_shared_ref *shared = (struct _WapiHandle_shared_ref *)handle_info;
1844 g_print ("offset: 0x%x", shared->offset);