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>
37 static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer);
39 static WapiHandleCapability handle_caps[WAPI_HANDLE_COUNT]={0};
40 static struct _WapiHandleOps *handle_ops[WAPI_HANDLE_COUNT]={
52 &_wapi_namedmutex_ops,
54 &_wapi_namedevent_ops,
57 static void _wapi_shared_details (gpointer handle_info);
59 static void (*handle_details[WAPI_HANDLE_COUNT])(gpointer) = {
62 _wapi_console_details,
63 _wapi_shared_details, /* thread */
67 NULL, /* Nothing useful to see in a socket handle */
68 NULL, /* Nothing useful to see in a find handle */
69 _wapi_shared_details, /* process */
71 _wapi_shared_details, /* namedmutex */
72 _wapi_shared_details, /* namedsem */
73 _wapi_shared_details, /* namedevent */
76 const char *_wapi_handle_typename[] = {
95 * We can hold _WAPI_PRIVATE_MAX_SLOTS * _WAPI_HANDLE_INITIAL_COUNT handles.
96 * If 4M handles are not enough... Oh, well... we will crash.
98 #define SLOT_INDEX(x) (x / _WAPI_HANDLE_INITIAL_COUNT)
99 #define SLOT_OFFSET(x) (x % _WAPI_HANDLE_INITIAL_COUNT)
101 struct _WapiHandleUnshared *_wapi_private_handles [_WAPI_PRIVATE_MAX_SLOTS];
102 static guint32 _wapi_private_handle_count = 0;
104 struct _WapiHandleSharedLayout *_wapi_shared_layout = NULL;
105 struct _WapiFileShareLayout *_wapi_fileshare_layout = NULL;
107 guint32 _wapi_fd_reserve;
109 mono_mutex_t _wapi_global_signal_mutex;
110 pthread_cond_t _wapi_global_signal_cond;
114 /* Use this instead of getpid(), to cope with linuxthreads. It's a
115 * function rather than a variable lookup because we need to get at
116 * this before share_init() might have been called.
118 static pid_t _wapi_pid;
119 static mono_once_t pid_init_once = MONO_ONCE_INIT;
121 static void pid_init (void)
123 _wapi_pid = getpid ();
126 pid_t _wapi_getpid (void)
128 mono_once (&pid_init_once, pid_init);
134 static mono_mutex_t scan_mutex = MONO_MUTEX_INITIALIZER;
136 static void handle_cleanup (void)
140 _wapi_process_signal_self ();
142 /* Every shared handle we were using ought really to be closed
143 * by now, but to make sure just blow them all away. The
144 * exiting finalizer thread in particular races us to the
145 * program exit and doesn't always win, so it can be left
146 * cluttering up the shared file. Anything else left over is
149 for(i = SLOT_INDEX (0); _wapi_private_handles[i] != NULL; i++) {
150 for(j = SLOT_OFFSET (0); j < _WAPI_HANDLE_INITIAL_COUNT; j++) {
151 struct _WapiHandleUnshared *handle_data = &_wapi_private_handles[i][j];
152 int type = handle_data->type;
155 if (_WAPI_SHARED_HANDLE (type)) {
156 gpointer handle = GINT_TO_POINTER (i*_WAPI_HANDLE_INITIAL_COUNT+j);
158 if (type == WAPI_HANDLE_THREAD) {
159 /* Special-case thread handles
160 * because they need extra
161 * cleanup. This also avoids
162 * a race condition between
163 * the application exit and
164 * the finalizer thread - if
165 * it finishes up between now
166 * and actual app termination
167 * it will find all its handle
168 * details have been blown
169 * away, so this sets those
172 _wapi_thread_set_termination_details (handle, 0);
175 for(k = handle_data->ref; k > 0; k--) {
177 g_message ("%s: unreffing %s handle %p", __func__, _wapi_handle_typename[type], handle);
180 _wapi_handle_unref (handle);
186 _wapi_shm_semaphores_remove ();
189 static mono_once_t shared_init_once = MONO_ONCE_INIT;
190 static void shared_init (void)
195 g_assert ((sizeof (handle_ops) / sizeof (handle_ops[0]))
196 == WAPI_HANDLE_COUNT);
198 _wapi_fd_reserve = getdtablesize();
201 _wapi_private_handles [idx++] = g_new0 (struct _WapiHandleUnshared,
202 _WAPI_HANDLE_INITIAL_COUNT);
204 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
205 } while(_wapi_fd_reserve > _wapi_private_handle_count);
207 _wapi_shm_semaphores_init ();
209 _wapi_shared_layout = _wapi_shm_attach (WAPI_SHM_DATA);
210 g_assert (_wapi_shared_layout != NULL);
212 _wapi_fileshare_layout = _wapi_shm_attach (WAPI_SHM_FILESHARE);
213 g_assert (_wapi_fileshare_layout != NULL);
215 _wapi_collection_init ();
217 thr_ret = pthread_cond_init(&_wapi_global_signal_cond, NULL);
218 g_assert (thr_ret == 0);
220 thr_ret = mono_mutex_init(&_wapi_global_signal_mutex, NULL);
221 g_assert (thr_ret == 0);
223 /* Using g_atexit here instead of an explicit function call in
224 * a cleanup routine lets us cope when a third-party library
225 * calls exit (eg if an X client loses the connection to its
228 g_atexit (handle_cleanup);
231 static void _wapi_handle_init_shared (struct _WapiHandleShared *handle,
233 gpointer handle_specific)
236 handle->timestamp = (guint32)(time (NULL) & 0xFFFFFFFF);
237 handle->signalled = FALSE;
238 handle->handle_refs = 1;
240 if (handle_specific != NULL) {
241 memcpy (&handle->u, handle_specific, sizeof (handle->u));
245 static void _wapi_handle_init (struct _WapiHandleUnshared *handle,
246 WapiHandleType type, gpointer handle_specific)
251 handle->signalled = FALSE;
254 if (!_WAPI_SHARED_HANDLE(type)) {
255 thr_ret = pthread_cond_init (&handle->signal_cond, NULL);
256 g_assert (thr_ret == 0);
258 thr_ret = mono_mutex_init (&handle->signal_mutex, NULL);
259 g_assert (thr_ret == 0);
261 if (handle_specific != NULL) {
262 memcpy (&handle->u, handle_specific,
268 static guint32 _wapi_handle_new_shared (WapiHandleType type,
269 gpointer handle_specific)
272 static guint32 last = 1;
275 /* Leave the first slot empty as a guard */
277 /* FIXME: expandable array */
278 for(offset = last; offset <_WAPI_HANDLE_INITIAL_COUNT; offset++) {
279 struct _WapiHandleShared *handle = &_wapi_shared_layout->handles[offset];
281 if(handle->type == WAPI_HANDLE_UNUSED) {
282 thr_ret = _wapi_handle_lock_shared_handles ();
283 g_assert (thr_ret == 0);
285 if (InterlockedCompareExchange ((gint32 *)&handle->type, type, WAPI_HANDLE_UNUSED) == WAPI_HANDLE_UNUSED) {
288 _wapi_handle_init_shared (handle, type,
291 _wapi_handle_unlock_shared_handles ();
295 /* Someone else beat us to it, just
300 _wapi_handle_unlock_shared_handles ();
305 /* Try again from the beginning */
310 /* Will need to expand the array. The caller will sort it out */
316 * _wapi_handle_new_internal:
317 * @type: Init handle to this type
319 * Search for a free handle and initialize it. Return the handle on
320 * success and 0 on failure. This is only called from
321 * _wapi_handle_new, and scan_mutex must be held.
323 static guint32 _wapi_handle_new_internal (WapiHandleType type,
324 gpointer handle_specific)
327 static guint32 last = 0;
328 gboolean retry = FALSE;
330 /* A linear scan should be fast enough. Start from the last
331 * allocation, assuming that handles are allocated more often
332 * than they're freed. Leave the space reserved for file
336 if (last < _wapi_fd_reserve) {
337 last = _wapi_fd_reserve;
344 for(i = SLOT_INDEX (count); _wapi_private_handles [i] != NULL; i++) {
345 for (k = SLOT_OFFSET (count); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
346 struct _WapiHandleUnshared *handle = &_wapi_private_handles [i][k];
348 if(handle->type == WAPI_HANDLE_UNUSED) {
351 _wapi_handle_init (handle, type, handle_specific);
358 if(retry && last > _wapi_fd_reserve) {
359 /* Try again from the beginning */
360 last = _wapi_fd_reserve;
364 /* Will need to expand the array. The caller will sort it out */
369 gpointer _wapi_handle_new (WapiHandleType type, gpointer handle_specific)
371 guint32 handle_idx = 0;
375 mono_once (&shared_init_once, shared_init);
378 g_message ("%s: Creating new handle of type %s", __func__,
379 _wapi_handle_typename[type]);
382 g_assert(!_WAPI_FD_HANDLE(type));
384 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
385 (void *)&scan_mutex);
386 thr_ret = mono_mutex_lock (&scan_mutex);
387 g_assert (thr_ret == 0);
389 while ((handle_idx = _wapi_handle_new_internal (type, handle_specific)) == 0) {
390 /* Try and expand the array, and have another go */
391 int idx = SLOT_INDEX (_wapi_private_handle_count);
392 if (idx >= _WAPI_PRIVATE_MAX_SLOTS) {
396 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
397 _WAPI_HANDLE_INITIAL_COUNT);
399 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
402 thr_ret = mono_mutex_unlock (&scan_mutex);
403 g_assert (thr_ret == 0);
404 pthread_cleanup_pop (0);
406 if (handle_idx == 0) {
407 /* We ran out of slots */
408 handle = _WAPI_HANDLE_INVALID;
412 /* Make sure we left the space for fd mappings */
413 g_assert (handle_idx >= _wapi_fd_reserve);
415 handle = GUINT_TO_POINTER (handle_idx);
418 g_message ("%s: Allocated new handle %p", __func__, handle);
421 if (_WAPI_SHARED_HANDLE(type)) {
422 /* Add the shared section too */
425 ref = _wapi_handle_new_shared (type, handle_specific);
427 _wapi_handle_collect ();
428 ref = _wapi_handle_new_shared (type, handle_specific);
430 /* FIXME: grow the arrays */
431 handle = _WAPI_HANDLE_INVALID;
436 _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = ref;
438 g_message ("%s: New shared handle at offset 0x%x", __func__,
447 gpointer _wapi_handle_new_from_offset (WapiHandleType type, guint32 offset,
450 guint32 handle_idx = 0;
451 gpointer handle = INVALID_HANDLE_VALUE;
453 struct _WapiHandleShared *shared;
454 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
456 mono_once (&shared_init_once, shared_init);
459 g_message ("%s: Creating new handle of type %s to offset %d", __func__,
460 _wapi_handle_typename[type], offset);
463 g_assert(!_WAPI_FD_HANDLE(type));
464 g_assert(_WAPI_SHARED_HANDLE(type));
465 g_assert(offset != 0);
467 shared = &_wapi_shared_layout->handles[offset];
469 /* Bump up the timestamp for this offset */
470 InterlockedExchange ((gint32 *)&shared->timestamp, now);
473 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
474 (void *)&scan_mutex);
475 thr_ret = mono_mutex_lock (&scan_mutex);
476 g_assert (thr_ret == 0);
478 for (i = SLOT_INDEX (0); _wapi_private_handles [i] != NULL; i++) {
479 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
480 struct _WapiHandleUnshared *handle_data = &_wapi_private_handles [i][k];
482 if (handle_data->type == type &&
483 handle_data->u.shared.offset == offset) {
484 handle = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
485 goto first_pass_done;
491 thr_ret = mono_mutex_unlock (&scan_mutex);
492 g_assert (thr_ret == 0);
493 pthread_cleanup_pop (0);
495 if (handle != INVALID_HANDLE_VALUE) {
496 _wapi_handle_ref (handle);
499 g_message ("%s: Returning old handle %p referencing 0x%x",
500 __func__, handle, offset);
505 /* Prevent entries expiring under us as we search */
506 thr_ret = _wapi_handle_lock_shared_handles ();
507 g_assert (thr_ret == 0);
509 if (shared->type == WAPI_HANDLE_UNUSED) {
510 /* Someone deleted this handle while we were working */
512 g_message ("%s: Handle at 0x%x unused", __func__, offset);
517 if (shared->type != type) {
519 g_message ("%s: Wrong type at %d 0x%x! Found %s wanted %s",
520 __func__, offset, offset,
521 _wapi_handle_typename[shared->type],
522 _wapi_handle_typename[type]);
527 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
528 (void *)&scan_mutex);
529 thr_ret = mono_mutex_lock (&scan_mutex);
530 g_assert (thr_ret == 0);
532 while ((handle_idx = _wapi_handle_new_internal (type, NULL)) == 0) {
533 /* Try and expand the array, and have another go */
534 int idx = SLOT_INDEX (_wapi_private_handle_count);
535 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
536 _WAPI_HANDLE_INITIAL_COUNT);
538 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
541 thr_ret = mono_mutex_unlock (&scan_mutex);
542 g_assert (thr_ret == 0);
543 pthread_cleanup_pop (0);
545 /* Make sure we left the space for fd mappings */
546 g_assert (handle_idx >= _wapi_fd_reserve);
548 handle = GUINT_TO_POINTER (handle_idx);
550 _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = offset;
551 InterlockedIncrement ((gint32 *)&shared->handle_refs);
554 g_message ("%s: Allocated new handle %p referencing 0x%x (shared refs %d)", __func__, handle, offset, shared->handle_refs);
558 _wapi_handle_unlock_shared_handles ();
563 gpointer _wapi_handle_new_fd (WapiHandleType type, int fd,
564 gpointer handle_specific)
566 struct _WapiHandleUnshared *handle;
569 mono_once (&shared_init_once, shared_init);
572 g_message ("%s: Creating new handle of type %s", __func__,
573 _wapi_handle_typename[type]);
576 g_assert(_WAPI_FD_HANDLE(type));
577 g_assert(!_WAPI_SHARED_HANDLE(type));
579 if (fd >= _wapi_fd_reserve) {
581 g_message ("%s: fd %d is too big", __func__, fd);
584 return(GUINT_TO_POINTER (_WAPI_HANDLE_INVALID));
587 handle = &_WAPI_PRIVATE_HANDLES(fd);
589 if (handle->type != WAPI_HANDLE_UNUSED) {
591 g_message ("%s: fd %d is already in use!", __func__, fd);
593 /* FIXME: clean up this handle? We can't do anything
594 * with the fd, cos thats the new one
599 g_message ("%s: Assigning new fd handle %d", __func__, fd);
602 /* Prevent file share entries racing with us, when the file
603 * handle is only half initialised
605 thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
606 g_assert(thr_ret == 0);
608 _wapi_handle_init (handle, type, handle_specific);
610 thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
612 return(GUINT_TO_POINTER(fd));
615 gboolean _wapi_lookup_handle (gpointer handle, WapiHandleType type,
616 gpointer *handle_specific)
618 struct _WapiHandleUnshared *handle_data;
619 guint32 handle_idx = GPOINTER_TO_UINT(handle);
621 if (!_WAPI_PRIVATE_VALID_SLOT (handle_idx)) {
625 handle_data = &_WAPI_PRIVATE_HANDLES(handle_idx);
627 if (handle_data->type != type) {
631 if (handle_specific == NULL) {
635 if (_WAPI_SHARED_HANDLE(type)) {
636 struct _WapiHandle_shared_ref *ref;
637 struct _WapiHandleShared *shared_handle_data;
639 ref = &handle_data->u.shared;
640 shared_handle_data = &_wapi_shared_layout->handles[ref->offset];
642 if (shared_handle_data->type != type) {
643 /* The handle must have been deleted on us
648 *handle_specific = &shared_handle_data->u;
650 *handle_specific = &handle_data->u;
657 _wapi_handle_foreach (WapiHandleType type,
658 gboolean (*on_each)(gpointer test, gpointer user),
661 struct _WapiHandleUnshared *handle_data = NULL;
666 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
667 (void *)&scan_mutex);
668 thr_ret = mono_mutex_lock (&scan_mutex);
669 g_assert (thr_ret == 0);
671 for (i = SLOT_INDEX (0); _wapi_private_handles [i] != NULL; i++) {
672 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
673 handle_data = &_wapi_private_handles [i][k];
675 if (handle_data->type == type) {
676 ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
677 if (on_each (ret, user_data) == TRUE)
683 thr_ret = mono_mutex_unlock (&scan_mutex);
684 g_assert (thr_ret == 0);
685 pthread_cleanup_pop (0);
688 /* This might list some shared handles twice if they are already
689 * opened by this process, and the check function returns FALSE the
690 * first time. Shared handles that are created during the search are
691 * unreffed if the check function returns FALSE, so callers must not
692 * rely on the handle persisting (unless the check function returns
695 gpointer _wapi_search_handle (WapiHandleType type,
696 gboolean (*check)(gpointer test, gpointer user),
698 gpointer *handle_specific,
699 gboolean search_shared)
701 struct _WapiHandleUnshared *handle_data = NULL;
702 struct _WapiHandleShared *shared;
705 gboolean found = FALSE;
708 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
709 (void *)&scan_mutex);
710 thr_ret = mono_mutex_lock (&scan_mutex);
711 g_assert (thr_ret == 0);
713 for (i = SLOT_INDEX (0); !found && _wapi_private_handles [i] != NULL; i++) {
714 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
715 handle_data = &_wapi_private_handles [i][k];
717 if (handle_data->type == type) {
718 ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
719 if (check (ret, user_data) == TRUE) {
720 _wapi_handle_ref (ret);
723 if (_WAPI_SHARED_HANDLE (type)) {
724 shared = &_wapi_shared_layout->handles[i];
733 thr_ret = mono_mutex_unlock (&scan_mutex);
734 g_assert (thr_ret == 0);
735 pthread_cleanup_pop (0);
737 if (!found && search_shared && _WAPI_SHARED_HANDLE (type)) {
738 /* Not found yet, so search the shared memory too */
740 g_message ("%s: Looking at other shared handles...", __func__);
743 for (i = 0; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
744 shared = &_wapi_shared_layout->handles[i];
746 if (shared->type == type) {
747 /* Tell new_from_offset to not
748 * timestamp this handle, because
749 * otherwise it will ping every handle
750 * in the list and they will never
753 ret = _wapi_handle_new_from_offset (type, i,
755 if (ret == INVALID_HANDLE_VALUE) {
756 /* This handle was deleted
757 * while we were looking at it
763 g_message ("%s: Opened tmp handle %p (type %s) from offset %d", __func__, ret, _wapi_handle_typename[type], i);
766 /* It's possible that the shared part
767 * of this handle has now been blown
768 * away (after new_from_offset
769 * successfully opened it,) if its
770 * timestamp is too old. The check
771 * function needs to be aware of this,
772 * and cope if the handle has
775 if (check (ret, user_data) == TRUE) {
776 /* Timestamp this handle, but make
777 * sure it still exists first
779 thr_ret = _wapi_handle_lock_shared_handles ();
780 g_assert (thr_ret == 0);
782 if (shared->type == type) {
783 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
784 InterlockedExchange ((gint32 *)&shared->timestamp, now);
787 handle_data = &_WAPI_PRIVATE_HANDLES(GPOINTER_TO_UINT(ret));
789 _wapi_handle_unlock_shared_handles ();
792 /* It's been deleted,
796 _wapi_handle_unlock_shared_handles ();
800 /* This isn't the handle we're looking
801 * for, so drop the reference we took
802 * in _wapi_handle_new_from_offset ()
804 _wapi_handle_unref (ret);
814 if(handle_specific != NULL) {
815 if (_WAPI_SHARED_HANDLE(type)) {
816 g_assert(shared->type == type);
818 *handle_specific = &shared->u;
820 *handle_specific = &handle_data->u;
828 /* Returns the offset of the metadata array, or -1 on error, or 0 for
829 * not found (0 is not a valid offset)
831 gint32 _wapi_search_handle_namespace (WapiHandleType type,
834 struct _WapiHandleShared *shared_handle_data;
839 g_assert(_WAPI_SHARED_HANDLE(type));
842 g_message ("%s: Lookup for handle named [%s] type %s", __func__,
843 utf8_name, _wapi_handle_typename[type]);
846 /* Do a handle collection before starting to look, so that any
847 * stale cruft gets removed
849 _wapi_handle_collect ();
851 thr_ret = _wapi_handle_lock_shared_handles ();
852 g_assert (thr_ret == 0);
854 for(i = 1; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
855 WapiSharedNamespace *sharedns;
857 shared_handle_data = &_wapi_shared_layout->handles[i];
859 /* Check mutex, event, semaphore, timer, job and
860 * file-mapping object names. So far only mutex,
861 * semaphore and event are implemented.
863 if (!_WAPI_SHARED_NAMESPACE (shared_handle_data->type)) {
868 g_message ("%s: found a shared namespace handle at 0x%x (type %s)", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
871 sharedns=(WapiSharedNamespace *)&shared_handle_data->u;
874 g_message ("%s: name is [%s]", __func__, sharedns->name);
877 if (strcmp (sharedns->name, utf8_name) == 0) {
878 if (shared_handle_data->type != type) {
879 /* Its the wrong type, so fail now */
881 g_message ("%s: handle 0x%x matches name but is wrong type: %s", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
887 g_message ("%s: handle 0x%x matches name and type", __func__, i);
896 _wapi_handle_unlock_shared_handles ();
901 void _wapi_handle_ref (gpointer handle)
903 guint32 idx = GPOINTER_TO_UINT(handle);
904 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
905 struct _WapiHandleUnshared *handle_data;
907 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
911 if (_wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) {
912 g_warning ("%s: Attempting to ref unused handle %p", __func__,
917 handle_data = &_WAPI_PRIVATE_HANDLES(idx);
919 InterlockedIncrement ((gint32 *)&handle_data->ref);
921 /* It's possible for processes to exit before getting around
922 * to updating timestamps in the collection thread, so if a
923 * shared handle is reffed do the timestamp here as well just
926 if (_WAPI_SHARED_HANDLE(handle_data->type)) {
927 struct _WapiHandleShared *shared_data = &_wapi_shared_layout->handles[handle_data->u.shared.offset];
929 InterlockedExchange ((gint32 *)&shared_data->timestamp, now);
933 g_message ("%s: %s handle %p ref now %d", __func__,
934 _wapi_handle_typename[_WAPI_PRIVATE_HANDLES (idx).type],
936 _WAPI_PRIVATE_HANDLES(idx).ref);
940 /* The handle must not be locked on entry to this function */
941 void _wapi_handle_unref (gpointer handle)
943 guint32 idx = GPOINTER_TO_UINT(handle);
944 gboolean destroy = FALSE;
947 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
951 if (_wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) {
952 g_warning ("%s: Attempting to unref unused handle %p",
957 /* Possible race condition here if another thread refs the
958 * handle between here and setting the type to UNUSED. I
959 * could lock a mutex, but I'm not sure that allowing a handle
960 * reference to reach 0 isn't an application bug anyway.
962 destroy = (InterlockedDecrement ((gint32 *)&_WAPI_PRIVATE_HANDLES(idx).ref) ==0);
965 g_message ("%s: %s handle %p ref now %d (destroy %s)", __func__,
966 _wapi_handle_typename[_WAPI_PRIVATE_HANDLES (idx).type],
968 _WAPI_PRIVATE_HANDLES(idx).ref, destroy?"TRUE":"FALSE");
972 /* Need to copy the handle info, reset the slot in the
973 * array, and _only then_ call the close function to
974 * avoid race conditions (eg file descriptors being
975 * closed, and another file being opened getting the
976 * same fd racing the memset())
978 struct _WapiHandleUnshared handle_data;
979 struct _WapiHandleShared shared_handle_data;
980 WapiHandleType type = _WAPI_PRIVATE_HANDLES(idx).type;
981 void (*close_func)(gpointer, gpointer) = _wapi_handle_ops_get_close_func (type);
982 gboolean is_shared = _WAPI_SHARED_HANDLE(type);
985 /* If this is a shared handle we need to take
986 * the shared lock outside of the scan_mutex
987 * lock to avoid deadlocks
989 thr_ret = _wapi_handle_lock_shared_handles ();
990 g_assert (thr_ret == 0);
993 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup, (void *)&scan_mutex);
994 thr_ret = mono_mutex_lock (&scan_mutex);
997 g_message ("%s: Destroying handle %p", __func__, handle);
1000 memcpy (&handle_data, &_WAPI_PRIVATE_HANDLES(idx),
1001 sizeof (struct _WapiHandleUnshared));
1003 memset (&_WAPI_PRIVATE_HANDLES(idx).u, '\0',
1004 sizeof(_WAPI_PRIVATE_HANDLES(idx).u));
1006 _WAPI_PRIVATE_HANDLES(idx).type = WAPI_HANDLE_UNUSED;
1009 /* Destroy the mutex and cond var. We hope nobody
1010 * tried to grab them between the handle unlock and
1011 * now, but pthreads doesn't have a
1012 * "unlock_and_destroy" atomic function.
1014 thr_ret = mono_mutex_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_mutex);
1015 g_assert (thr_ret == 0);
1017 thr_ret = pthread_cond_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_cond);
1018 g_assert (thr_ret == 0);
1020 struct _WapiHandleShared *shared = &_wapi_shared_layout->handles[handle_data.u.shared.offset];
1022 memcpy (&shared_handle_data, shared,
1023 sizeof (struct _WapiHandleShared));
1025 /* It's possible that this handle is already
1026 * pointing at a deleted shared section
1029 g_message ("%s: %s handle %p shared refs before dec %d", __func__, _wapi_handle_typename[type], handle, shared->handle_refs);
1032 if (shared->handle_refs > 0) {
1033 shared->handle_refs--;
1034 if (shared->handle_refs == 0) {
1035 memset (shared, '\0', sizeof (struct _WapiHandleShared));
1040 thr_ret = mono_mutex_unlock (&scan_mutex);
1041 g_assert (thr_ret == 0);
1042 pthread_cleanup_pop (0);
1045 _wapi_handle_unlock_shared_handles ();
1048 if (close_func != NULL) {
1050 close_func (handle, &shared_handle_data.u);
1052 close_func (handle, &handle_data.u);
1058 void _wapi_handle_register_capabilities (WapiHandleType type,
1059 WapiHandleCapability caps)
1061 handle_caps[type] = caps;
1064 gboolean _wapi_handle_test_capabilities (gpointer handle,
1065 WapiHandleCapability caps)
1067 guint32 idx = GPOINTER_TO_UINT(handle);
1068 WapiHandleType type;
1070 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1074 type = _WAPI_PRIVATE_HANDLES(idx).type;
1077 g_message ("%s: testing 0x%x against 0x%x (%d)", __func__,
1078 handle_caps[type], caps, handle_caps[type] & caps);
1081 return((handle_caps[type] & caps) != 0);
1084 static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer)
1086 if (handle_ops[type] != NULL &&
1087 handle_ops[type]->close != NULL) {
1088 return (handle_ops[type]->close);
1094 void _wapi_handle_ops_close (gpointer handle, gpointer data)
1096 guint32 idx = GPOINTER_TO_UINT(handle);
1097 WapiHandleType type;
1099 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1103 type = _WAPI_PRIVATE_HANDLES(idx).type;
1105 if (handle_ops[type] != NULL &&
1106 handle_ops[type]->close != NULL) {
1107 handle_ops[type]->close (handle, data);
1111 void _wapi_handle_ops_signal (gpointer handle)
1113 guint32 idx = GPOINTER_TO_UINT(handle);
1114 WapiHandleType type;
1116 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1120 type = _WAPI_PRIVATE_HANDLES(idx).type;
1122 if (handle_ops[type] != NULL && handle_ops[type]->signal != NULL) {
1123 handle_ops[type]->signal (handle);
1127 gboolean _wapi_handle_ops_own (gpointer handle)
1129 guint32 idx = GPOINTER_TO_UINT(handle);
1130 WapiHandleType type;
1132 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1136 type = _WAPI_PRIVATE_HANDLES(idx).type;
1138 if (handle_ops[type] != NULL && handle_ops[type]->own_handle != NULL) {
1139 return(handle_ops[type]->own_handle (handle));
1145 gboolean _wapi_handle_ops_isowned (gpointer handle)
1147 guint32 idx = GPOINTER_TO_UINT(handle);
1148 WapiHandleType type;
1150 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1154 type = _WAPI_PRIVATE_HANDLES(idx).type;
1156 if (handle_ops[type] != NULL && handle_ops[type]->is_owned != NULL) {
1157 return(handle_ops[type]->is_owned (handle));
1163 guint32 _wapi_handle_ops_special_wait (gpointer handle, guint32 timeout)
1165 guint32 idx = GPOINTER_TO_UINT(handle);
1166 WapiHandleType type;
1168 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1169 return(WAIT_FAILED);
1172 type = _WAPI_PRIVATE_HANDLES(idx).type;
1174 if (handle_ops[type] != NULL &&
1175 handle_ops[type]->special_wait != NULL) {
1176 return(handle_ops[type]->special_wait (handle, timeout));
1178 return(WAIT_FAILED);
1182 void _wapi_handle_ops_prewait (gpointer handle)
1184 guint32 idx = GPOINTER_TO_UINT (handle);
1185 WapiHandleType type;
1187 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1191 type = _WAPI_PRIVATE_HANDLES (idx).type;
1193 if (handle_ops[type] != NULL &&
1194 handle_ops[type]->prewait != NULL) {
1195 handle_ops[type]->prewait (handle);
1202 * @handle: The handle to release
1204 * Closes and invalidates @handle, releasing any resources it
1205 * consumes. When the last handle to a temporary or non-persistent
1206 * object is closed, that object can be deleted. Closing the same
1207 * handle twice is an error.
1209 * Return value: %TRUE on success, %FALSE otherwise.
1211 gboolean CloseHandle(gpointer handle)
1213 if (handle == NULL) {
1214 /* Problem: because we map file descriptors to the
1215 * same-numbered handle we can't tell the difference
1216 * between a bogus handle and the handle to stdin.
1217 * Assume that it's the console handle if that handle
1220 if (_WAPI_PRIVATE_HANDLES (0).type != WAPI_HANDLE_CONSOLE) {
1221 SetLastError (ERROR_INVALID_PARAMETER);
1226 _wapi_handle_unref (handle);
1231 /* Lots more to implement here, but this is all we need at the moment */
1232 gboolean DuplicateHandle (gpointer srcprocess, gpointer src,
1233 gpointer targetprocess, gpointer *target,
1234 guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, guint32 options G_GNUC_UNUSED)
1236 if (srcprocess != _WAPI_PROCESS_CURRENT ||
1237 targetprocess != _WAPI_PROCESS_CURRENT) {
1238 /* Duplicating other process's handles is not supported */
1239 SetLastError (ERROR_INVALID_HANDLE);
1243 if (src == _WAPI_PROCESS_CURRENT) {
1244 *target = _wapi_process_duplicate ();
1245 } else if (src == _WAPI_THREAD_CURRENT) {
1246 *target = _wapi_thread_duplicate ();
1248 _wapi_handle_ref (src);
1255 gboolean _wapi_handle_count_signalled_handles (guint32 numhandles,
1261 guint32 count, i, iter=0;
1264 WapiHandleType type;
1266 /* Lock all the handles, with backoff */
1268 thr_ret = _wapi_handle_lock_shared_handles ();
1269 g_assert (thr_ret == 0);
1271 for(i=0; i<numhandles; i++) {
1272 gpointer handle = handles[i];
1273 guint32 idx = GPOINTER_TO_UINT(handle);
1276 g_message ("%s: attempting to lock %p", __func__, handle);
1279 type = _WAPI_PRIVATE_HANDLES(idx).type;
1281 thr_ret = _wapi_handle_trylock_handle (handle);
1287 g_message ("%s: attempt failed for %p: %s", __func__,
1288 handle, strerror (thr_ret));
1291 thr_ret = _wapi_handle_unlock_shared_handles ();
1292 g_assert (thr_ret == 0);
1295 handle = handles[i];
1296 idx = GPOINTER_TO_UINT(handle);
1298 thr_ret = _wapi_handle_unlock_handle (handle);
1299 g_assert (thr_ret == 0);
1302 /* If iter ever reaches 100 the nanosleep will
1303 * return EINVAL immediately, but we have a
1304 * design flaw if that happens.
1308 g_warning ("%s: iteration overflow!",
1314 g_message ("%s: Backing off for %d ms", __func__,
1317 _wapi_handle_spin (10 * iter);
1324 g_message ("%s: Locked all handles", __func__);
1330 for(i=0; i<numhandles; i++) {
1331 gpointer handle = handles[i];
1332 guint32 idx = GPOINTER_TO_UINT(handle);
1334 type = _WAPI_PRIVATE_HANDLES(idx).type;
1336 _wapi_handle_ref (handle);
1339 g_message ("%s: Checking handle %p", __func__, handle);
1342 if(((_wapi_handle_test_capabilities (handle, WAPI_HANDLE_CAP_OWN)==TRUE) &&
1343 (_wapi_handle_ops_isowned (handle) == TRUE)) ||
1344 (_WAPI_SHARED_HANDLE(type) &&
1345 WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) ||
1346 (!_WAPI_SHARED_HANDLE(type) &&
1347 _WAPI_PRIVATE_HANDLES(idx).signalled == TRUE)) {
1351 g_message ("%s: Handle %p signalled", __func__,
1361 g_message ("%s: %d event handles signalled", __func__, count);
1364 if ((waitall == TRUE && count == numhandles) ||
1365 (waitall == FALSE && count > 0)) {
1372 g_message ("%s: Returning %d", __func__, ret);
1380 void _wapi_handle_unlock_handles (guint32 numhandles, gpointer *handles)
1385 thr_ret = _wapi_handle_unlock_shared_handles ();
1386 g_assert (thr_ret == 0);
1388 for(i=0; i<numhandles; i++) {
1389 gpointer handle = handles[i];
1392 g_message ("%s: unlocking handle %p", __func__, handle);
1395 thr_ret = _wapi_handle_unlock_handle (handle);
1396 g_assert (thr_ret == 0);
1400 static int timedwait_signal_poll_cond (pthread_cond_t *cond, mono_mutex_t *mutex, struct timespec *timeout)
1402 struct timespec fake_timeout;
1405 _wapi_calc_timeout (&fake_timeout, 100);
1407 if (timeout != NULL && ((fake_timeout.tv_sec > timeout->tv_sec) ||
1408 (fake_timeout.tv_sec == timeout->tv_sec &&
1409 fake_timeout.tv_nsec > timeout->tv_nsec))) {
1410 /* Real timeout is less than 100ms time */
1411 ret=mono_cond_timedwait (cond, mutex, timeout);
1413 ret=mono_cond_timedwait (cond, mutex, &fake_timeout);
1415 /* Mask the fake timeout, this will cause
1416 * another poll if the cond was not really signaled
1418 if (ret==ETIMEDOUT) {
1426 int _wapi_handle_wait_signal (void)
1428 return timedwait_signal_poll_cond (&_wapi_global_signal_cond, &_wapi_global_signal_mutex, NULL);
1431 int _wapi_handle_timedwait_signal (struct timespec *timeout)
1433 return timedwait_signal_poll_cond (&_wapi_global_signal_cond, &_wapi_global_signal_mutex, timeout);
1436 int _wapi_handle_wait_signal_handle (gpointer handle)
1439 g_message ("%s: waiting for %p", __func__, handle);
1442 return _wapi_handle_timedwait_signal_handle (handle, NULL);
1445 int _wapi_handle_timedwait_signal_handle (gpointer handle,
1446 struct timespec *timeout)
1449 g_message ("%s: waiting for %p (type %s)", __func__, handle,
1450 _wapi_handle_typename[_wapi_handle_type (handle)]);
1453 if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
1454 if (WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) {
1457 if (timeout != NULL) {
1458 struct timespec fake_timeout;
1459 _wapi_calc_timeout (&fake_timeout, 100);
1461 if ((fake_timeout.tv_sec > timeout->tv_sec) ||
1462 (fake_timeout.tv_sec == timeout->tv_sec &&
1463 fake_timeout.tv_nsec > timeout->tv_nsec)) {
1464 /* FIXME: Real timeout is less than
1465 * 100ms time, but is it really worth
1466 * calculating to the exact ms?
1468 _wapi_handle_spin (100);
1470 if (WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) {
1477 _wapi_handle_spin (100);
1481 guint32 idx = GPOINTER_TO_UINT(handle);
1482 return timedwait_signal_poll_cond (&_WAPI_PRIVATE_HANDLES(idx).signal_cond, &_WAPI_PRIVATE_HANDLES(idx).signal_mutex, timeout);
1486 gboolean _wapi_handle_get_or_set_share (dev_t device, ino_t inode,
1487 guint32 new_sharemode,
1489 guint32 *old_sharemode,
1490 guint32 *old_access,
1491 struct _WapiFileShare **share_info)
1493 struct _WapiFileShare *file_share;
1494 guint32 now = (guint32)(time(NULL) & 0xFFFFFFFF);
1495 int thr_ret, i, first_unused = -1;
1496 gboolean exists = FALSE;
1498 /* Prevents entries from expiring under us as we search
1500 thr_ret = _wapi_handle_lock_shared_handles ();
1501 g_assert (thr_ret == 0);
1503 /* Prevent new entries racing with us */
1504 thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1505 g_assert (thr_ret == 0);
1507 /* If a linear scan gets too slow we'll have to fit a hash
1508 * table onto the shared mem backing store
1511 for (i = 0; i <= _wapi_fileshare_layout->hwm; i++) {
1512 file_share = &_wapi_fileshare_layout->share_info[i];
1514 /* Make a note of an unused slot, in case we need to
1517 if (first_unused == -1 && file_share->handle_refs == 0) {
1522 if (file_share->handle_refs == 0) {
1526 if (file_share->device == device &&
1527 file_share->inode == inode) {
1528 *old_sharemode = file_share->sharemode;
1529 *old_access = file_share->access;
1530 *share_info = file_share;
1532 /* Increment the reference count while we
1533 * still have sole access to the shared area.
1534 * This makes the increment atomic wrt
1537 InterlockedIncrement ((gint32 *)&file_share->handle_refs);
1545 if (i == _WAPI_FILESHARE_SIZE && first_unused == -1) {
1548 if (first_unused == -1) {
1549 file_share = &_wapi_fileshare_layout->share_info[++i];
1550 _wapi_fileshare_layout->hwm = i;
1552 file_share = &_wapi_fileshare_layout->share_info[first_unused];
1555 file_share->device = device;
1556 file_share->inode = inode;
1557 file_share->opened_by_pid = _wapi_getpid ();
1558 file_share->sharemode = new_sharemode;
1559 file_share->access = new_access;
1560 file_share->handle_refs = 1;
1561 *share_info = file_share;
1565 if (*share_info != NULL) {
1566 InterlockedExchange ((gint32 *)&(*share_info)->timestamp, now);
1569 thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1571 _wapi_handle_unlock_shared_handles ();
1576 /* If we don't have the info in /proc, check if the process that
1577 * opened this share info is still there (it's not a perfect method,
1580 static void _wapi_handle_check_share_by_pid (struct _WapiFileShare *share_info)
1582 if (kill (share_info->opened_by_pid, 0) == -1 &&
1585 /* It's gone completely (or there's a new process
1586 * owned by someone else) so mark this share info as
1590 g_message ("%s: Didn't find it, destroying entry", __func__);
1593 memset (share_info, '\0', sizeof(struct _WapiFileShare));
1597 /* Scan /proc/<pids>/fd/ for open file descriptors to the file in
1598 * question. If there are none, reset the share info.
1600 * This implementation is Linux-specific; legacy systems will have to
1601 * implement their own ways of finding out if a particular file is
1602 * open by a process.
1604 void _wapi_handle_check_share (struct _WapiFileShare *share_info, int fd)
1606 gboolean found = FALSE, proc_fds = FALSE;
1607 pid_t self = _wapi_getpid ();
1611 /* Prevents entries from expiring under us if we remove this
1614 thr_ret = _wapi_handle_lock_shared_handles ();
1615 g_assert (thr_ret == 0);
1617 /* Prevent new entries racing with us */
1618 thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1619 g_assert (thr_ret == 0);
1621 /* If there is no /proc, there's nothing more we can do here */
1622 if (access ("/proc", F_OK) == -1) {
1623 _wapi_handle_check_share_by_pid (share_info);
1627 /* If there's another handle that thinks it owns this fd, then even
1628 * if the fd has been closed behind our back consider it still owned.
1629 * See bugs 75764 and 75891
1631 for (i = 0; i < _wapi_fd_reserve; i++) {
1632 struct _WapiHandleUnshared *handle = &_WAPI_PRIVATE_HANDLES(i);
1635 handle->type == WAPI_HANDLE_FILE) {
1636 struct _WapiHandle_file *file_handle = &handle->u.file;
1638 if (file_handle->share_info == share_info) {
1640 g_message ("%s: handle 0x%x has this file open!",
1649 for (i = 0; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
1650 struct _WapiHandleShared *shared;
1651 struct _WapiHandle_process *process_handle;
1653 shared = &_wapi_shared_layout->handles[i];
1655 if (shared->type == WAPI_HANDLE_PROCESS) {
1657 struct dirent *fd_entry;
1658 char subdir[_POSIX_PATH_MAX];
1660 process_handle = &shared->u.process;
1661 pid = process_handle->id;
1663 /* Look in /proc/<pid>/fd/ but ignore
1664 * /proc/<our pid>/fd/<fd>, as we have the
1667 g_snprintf (subdir, _POSIX_PATH_MAX, "/proc/%d/fd",
1670 fd_dir = opendir (subdir);
1671 if (fd_dir == NULL) {
1676 g_message ("%s: Looking in %s", __func__, subdir);
1681 while ((fd_entry = readdir (fd_dir)) != NULL) {
1682 char path[_POSIX_PATH_MAX];
1683 struct stat link_stat;
1685 if (!strcmp (fd_entry->d_name, ".") ||
1686 !strcmp (fd_entry->d_name, "..") ||
1688 fd == atoi (fd_entry->d_name))) {
1692 g_snprintf (path, _POSIX_PATH_MAX,
1693 "/proc/%d/fd/%s", pid,
1696 stat (path, &link_stat);
1697 if (link_stat.st_dev == share_info->device &&
1698 link_stat.st_ino == share_info->inode) {
1700 g_message ("%s: Found it at %s",
1712 if (proc_fds == FALSE) {
1713 _wapi_handle_check_share_by_pid (share_info);
1714 } else if (found == FALSE) {
1715 /* Blank out this entry, as it is stale */
1717 g_message ("%s: Didn't find it, destroying entry", __func__);
1720 memset (share_info, '\0', sizeof(struct _WapiFileShare));
1724 thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1726 _wapi_handle_unlock_shared_handles ();
1729 void _wapi_handle_dump (void)
1731 struct _WapiHandleUnshared *handle_data;
1735 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
1736 (void *)&scan_mutex);
1737 thr_ret = mono_mutex_lock (&scan_mutex);
1738 g_assert (thr_ret == 0);
1740 for(i = SLOT_INDEX (0); _wapi_private_handles [i] != NULL; i++) {
1741 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
1742 handle_data = &_wapi_private_handles [i][k];
1744 if (handle_data->type == WAPI_HANDLE_UNUSED) {
1748 g_print ("%3x [%7s] %s %d ",
1749 i * _WAPI_HANDLE_INITIAL_COUNT + k,
1750 _wapi_handle_typename[handle_data->type],
1751 handle_data->signalled?"Sg":"Un",
1753 handle_details[handle_data->type](&handle_data->u);
1758 thr_ret = mono_mutex_unlock (&scan_mutex);
1759 g_assert (thr_ret == 0);
1760 pthread_cleanup_pop (0);
1763 static void _wapi_shared_details (gpointer handle_info)
1765 struct _WapiHandle_shared_ref *shared = (struct _WapiHandle_shared_ref *)handle_info;
1767 g_print ("offset: 0x%x", shared->offset);
1770 void _wapi_handle_update_refs (void)
1774 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
1776 thr_ret = _wapi_handle_lock_shared_handles ();
1777 g_assert (thr_ret == 0);
1779 /* Prevent file share entries racing with us */
1780 thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1781 g_assert(thr_ret == 0);
1783 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
1784 (void *)&scan_mutex);
1785 thr_ret = mono_mutex_lock (&scan_mutex);
1787 for(i = SLOT_INDEX (0); _wapi_private_handles [i] != NULL; i++) {
1788 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
1789 struct _WapiHandleUnshared *handle = &_wapi_private_handles [i][k];
1791 if (_WAPI_SHARED_HANDLE(handle->type)) {
1792 struct _WapiHandleShared *shared_data;
1795 g_message ("%s: (%d) handle 0x%x is SHARED (%s)", __func__, _wapi_getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k, _wapi_handle_typename[handle->type]);
1798 shared_data = &_wapi_shared_layout->handles[handle->u.shared.offset];
1801 g_message ("%s: (%d) Updating timestamp of handle 0x%x", __func__, _wapi_getpid (), handle->u.shared.offset);
1804 InterlockedExchange ((gint32 *)&shared_data->timestamp, now);
1805 } else if (handle->type == WAPI_HANDLE_FILE) {
1806 struct _WapiHandle_file *file_handle = &handle->u.file;
1809 g_message ("%s: (%d) handle 0x%x is FILE", __func__, _wapi_getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k);
1812 g_assert (file_handle->share_info != NULL);
1815 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));
1818 InterlockedExchange ((gint32 *)&file_handle->share_info->timestamp, now);
1823 thr_ret = mono_mutex_unlock (&scan_mutex);
1824 g_assert (thr_ret == 0);
1825 pthread_cleanup_pop (0);
1827 thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1829 _wapi_handle_unlock_shared_handles ();