2 * handles.c: Generic and internal operations on handles
5 * Dick Porter (dick@ximian.com)
7 * (C) 2002-2006 Novell, Inc.
16 #include <sys/types.h>
17 #include <sys/socket.h>
23 #include <mono/os/gc_wrapper.h>
25 #include <mono/io-layer/wapi.h>
26 #include <mono/io-layer/wapi-private.h>
27 #include <mono/io-layer/handles-private.h>
28 #include <mono/io-layer/mono-mutex.h>
29 #include <mono/io-layer/misc-private.h>
30 #include <mono/io-layer/shared.h>
31 #include <mono/io-layer/collection.h>
32 #include <mono/io-layer/process-private.h>
33 #include <mono/io-layer/critical-section-private.h>
38 static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer);
40 static WapiHandleCapability handle_caps[WAPI_HANDLE_COUNT]={0};
41 static struct _WapiHandleOps *handle_ops[WAPI_HANDLE_COUNT]={
53 &_wapi_namedmutex_ops,
55 &_wapi_namedevent_ops,
58 static void _wapi_shared_details (gpointer handle_info);
60 static void (*handle_details[WAPI_HANDLE_COUNT])(gpointer) = {
63 _wapi_console_details,
64 _wapi_shared_details, /* thread */
68 NULL, /* Nothing useful to see in a socket handle */
69 NULL, /* Nothing useful to see in a find handle */
70 _wapi_shared_details, /* process */
72 _wapi_shared_details, /* namedmutex */
73 _wapi_shared_details, /* namedsem */
74 _wapi_shared_details, /* namedevent */
77 const char *_wapi_handle_typename[] = {
96 * We can hold _WAPI_PRIVATE_MAX_SLOTS * _WAPI_HANDLE_INITIAL_COUNT handles.
97 * If 4M handles are not enough... Oh, well... we will crash.
99 #define SLOT_INDEX(x) (x / _WAPI_HANDLE_INITIAL_COUNT)
100 #define SLOT_OFFSET(x) (x % _WAPI_HANDLE_INITIAL_COUNT)
102 struct _WapiHandleUnshared *_wapi_private_handles [_WAPI_PRIVATE_MAX_SLOTS];
103 static guint32 _wapi_private_handle_count = 0;
104 static guint32 _wapi_private_handle_slot_count = 0;
106 struct _WapiHandleSharedLayout *_wapi_shared_layout = NULL;
107 struct _WapiFileShareLayout *_wapi_fileshare_layout = NULL;
109 guint32 _wapi_fd_reserve;
111 mono_mutex_t _wapi_global_signal_mutex;
112 pthread_cond_t _wapi_global_signal_cond;
115 gboolean _wapi_has_shut_down = FALSE;
117 /* Use this instead of getpid(), to cope with linuxthreads. It's a
118 * function rather than a variable lookup because we need to get at
119 * this before share_init() might have been called.
121 static pid_t _wapi_pid;
122 static mono_once_t pid_init_once = MONO_ONCE_INIT;
124 static void pid_init (void)
126 _wapi_pid = getpid ();
129 pid_t _wapi_getpid (void)
131 mono_once (&pid_init_once, pid_init);
137 static mono_mutex_t scan_mutex = MONO_MUTEX_INITIALIZER;
139 static void handle_cleanup (void)
143 _wapi_process_signal_self ();
145 /* Every shared handle we were using ought really to be closed
146 * by now, but to make sure just blow them all away. The
147 * exiting finalizer thread in particular races us to the
148 * program exit and doesn't always win, so it can be left
149 * cluttering up the shared file. Anything else left over is
152 for(i = SLOT_INDEX (0); _wapi_private_handles[i] != NULL; i++) {
153 for(j = SLOT_OFFSET (0); j < _WAPI_HANDLE_INITIAL_COUNT; j++) {
154 struct _WapiHandleUnshared *handle_data = &_wapi_private_handles[i][j];
155 int type = handle_data->type;
158 if (_WAPI_SHARED_HANDLE (type)) {
159 gpointer handle = GINT_TO_POINTER (i*_WAPI_HANDLE_INITIAL_COUNT+j);
161 if (type == WAPI_HANDLE_THREAD) {
162 /* Special-case thread handles
163 * because they need extra
164 * cleanup. This also avoids
165 * a race condition between
166 * the application exit and
167 * the finalizer thread - if
168 * it finishes up between now
169 * and actual app termination
170 * it will find all its handle
171 * details have been blown
172 * away, so this sets those
175 _wapi_thread_set_termination_details (handle, 0);
178 for(k = handle_data->ref; k > 0; k--) {
180 g_message ("%s: unreffing %s handle %p", __func__, _wapi_handle_typename[type], handle);
183 _wapi_handle_unref (handle);
189 _wapi_shm_semaphores_remove ();
191 mono_mutex_destroy(&_wapi_global_signal_mutex);
192 pthread_cond_destroy(&_wapi_global_signal_cond);
195 void _wapi_cleanup ()
197 g_assert (_wapi_has_shut_down == FALSE);
199 _wapi_has_shut_down = TRUE;
201 _wapi_critical_section_cleanup ();
202 _wapi_error_cleanup ();
203 _wapi_thread_cleanup ();
206 static mono_once_t shared_init_once = MONO_ONCE_INIT;
207 static void shared_init (void)
211 g_assert ((sizeof (handle_ops) / sizeof (handle_ops[0]))
212 == WAPI_HANDLE_COUNT);
214 _wapi_fd_reserve = getdtablesize();
216 /* This is needed by the code in _wapi_handle_new_internal */
217 _wapi_fd_reserve = (_wapi_fd_reserve + (_WAPI_HANDLE_INITIAL_COUNT - 1)) & ~(_WAPI_HANDLE_INITIAL_COUNT - 1);
221 * The entries in _wapi_private_handles reserved for fds are allocated lazily to
225 _wapi_private_handles [idx++] = g_new0 (struct _WapiHandleUnshared,
226 _WAPI_HANDLE_INITIAL_COUNT);
229 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
230 _wapi_private_handle_slot_count ++;
231 } while(_wapi_fd_reserve > _wapi_private_handle_count);
233 _wapi_shm_semaphores_init ();
235 _wapi_shared_layout = _wapi_shm_attach (WAPI_SHM_DATA);
236 g_assert (_wapi_shared_layout != NULL);
238 _wapi_fileshare_layout = _wapi_shm_attach (WAPI_SHM_FILESHARE);
239 g_assert (_wapi_fileshare_layout != NULL);
241 _wapi_collection_init ();
243 thr_ret = pthread_cond_init(&_wapi_global_signal_cond, NULL);
244 g_assert (thr_ret == 0);
246 thr_ret = mono_mutex_init(&_wapi_global_signal_mutex, NULL);
247 g_assert (thr_ret == 0);
249 /* Using g_atexit here instead of an explicit function call in
250 * a cleanup routine lets us cope when a third-party library
251 * calls exit (eg if an X client loses the connection to its
254 g_atexit (handle_cleanup);
257 static void _wapi_handle_init_shared (struct _WapiHandleShared *handle,
259 gpointer handle_specific)
261 g_assert (_wapi_has_shut_down == FALSE);
264 handle->timestamp = (guint32)(time (NULL) & 0xFFFFFFFF);
265 handle->signalled = FALSE;
266 handle->handle_refs = 1;
268 if (handle_specific != NULL) {
269 memcpy (&handle->u, handle_specific, sizeof (handle->u));
273 static void _wapi_handle_init (struct _WapiHandleUnshared *handle,
274 WapiHandleType type, gpointer handle_specific)
278 g_assert (_wapi_has_shut_down == FALSE);
281 handle->signalled = FALSE;
284 if (!_WAPI_SHARED_HANDLE(type)) {
285 thr_ret = pthread_cond_init (&handle->signal_cond, NULL);
286 g_assert (thr_ret == 0);
288 thr_ret = mono_mutex_init (&handle->signal_mutex, NULL);
289 g_assert (thr_ret == 0);
291 if (handle_specific != NULL) {
292 memcpy (&handle->u, handle_specific,
298 static guint32 _wapi_handle_new_shared (WapiHandleType type,
299 gpointer handle_specific)
302 static guint32 last = 1;
305 g_assert (_wapi_has_shut_down == FALSE);
307 /* Leave the first slot empty as a guard */
309 /* FIXME: expandable array */
310 for(offset = last; offset <_WAPI_HANDLE_INITIAL_COUNT; offset++) {
311 struct _WapiHandleShared *handle = &_wapi_shared_layout->handles[offset];
313 if(handle->type == WAPI_HANDLE_UNUSED) {
314 thr_ret = _wapi_handle_lock_shared_handles ();
315 g_assert (thr_ret == 0);
317 if (InterlockedCompareExchange ((gint32 *)&handle->type, type, WAPI_HANDLE_UNUSED) == WAPI_HANDLE_UNUSED) {
320 _wapi_handle_init_shared (handle, type,
323 _wapi_handle_unlock_shared_handles ();
327 /* Someone else beat us to it, just
332 _wapi_handle_unlock_shared_handles ();
337 /* Try again from the beginning */
342 /* Will need to expand the array. The caller will sort it out */
348 * _wapi_handle_new_internal:
349 * @type: Init handle to this type
351 * Search for a free handle and initialize it. Return the handle on
352 * success and 0 on failure. This is only called from
353 * _wapi_handle_new, and scan_mutex must be held.
355 static guint32 _wapi_handle_new_internal (WapiHandleType type,
356 gpointer handle_specific)
359 static guint32 last = 0;
360 gboolean retry = FALSE;
362 g_assert (_wapi_has_shut_down == FALSE);
364 /* A linear scan should be fast enough. Start from the last
365 * allocation, assuming that handles are allocated more often
366 * than they're freed. Leave the space reserved for file
370 if (last < _wapi_fd_reserve) {
371 last = _wapi_fd_reserve;
378 for(i = SLOT_INDEX (count); i < _wapi_private_handle_slot_count; i++) {
379 if (_wapi_private_handles [i]) {
380 for (k = SLOT_OFFSET (count); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
381 struct _WapiHandleUnshared *handle = &_wapi_private_handles [i][k];
383 if(handle->type == WAPI_HANDLE_UNUSED) {
386 _wapi_handle_init (handle, type, handle_specific);
394 if(retry && last > _wapi_fd_reserve) {
395 /* Try again from the beginning */
396 last = _wapi_fd_reserve;
400 /* Will need to expand the array. The caller will sort it out */
405 gpointer _wapi_handle_new (WapiHandleType type, gpointer handle_specific)
407 guint32 handle_idx = 0;
411 g_assert (_wapi_has_shut_down == FALSE);
413 mono_once (&shared_init_once, shared_init);
416 g_message ("%s: Creating new handle of type %s", __func__,
417 _wapi_handle_typename[type]);
420 g_assert(!_WAPI_FD_HANDLE(type));
422 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
423 (void *)&scan_mutex);
424 thr_ret = mono_mutex_lock (&scan_mutex);
425 g_assert (thr_ret == 0);
427 while ((handle_idx = _wapi_handle_new_internal (type, handle_specific)) == 0) {
428 /* Try and expand the array, and have another go */
429 int idx = SLOT_INDEX (_wapi_private_handle_count);
430 if (idx >= _WAPI_PRIVATE_MAX_SLOTS) {
434 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
435 _WAPI_HANDLE_INITIAL_COUNT);
437 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
438 _wapi_private_handle_slot_count ++;
441 thr_ret = mono_mutex_unlock (&scan_mutex);
442 g_assert (thr_ret == 0);
443 pthread_cleanup_pop (0);
445 if (handle_idx == 0) {
446 /* We ran out of slots */
447 handle = _WAPI_HANDLE_INVALID;
451 /* Make sure we left the space for fd mappings */
452 g_assert (handle_idx >= _wapi_fd_reserve);
454 handle = GUINT_TO_POINTER (handle_idx);
457 g_message ("%s: Allocated new handle %p", __func__, handle);
460 if (_WAPI_SHARED_HANDLE(type)) {
461 /* Add the shared section too */
464 ref = _wapi_handle_new_shared (type, handle_specific);
466 _wapi_handle_collect ();
467 ref = _wapi_handle_new_shared (type, handle_specific);
469 /* FIXME: grow the arrays */
470 handle = _WAPI_HANDLE_INVALID;
475 _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = ref;
477 g_message ("%s: New shared handle at offset 0x%x", __func__,
486 gpointer _wapi_handle_new_from_offset (WapiHandleType type, guint32 offset,
489 guint32 handle_idx = 0;
490 gpointer handle = INVALID_HANDLE_VALUE;
492 struct _WapiHandleShared *shared;
493 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
495 g_assert (_wapi_has_shut_down == FALSE);
497 mono_once (&shared_init_once, shared_init);
500 g_message ("%s: Creating new handle of type %s to offset %d", __func__,
501 _wapi_handle_typename[type], offset);
504 g_assert(!_WAPI_FD_HANDLE(type));
505 g_assert(_WAPI_SHARED_HANDLE(type));
506 g_assert(offset != 0);
508 shared = &_wapi_shared_layout->handles[offset];
510 /* Bump up the timestamp for this offset */
511 InterlockedExchange ((gint32 *)&shared->timestamp, now);
514 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
515 (void *)&scan_mutex);
516 thr_ret = mono_mutex_lock (&scan_mutex);
517 g_assert (thr_ret == 0);
519 for (i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
520 if (_wapi_private_handles [i]) {
521 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
522 struct _WapiHandleUnshared *handle_data = &_wapi_private_handles [i][k];
524 if (handle_data->type == type &&
525 handle_data->u.shared.offset == offset) {
526 handle = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
527 goto first_pass_done;
534 thr_ret = mono_mutex_unlock (&scan_mutex);
535 g_assert (thr_ret == 0);
536 pthread_cleanup_pop (0);
538 if (handle != INVALID_HANDLE_VALUE) {
539 _wapi_handle_ref (handle);
542 g_message ("%s: Returning old handle %p referencing 0x%x",
543 __func__, handle, offset);
548 /* Prevent entries expiring under us as we search */
549 thr_ret = _wapi_handle_lock_shared_handles ();
550 g_assert (thr_ret == 0);
552 if (shared->type == WAPI_HANDLE_UNUSED) {
553 /* Someone deleted this handle while we were working */
555 g_message ("%s: Handle at 0x%x unused", __func__, offset);
560 if (shared->type != type) {
562 g_message ("%s: Wrong type at %d 0x%x! Found %s wanted %s",
563 __func__, offset, offset,
564 _wapi_handle_typename[shared->type],
565 _wapi_handle_typename[type]);
570 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
571 (void *)&scan_mutex);
572 thr_ret = mono_mutex_lock (&scan_mutex);
573 g_assert (thr_ret == 0);
575 while ((handle_idx = _wapi_handle_new_internal (type, NULL)) == 0) {
576 /* Try and expand the array, and have another go */
577 int idx = SLOT_INDEX (_wapi_private_handle_count);
578 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
579 _WAPI_HANDLE_INITIAL_COUNT);
581 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
582 _wapi_private_handle_slot_count ++;
585 thr_ret = mono_mutex_unlock (&scan_mutex);
586 g_assert (thr_ret == 0);
587 pthread_cleanup_pop (0);
589 /* Make sure we left the space for fd mappings */
590 g_assert (handle_idx >= _wapi_fd_reserve);
592 handle = GUINT_TO_POINTER (handle_idx);
594 _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = offset;
595 InterlockedIncrement ((gint32 *)&shared->handle_refs);
598 g_message ("%s: Allocated new handle %p referencing 0x%x (shared refs %d)", __func__, handle, offset, shared->handle_refs);
602 _wapi_handle_unlock_shared_handles ();
608 init_handles_slot (int idx)
612 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
613 (void *)&scan_mutex);
614 thr_ret = mono_mutex_lock (&scan_mutex);
615 g_assert (thr_ret == 0);
617 if (_wapi_private_handles [idx] == NULL) {
618 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
619 _WAPI_HANDLE_INITIAL_COUNT);
620 g_assert (_wapi_private_handles [idx]);
623 thr_ret = mono_mutex_unlock (&scan_mutex);
624 g_assert (thr_ret == 0);
625 pthread_cleanup_pop (0);
628 gpointer _wapi_handle_new_fd (WapiHandleType type, int fd,
629 gpointer handle_specific)
631 struct _WapiHandleUnshared *handle;
634 g_assert (_wapi_has_shut_down == FALSE);
636 mono_once (&shared_init_once, shared_init);
639 g_message ("%s: Creating new handle of type %s", __func__,
640 _wapi_handle_typename[type]);
643 g_assert(_WAPI_FD_HANDLE(type));
644 g_assert(!_WAPI_SHARED_HANDLE(type));
646 if (fd >= _wapi_fd_reserve) {
648 g_message ("%s: fd %d is too big", __func__, fd);
651 return(GUINT_TO_POINTER (_WAPI_HANDLE_INVALID));
654 /* Initialize the array entries on demand */
655 if (_wapi_private_handles [SLOT_INDEX (fd)] == NULL)
656 init_handles_slot (SLOT_INDEX (fd));
658 handle = &_WAPI_PRIVATE_HANDLES(fd);
660 if (handle->type != WAPI_HANDLE_UNUSED) {
662 g_message ("%s: fd %d is already in use!", __func__, fd);
664 /* FIXME: clean up this handle? We can't do anything
665 * with the fd, cos thats the new one
670 g_message ("%s: Assigning new fd handle %d", __func__, fd);
673 /* Prevent file share entries racing with us, when the file
674 * handle is only half initialised
676 thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
677 g_assert(thr_ret == 0);
679 _wapi_handle_init (handle, type, handle_specific);
681 thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
683 return(GUINT_TO_POINTER(fd));
686 gboolean _wapi_lookup_handle (gpointer handle, WapiHandleType type,
687 gpointer *handle_specific)
689 struct _WapiHandleUnshared *handle_data;
690 guint32 handle_idx = GPOINTER_TO_UINT(handle);
692 if (!_WAPI_PRIVATE_VALID_SLOT (handle_idx)) {
696 /* Initialize the array entries on demand */
697 if (_wapi_private_handles [SLOT_INDEX (handle_idx)] == NULL)
698 init_handles_slot (SLOT_INDEX (handle_idx));
700 handle_data = &_WAPI_PRIVATE_HANDLES(handle_idx);
702 if (handle_data->type != type) {
706 if (handle_specific == NULL) {
710 if (_WAPI_SHARED_HANDLE(type)) {
711 struct _WapiHandle_shared_ref *ref;
712 struct _WapiHandleShared *shared_handle_data;
714 ref = &handle_data->u.shared;
715 shared_handle_data = &_wapi_shared_layout->handles[ref->offset];
717 if (shared_handle_data->type != type) {
718 /* The handle must have been deleted on us
723 *handle_specific = &shared_handle_data->u;
725 *handle_specific = &handle_data->u;
732 _wapi_handle_foreach (WapiHandleType type,
733 gboolean (*on_each)(gpointer test, gpointer user),
736 struct _WapiHandleUnshared *handle_data = NULL;
741 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
742 (void *)&scan_mutex);
743 thr_ret = mono_mutex_lock (&scan_mutex);
744 g_assert (thr_ret == 0);
746 for (i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
747 if (_wapi_private_handles [i]) {
748 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
749 handle_data = &_wapi_private_handles [i][k];
751 if (handle_data->type == type) {
752 ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
753 if (on_each (ret, user_data) == TRUE)
760 thr_ret = mono_mutex_unlock (&scan_mutex);
761 g_assert (thr_ret == 0);
762 pthread_cleanup_pop (0);
765 /* This might list some shared handles twice if they are already
766 * opened by this process, and the check function returns FALSE the
767 * first time. Shared handles that are created during the search are
768 * unreffed if the check function returns FALSE, so callers must not
769 * rely on the handle persisting (unless the check function returns
772 gpointer _wapi_search_handle (WapiHandleType type,
773 gboolean (*check)(gpointer test, gpointer user),
775 gpointer *handle_specific,
776 gboolean search_shared)
778 struct _WapiHandleUnshared *handle_data = NULL;
779 struct _WapiHandleShared *shared = NULL;
782 gboolean found = FALSE;
785 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
786 (void *)&scan_mutex);
787 thr_ret = mono_mutex_lock (&scan_mutex);
788 g_assert (thr_ret == 0);
790 for (i = SLOT_INDEX (0); !found && i < _wapi_private_handle_slot_count; i++) {
791 if (_wapi_private_handles [i]) {
792 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
793 handle_data = &_wapi_private_handles [i][k];
795 if (handle_data->type == type) {
796 ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
797 if (check (ret, user_data) == TRUE) {
798 _wapi_handle_ref (ret);
801 if (_WAPI_SHARED_HANDLE (type)) {
802 shared = &_wapi_shared_layout->handles[i];
812 thr_ret = mono_mutex_unlock (&scan_mutex);
813 g_assert (thr_ret == 0);
814 pthread_cleanup_pop (0);
816 if (!found && search_shared && _WAPI_SHARED_HANDLE (type)) {
817 /* Not found yet, so search the shared memory too */
819 g_message ("%s: Looking at other shared handles...", __func__);
822 for (i = 0; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
823 shared = &_wapi_shared_layout->handles[i];
825 if (shared->type == type) {
826 /* Tell new_from_offset to not
827 * timestamp this handle, because
828 * otherwise it will ping every handle
829 * in the list and they will never
832 ret = _wapi_handle_new_from_offset (type, i,
834 if (ret == INVALID_HANDLE_VALUE) {
835 /* This handle was deleted
836 * while we were looking at it
842 g_message ("%s: Opened tmp handle %p (type %s) from offset %d", __func__, ret, _wapi_handle_typename[type], i);
845 /* It's possible that the shared part
846 * of this handle has now been blown
847 * away (after new_from_offset
848 * successfully opened it,) if its
849 * timestamp is too old. The check
850 * function needs to be aware of this,
851 * and cope if the handle has
854 if (check (ret, user_data) == TRUE) {
855 /* Timestamp this handle, but make
856 * sure it still exists first
858 thr_ret = _wapi_handle_lock_shared_handles ();
859 g_assert (thr_ret == 0);
861 if (shared->type == type) {
862 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
863 InterlockedExchange ((gint32 *)&shared->timestamp, now);
866 handle_data = &_WAPI_PRIVATE_HANDLES(GPOINTER_TO_UINT(ret));
868 _wapi_handle_unlock_shared_handles ();
871 /* It's been deleted,
875 _wapi_handle_unlock_shared_handles ();
879 /* This isn't the handle we're looking
880 * for, so drop the reference we took
881 * in _wapi_handle_new_from_offset ()
883 _wapi_handle_unref (ret);
893 if(handle_specific != NULL) {
894 if (_WAPI_SHARED_HANDLE(type)) {
895 g_assert(shared->type == type);
897 *handle_specific = &shared->u;
899 *handle_specific = &handle_data->u;
907 /* Returns the offset of the metadata array, or -1 on error, or 0 for
908 * not found (0 is not a valid offset)
910 gint32 _wapi_search_handle_namespace (WapiHandleType type,
913 struct _WapiHandleShared *shared_handle_data;
918 g_assert(_WAPI_SHARED_HANDLE(type));
921 g_message ("%s: Lookup for handle named [%s] type %s", __func__,
922 utf8_name, _wapi_handle_typename[type]);
925 /* Do a handle collection before starting to look, so that any
926 * stale cruft gets removed
928 _wapi_handle_collect ();
930 thr_ret = _wapi_handle_lock_shared_handles ();
931 g_assert (thr_ret == 0);
933 for(i = 1; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
934 WapiSharedNamespace *sharedns;
936 shared_handle_data = &_wapi_shared_layout->handles[i];
938 /* Check mutex, event, semaphore, timer, job and
939 * file-mapping object names. So far only mutex,
940 * semaphore and event are implemented.
942 if (!_WAPI_SHARED_NAMESPACE (shared_handle_data->type)) {
947 g_message ("%s: found a shared namespace handle at 0x%x (type %s)", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
950 sharedns=(WapiSharedNamespace *)&shared_handle_data->u;
953 g_message ("%s: name is [%s]", __func__, sharedns->name);
956 if (strcmp (sharedns->name, utf8_name) == 0) {
957 if (shared_handle_data->type != type) {
958 /* Its the wrong type, so fail now */
960 g_message ("%s: handle 0x%x matches name but is wrong type: %s", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
966 g_message ("%s: handle 0x%x matches name and type", __func__, i);
975 _wapi_handle_unlock_shared_handles ();
980 void _wapi_handle_ref (gpointer handle)
982 guint32 idx = GPOINTER_TO_UINT(handle);
983 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
984 struct _WapiHandleUnshared *handle_data;
986 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
990 if (_wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) {
991 g_warning ("%s: Attempting to ref unused handle %p", __func__,
996 handle_data = &_WAPI_PRIVATE_HANDLES(idx);
998 InterlockedIncrement ((gint32 *)&handle_data->ref);
1000 /* It's possible for processes to exit before getting around
1001 * to updating timestamps in the collection thread, so if a
1002 * shared handle is reffed do the timestamp here as well just
1005 if (_WAPI_SHARED_HANDLE(handle_data->type)) {
1006 struct _WapiHandleShared *shared_data = &_wapi_shared_layout->handles[handle_data->u.shared.offset];
1008 InterlockedExchange ((gint32 *)&shared_data->timestamp, now);
1012 g_message ("%s: %s handle %p ref now %d", __func__,
1013 _wapi_handle_typename[_WAPI_PRIVATE_HANDLES (idx).type],
1015 _WAPI_PRIVATE_HANDLES(idx).ref);
1019 /* The handle must not be locked on entry to this function */
1020 void _wapi_handle_unref (gpointer handle)
1022 guint32 idx = GPOINTER_TO_UINT(handle);
1023 gboolean destroy = FALSE;
1026 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1030 if (_wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) {
1031 g_warning ("%s: Attempting to unref unused handle %p",
1036 /* Possible race condition here if another thread refs the
1037 * handle between here and setting the type to UNUSED. I
1038 * could lock a mutex, but I'm not sure that allowing a handle
1039 * reference to reach 0 isn't an application bug anyway.
1041 destroy = (InterlockedDecrement ((gint32 *)&_WAPI_PRIVATE_HANDLES(idx).ref) ==0);
1044 g_message ("%s: %s handle %p ref now %d (destroy %s)", __func__,
1045 _wapi_handle_typename[_WAPI_PRIVATE_HANDLES (idx).type],
1047 _WAPI_PRIVATE_HANDLES(idx).ref, destroy?"TRUE":"FALSE");
1051 /* Need to copy the handle info, reset the slot in the
1052 * array, and _only then_ call the close function to
1053 * avoid race conditions (eg file descriptors being
1054 * closed, and another file being opened getting the
1055 * same fd racing the memset())
1057 struct _WapiHandleUnshared handle_data;
1058 struct _WapiHandleShared shared_handle_data;
1059 WapiHandleType type = _WAPI_PRIVATE_HANDLES(idx).type;
1060 void (*close_func)(gpointer, gpointer) = _wapi_handle_ops_get_close_func (type);
1061 gboolean is_shared = _WAPI_SHARED_HANDLE(type);
1064 /* If this is a shared handle we need to take
1065 * the shared lock outside of the scan_mutex
1066 * lock to avoid deadlocks
1068 thr_ret = _wapi_handle_lock_shared_handles ();
1069 g_assert (thr_ret == 0);
1072 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup, (void *)&scan_mutex);
1073 thr_ret = mono_mutex_lock (&scan_mutex);
1076 g_message ("%s: Destroying handle %p", __func__, handle);
1079 memcpy (&handle_data, &_WAPI_PRIVATE_HANDLES(idx),
1080 sizeof (struct _WapiHandleUnshared));
1082 memset (&_WAPI_PRIVATE_HANDLES(idx).u, '\0',
1083 sizeof(_WAPI_PRIVATE_HANDLES(idx).u));
1085 _WAPI_PRIVATE_HANDLES(idx).type = WAPI_HANDLE_UNUSED;
1088 /* Destroy the mutex and cond var. We hope nobody
1089 * tried to grab them between the handle unlock and
1090 * now, but pthreads doesn't have a
1091 * "unlock_and_destroy" atomic function.
1093 thr_ret = mono_mutex_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_mutex);
1094 g_assert (thr_ret == 0);
1096 thr_ret = pthread_cond_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_cond);
1097 g_assert (thr_ret == 0);
1099 struct _WapiHandleShared *shared = &_wapi_shared_layout->handles[handle_data.u.shared.offset];
1101 memcpy (&shared_handle_data, shared,
1102 sizeof (struct _WapiHandleShared));
1104 /* It's possible that this handle is already
1105 * pointing at a deleted shared section
1108 g_message ("%s: %s handle %p shared refs before dec %d", __func__, _wapi_handle_typename[type], handle, shared->handle_refs);
1111 if (shared->handle_refs > 0) {
1112 shared->handle_refs--;
1113 if (shared->handle_refs == 0) {
1114 memset (shared, '\0', sizeof (struct _WapiHandleShared));
1119 thr_ret = mono_mutex_unlock (&scan_mutex);
1120 g_assert (thr_ret == 0);
1121 pthread_cleanup_pop (0);
1124 _wapi_handle_unlock_shared_handles ();
1127 if (close_func != NULL) {
1129 close_func (handle, &shared_handle_data.u);
1131 close_func (handle, &handle_data.u);
1137 void _wapi_handle_register_capabilities (WapiHandleType type,
1138 WapiHandleCapability caps)
1140 handle_caps[type] = caps;
1143 gboolean _wapi_handle_test_capabilities (gpointer handle,
1144 WapiHandleCapability caps)
1146 guint32 idx = GPOINTER_TO_UINT(handle);
1147 WapiHandleType type;
1149 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1153 type = _WAPI_PRIVATE_HANDLES(idx).type;
1156 g_message ("%s: testing 0x%x against 0x%x (%d)", __func__,
1157 handle_caps[type], caps, handle_caps[type] & caps);
1160 return((handle_caps[type] & caps) != 0);
1163 static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer)
1165 if (handle_ops[type] != NULL &&
1166 handle_ops[type]->close != NULL) {
1167 return (handle_ops[type]->close);
1173 void _wapi_handle_ops_close (gpointer handle, gpointer data)
1175 guint32 idx = GPOINTER_TO_UINT(handle);
1176 WapiHandleType type;
1178 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1182 type = _WAPI_PRIVATE_HANDLES(idx).type;
1184 if (handle_ops[type] != NULL &&
1185 handle_ops[type]->close != NULL) {
1186 handle_ops[type]->close (handle, data);
1190 void _wapi_handle_ops_signal (gpointer handle)
1192 guint32 idx = GPOINTER_TO_UINT(handle);
1193 WapiHandleType type;
1195 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1199 type = _WAPI_PRIVATE_HANDLES(idx).type;
1201 if (handle_ops[type] != NULL && handle_ops[type]->signal != NULL) {
1202 handle_ops[type]->signal (handle);
1206 gboolean _wapi_handle_ops_own (gpointer handle)
1208 guint32 idx = GPOINTER_TO_UINT(handle);
1209 WapiHandleType type;
1211 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1215 type = _WAPI_PRIVATE_HANDLES(idx).type;
1217 if (handle_ops[type] != NULL && handle_ops[type]->own_handle != NULL) {
1218 return(handle_ops[type]->own_handle (handle));
1224 gboolean _wapi_handle_ops_isowned (gpointer handle)
1226 guint32 idx = GPOINTER_TO_UINT(handle);
1227 WapiHandleType type;
1229 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1233 type = _WAPI_PRIVATE_HANDLES(idx).type;
1235 if (handle_ops[type] != NULL && handle_ops[type]->is_owned != NULL) {
1236 return(handle_ops[type]->is_owned (handle));
1242 guint32 _wapi_handle_ops_special_wait (gpointer handle, guint32 timeout)
1244 guint32 idx = GPOINTER_TO_UINT(handle);
1245 WapiHandleType type;
1247 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1248 return(WAIT_FAILED);
1251 type = _WAPI_PRIVATE_HANDLES(idx).type;
1253 if (handle_ops[type] != NULL &&
1254 handle_ops[type]->special_wait != NULL) {
1255 return(handle_ops[type]->special_wait (handle, timeout));
1257 return(WAIT_FAILED);
1261 void _wapi_handle_ops_prewait (gpointer handle)
1263 guint32 idx = GPOINTER_TO_UINT (handle);
1264 WapiHandleType type;
1266 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1270 type = _WAPI_PRIVATE_HANDLES (idx).type;
1272 if (handle_ops[type] != NULL &&
1273 handle_ops[type]->prewait != NULL) {
1274 handle_ops[type]->prewait (handle);
1281 * @handle: The handle to release
1283 * Closes and invalidates @handle, releasing any resources it
1284 * consumes. When the last handle to a temporary or non-persistent
1285 * object is closed, that object can be deleted. Closing the same
1286 * handle twice is an error.
1288 * Return value: %TRUE on success, %FALSE otherwise.
1290 gboolean CloseHandle(gpointer handle)
1292 if (handle == NULL) {
1293 /* Problem: because we map file descriptors to the
1294 * same-numbered handle we can't tell the difference
1295 * between a bogus handle and the handle to stdin.
1296 * Assume that it's the console handle if that handle
1299 if (_WAPI_PRIVATE_HANDLES (0).type != WAPI_HANDLE_CONSOLE) {
1300 SetLastError (ERROR_INVALID_PARAMETER);
1304 if (handle == _WAPI_HANDLE_INVALID){
1305 SetLastError (ERROR_INVALID_PARAMETER);
1309 _wapi_handle_unref (handle);
1314 /* Lots more to implement here, but this is all we need at the moment */
1315 gboolean DuplicateHandle (gpointer srcprocess, gpointer src,
1316 gpointer targetprocess, gpointer *target,
1317 guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, guint32 options G_GNUC_UNUSED)
1319 if (srcprocess != _WAPI_PROCESS_CURRENT ||
1320 targetprocess != _WAPI_PROCESS_CURRENT) {
1321 /* Duplicating other process's handles is not supported */
1322 SetLastError (ERROR_INVALID_HANDLE);
1326 if (src == _WAPI_PROCESS_CURRENT) {
1327 *target = _wapi_process_duplicate ();
1328 } else if (src == _WAPI_THREAD_CURRENT) {
1329 *target = _wapi_thread_duplicate ();
1331 _wapi_handle_ref (src);
1338 gboolean _wapi_handle_count_signalled_handles (guint32 numhandles,
1344 guint32 count, i, iter=0;
1347 WapiHandleType type;
1349 /* Lock all the handles, with backoff */
1351 thr_ret = _wapi_handle_lock_shared_handles ();
1352 g_assert (thr_ret == 0);
1354 for(i=0; i<numhandles; i++) {
1355 gpointer handle = handles[i];
1356 guint32 idx = GPOINTER_TO_UINT(handle);
1359 g_message ("%s: attempting to lock %p", __func__, handle);
1362 type = _WAPI_PRIVATE_HANDLES(idx).type;
1364 thr_ret = _wapi_handle_trylock_handle (handle);
1370 g_message ("%s: attempt failed for %p: %s", __func__,
1371 handle, strerror (thr_ret));
1374 thr_ret = _wapi_handle_unlock_shared_handles ();
1375 g_assert (thr_ret == 0);
1378 handle = handles[i];
1379 idx = GPOINTER_TO_UINT(handle);
1381 thr_ret = _wapi_handle_unlock_handle (handle);
1382 g_assert (thr_ret == 0);
1385 /* If iter ever reaches 100 the nanosleep will
1386 * return EINVAL immediately, but we have a
1387 * design flaw if that happens.
1391 g_warning ("%s: iteration overflow!",
1397 g_message ("%s: Backing off for %d ms", __func__,
1400 _wapi_handle_spin (10 * iter);
1407 g_message ("%s: Locked all handles", __func__);
1413 for(i=0; i<numhandles; i++) {
1414 gpointer handle = handles[i];
1415 guint32 idx = GPOINTER_TO_UINT(handle);
1417 type = _WAPI_PRIVATE_HANDLES(idx).type;
1420 g_message ("%s: Checking handle %p", __func__, handle);
1423 if(((_wapi_handle_test_capabilities (handle, WAPI_HANDLE_CAP_OWN)==TRUE) &&
1424 (_wapi_handle_ops_isowned (handle) == TRUE)) ||
1425 (_WAPI_SHARED_HANDLE(type) &&
1426 WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) ||
1427 (!_WAPI_SHARED_HANDLE(type) &&
1428 _WAPI_PRIVATE_HANDLES(idx).signalled == TRUE)) {
1432 g_message ("%s: Handle %p signalled", __func__,
1442 g_message ("%s: %d event handles signalled", __func__, count);
1445 if ((waitall == TRUE && count == numhandles) ||
1446 (waitall == FALSE && count > 0)) {
1453 g_message ("%s: Returning %d", __func__, ret);
1461 void _wapi_handle_unlock_handles (guint32 numhandles, gpointer *handles)
1466 thr_ret = _wapi_handle_unlock_shared_handles ();
1467 g_assert (thr_ret == 0);
1469 for(i=0; i<numhandles; i++) {
1470 gpointer handle = handles[i];
1473 g_message ("%s: unlocking handle %p", __func__, handle);
1476 thr_ret = _wapi_handle_unlock_handle (handle);
1477 g_assert (thr_ret == 0);
1481 static int timedwait_signal_poll_cond (pthread_cond_t *cond, mono_mutex_t *mutex, struct timespec *timeout, gboolean alertable)
1483 struct timespec fake_timeout;
1488 ret=mono_cond_timedwait (cond, mutex, timeout);
1490 ret=mono_cond_wait (cond, mutex);
1492 _wapi_calc_timeout (&fake_timeout, 100);
1494 if (timeout != NULL && ((fake_timeout.tv_sec > timeout->tv_sec) ||
1495 (fake_timeout.tv_sec == timeout->tv_sec &&
1496 fake_timeout.tv_nsec > timeout->tv_nsec))) {
1497 /* Real timeout is less than 100ms time */
1498 ret=mono_cond_timedwait (cond, mutex, timeout);
1500 ret=mono_cond_timedwait (cond, mutex, &fake_timeout);
1502 /* Mask the fake timeout, this will cause
1503 * another poll if the cond was not really signaled
1505 if (ret==ETIMEDOUT) {
1514 int _wapi_handle_wait_signal (void)
1516 return timedwait_signal_poll_cond (&_wapi_global_signal_cond, &_wapi_global_signal_mutex, NULL, TRUE);
1519 int _wapi_handle_timedwait_signal (struct timespec *timeout)
1521 return timedwait_signal_poll_cond (&_wapi_global_signal_cond, &_wapi_global_signal_mutex, timeout, TRUE);
1524 int _wapi_handle_wait_signal_handle (gpointer handle, gboolean alertable)
1527 g_message ("%s: waiting for %p", __func__, handle);
1530 return _wapi_handle_timedwait_signal_handle (handle, NULL, alertable);
1533 int _wapi_handle_timedwait_signal_handle (gpointer handle,
1534 struct timespec *timeout, gboolean alertable)
1537 g_message ("%s: waiting for %p (type %s)", __func__, handle,
1538 _wapi_handle_typename[_wapi_handle_type (handle)]);
1541 if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
1542 if (WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) {
1545 if (timeout != NULL) {
1546 struct timespec fake_timeout;
1547 _wapi_calc_timeout (&fake_timeout, 100);
1549 if ((fake_timeout.tv_sec > timeout->tv_sec) ||
1550 (fake_timeout.tv_sec == timeout->tv_sec &&
1551 fake_timeout.tv_nsec > timeout->tv_nsec)) {
1552 /* FIXME: Real timeout is less than
1553 * 100ms time, but is it really worth
1554 * calculating to the exact ms?
1556 _wapi_handle_spin (100);
1558 if (WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) {
1565 _wapi_handle_spin (100);
1569 guint32 idx = GPOINTER_TO_UINT(handle);
1570 return timedwait_signal_poll_cond (&_WAPI_PRIVATE_HANDLES(idx).signal_cond, &_WAPI_PRIVATE_HANDLES(idx).signal_mutex, timeout, alertable);
1574 gboolean _wapi_handle_get_or_set_share (dev_t device, ino_t inode,
1575 guint32 new_sharemode,
1577 guint32 *old_sharemode,
1578 guint32 *old_access,
1579 struct _WapiFileShare **share_info)
1581 struct _WapiFileShare *file_share;
1582 guint32 now = (guint32)(time(NULL) & 0xFFFFFFFF);
1583 int thr_ret, i, first_unused = -1;
1584 gboolean exists = FALSE;
1586 /* Prevents entries from expiring under us as we search
1588 thr_ret = _wapi_handle_lock_shared_handles ();
1589 g_assert (thr_ret == 0);
1591 /* Prevent new entries racing with us */
1592 thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1593 g_assert (thr_ret == 0);
1595 /* If a linear scan gets too slow we'll have to fit a hash
1596 * table onto the shared mem backing store
1599 for (i = 0; i <= _wapi_fileshare_layout->hwm; i++) {
1600 file_share = &_wapi_fileshare_layout->share_info[i];
1602 /* Make a note of an unused slot, in case we need to
1605 if (first_unused == -1 && file_share->handle_refs == 0) {
1610 if (file_share->handle_refs == 0) {
1614 if (file_share->device == device &&
1615 file_share->inode == inode) {
1616 *old_sharemode = file_share->sharemode;
1617 *old_access = file_share->access;
1618 *share_info = file_share;
1620 /* Increment the reference count while we
1621 * still have sole access to the shared area.
1622 * This makes the increment atomic wrt
1625 InterlockedIncrement ((gint32 *)&file_share->handle_refs);
1633 if (i == _WAPI_FILESHARE_SIZE && first_unused == -1) {
1636 if (first_unused == -1) {
1637 file_share = &_wapi_fileshare_layout->share_info[++i];
1638 _wapi_fileshare_layout->hwm = i;
1640 file_share = &_wapi_fileshare_layout->share_info[first_unused];
1643 file_share->device = device;
1644 file_share->inode = inode;
1645 file_share->opened_by_pid = _wapi_getpid ();
1646 file_share->sharemode = new_sharemode;
1647 file_share->access = new_access;
1648 file_share->handle_refs = 1;
1649 *share_info = file_share;
1653 if (*share_info != NULL) {
1654 InterlockedExchange ((gint32 *)&(*share_info)->timestamp, now);
1657 thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1659 _wapi_handle_unlock_shared_handles ();
1664 /* If we don't have the info in /proc, check if the process that
1665 * opened this share info is still there (it's not a perfect method,
1668 static void _wapi_handle_check_share_by_pid (struct _WapiFileShare *share_info)
1670 if (kill (share_info->opened_by_pid, 0) == -1 &&
1673 /* It's gone completely (or there's a new process
1674 * owned by someone else) so mark this share info as
1678 g_message ("%s: Didn't find it, destroying entry", __func__);
1681 memset (share_info, '\0', sizeof(struct _WapiFileShare));
1685 /* Scan /proc/<pids>/fd/ for open file descriptors to the file in
1686 * question. If there are none, reset the share info.
1688 * This implementation is Linux-specific; legacy systems will have to
1689 * implement their own ways of finding out if a particular file is
1690 * open by a process.
1692 void _wapi_handle_check_share (struct _WapiFileShare *share_info, int fd)
1694 gboolean found = FALSE, proc_fds = FALSE;
1695 pid_t self = _wapi_getpid ();
1699 /* Prevents entries from expiring under us if we remove this
1702 thr_ret = _wapi_handle_lock_shared_handles ();
1703 g_assert (thr_ret == 0);
1705 /* Prevent new entries racing with us */
1706 thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1707 g_assert (thr_ret == 0);
1709 /* If there is no /proc, there's nothing more we can do here */
1710 if (access ("/proc", F_OK) == -1) {
1711 _wapi_handle_check_share_by_pid (share_info);
1715 /* If there's another handle that thinks it owns this fd, then even
1716 * if the fd has been closed behind our back consider it still owned.
1717 * See bugs 75764 and 75891
1719 for (i = 0; i < _wapi_fd_reserve; i++) {
1720 if (_wapi_private_handles [SLOT_INDEX (i)]) {
1721 struct _WapiHandleUnshared *handle = &_WAPI_PRIVATE_HANDLES(i);
1724 handle->type == WAPI_HANDLE_FILE) {
1725 struct _WapiHandle_file *file_handle = &handle->u.file;
1727 if (file_handle->share_info == share_info) {
1729 g_message ("%s: handle 0x%x has this file open!",
1739 for (i = 0; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
1740 struct _WapiHandleShared *shared;
1741 struct _WapiHandle_process *process_handle;
1743 shared = &_wapi_shared_layout->handles[i];
1745 if (shared->type == WAPI_HANDLE_PROCESS) {
1747 struct dirent *fd_entry;
1748 char subdir[_POSIX_PATH_MAX];
1750 process_handle = &shared->u.process;
1751 pid = process_handle->id;
1753 /* Look in /proc/<pid>/fd/ but ignore
1754 * /proc/<our pid>/fd/<fd>, as we have the
1757 g_snprintf (subdir, _POSIX_PATH_MAX, "/proc/%d/fd",
1760 fd_dir = opendir (subdir);
1761 if (fd_dir == NULL) {
1766 g_message ("%s: Looking in %s", __func__, subdir);
1771 while ((fd_entry = readdir (fd_dir)) != NULL) {
1772 char path[_POSIX_PATH_MAX];
1773 struct stat link_stat;
1775 if (!strcmp (fd_entry->d_name, ".") ||
1776 !strcmp (fd_entry->d_name, "..") ||
1778 fd == atoi (fd_entry->d_name))) {
1782 g_snprintf (path, _POSIX_PATH_MAX,
1783 "/proc/%d/fd/%s", pid,
1786 stat (path, &link_stat);
1787 if (link_stat.st_dev == share_info->device &&
1788 link_stat.st_ino == share_info->inode) {
1790 g_message ("%s: Found it at %s",
1802 if (proc_fds == FALSE) {
1803 _wapi_handle_check_share_by_pid (share_info);
1804 } else if (found == FALSE) {
1805 /* Blank out this entry, as it is stale */
1807 g_message ("%s: Didn't find it, destroying entry", __func__);
1810 memset (share_info, '\0', sizeof(struct _WapiFileShare));
1814 thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1816 _wapi_handle_unlock_shared_handles ();
1819 void _wapi_handle_dump (void)
1821 struct _WapiHandleUnshared *handle_data;
1825 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
1826 (void *)&scan_mutex);
1827 thr_ret = mono_mutex_lock (&scan_mutex);
1828 g_assert (thr_ret == 0);
1830 for(i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
1831 if (_wapi_private_handles [i]) {
1832 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
1833 handle_data = &_wapi_private_handles [i][k];
1835 if (handle_data->type == WAPI_HANDLE_UNUSED) {
1839 g_print ("%3x [%7s] %s %d ",
1840 i * _WAPI_HANDLE_INITIAL_COUNT + k,
1841 _wapi_handle_typename[handle_data->type],
1842 handle_data->signalled?"Sg":"Un",
1844 handle_details[handle_data->type](&handle_data->u);
1850 thr_ret = mono_mutex_unlock (&scan_mutex);
1851 g_assert (thr_ret == 0);
1852 pthread_cleanup_pop (0);
1855 static void _wapi_shared_details (gpointer handle_info)
1857 struct _WapiHandle_shared_ref *shared = (struct _WapiHandle_shared_ref *)handle_info;
1859 g_print ("offset: 0x%x", shared->offset);
1862 void _wapi_handle_update_refs (void)
1866 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
1868 thr_ret = _wapi_handle_lock_shared_handles ();
1869 g_assert (thr_ret == 0);
1871 /* Prevent file share entries racing with us */
1872 thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1873 g_assert(thr_ret == 0);
1875 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
1876 (void *)&scan_mutex);
1877 thr_ret = mono_mutex_lock (&scan_mutex);
1879 for(i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
1880 if (_wapi_private_handles [i]) {
1881 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
1882 struct _WapiHandleUnshared *handle = &_wapi_private_handles [i][k];
1884 if (_WAPI_SHARED_HANDLE(handle->type)) {
1885 struct _WapiHandleShared *shared_data;
1888 g_message ("%s: (%d) handle 0x%x is SHARED (%s)", __func__, _wapi_getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k, _wapi_handle_typename[handle->type]);
1891 shared_data = &_wapi_shared_layout->handles[handle->u.shared.offset];
1894 g_message ("%s: (%d) Updating timestamp of handle 0x%x", __func__, _wapi_getpid (), handle->u.shared.offset);
1897 InterlockedExchange ((gint32 *)&shared_data->timestamp, now);
1898 } else if (handle->type == WAPI_HANDLE_FILE) {
1899 struct _WapiHandle_file *file_handle = &handle->u.file;
1902 g_message ("%s: (%d) handle 0x%x is FILE", __func__, _wapi_getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k);
1905 g_assert (file_handle->share_info != NULL);
1908 g_message ("%s: (%d) Inc refs on fileshare 0x%x", __func__, _wapi_getpid (), (file_handle->share_info - &_wapi_fileshare_layout->share_info[0]) / sizeof(struct _WapiFileShare));
1911 InterlockedExchange ((gint32 *)&file_handle->share_info->timestamp, now);
1917 thr_ret = mono_mutex_unlock (&scan_mutex);
1918 g_assert (thr_ret == 0);
1919 pthread_cleanup_pop (0);
1921 thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1923 _wapi_handle_unlock_shared_handles ();