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;
105 struct _WapiHandleSharedLayout *_wapi_shared_layout = NULL;
106 struct _WapiFileShareLayout *_wapi_fileshare_layout = NULL;
108 guint32 _wapi_fd_reserve;
110 mono_mutex_t _wapi_global_signal_mutex;
111 pthread_cond_t _wapi_global_signal_cond;
114 gboolean _wapi_has_shut_down = FALSE;
116 /* Use this instead of getpid(), to cope with linuxthreads. It's a
117 * function rather than a variable lookup because we need to get at
118 * this before share_init() might have been called.
120 static pid_t _wapi_pid;
121 static mono_once_t pid_init_once = MONO_ONCE_INIT;
123 static void pid_init (void)
125 _wapi_pid = getpid ();
128 pid_t _wapi_getpid (void)
130 mono_once (&pid_init_once, pid_init);
136 static mono_mutex_t scan_mutex = MONO_MUTEX_INITIALIZER;
138 static void handle_cleanup (void)
142 _wapi_process_signal_self ();
144 /* Every shared handle we were using ought really to be closed
145 * by now, but to make sure just blow them all away. The
146 * exiting finalizer thread in particular races us to the
147 * program exit and doesn't always win, so it can be left
148 * cluttering up the shared file. Anything else left over is
151 for(i = SLOT_INDEX (0); _wapi_private_handles[i] != NULL; i++) {
152 for(j = SLOT_OFFSET (0); j < _WAPI_HANDLE_INITIAL_COUNT; j++) {
153 struct _WapiHandleUnshared *handle_data = &_wapi_private_handles[i][j];
154 int type = handle_data->type;
157 if (_WAPI_SHARED_HANDLE (type)) {
158 gpointer handle = GINT_TO_POINTER (i*_WAPI_HANDLE_INITIAL_COUNT+j);
160 if (type == WAPI_HANDLE_THREAD) {
161 /* Special-case thread handles
162 * because they need extra
163 * cleanup. This also avoids
164 * a race condition between
165 * the application exit and
166 * the finalizer thread - if
167 * it finishes up between now
168 * and actual app termination
169 * it will find all its handle
170 * details have been blown
171 * away, so this sets those
174 _wapi_thread_set_termination_details (handle, 0);
177 for(k = handle_data->ref; k > 0; k--) {
179 g_message ("%s: unreffing %s handle %p", __func__, _wapi_handle_typename[type], handle);
182 _wapi_handle_unref (handle);
188 _wapi_shm_semaphores_remove ();
190 mono_mutex_destroy(&_wapi_global_signal_mutex);
191 pthread_cond_destroy(&_wapi_global_signal_cond);
194 void _wapi_cleanup ()
196 g_assert (_wapi_has_shut_down == FALSE);
198 _wapi_has_shut_down = TRUE;
200 _wapi_critical_section_cleanup ();
201 _wapi_error_cleanup ();
202 _wapi_thread_cleanup ();
205 static mono_once_t shared_init_once = MONO_ONCE_INIT;
206 static void shared_init (void)
211 g_assert ((sizeof (handle_ops) / sizeof (handle_ops[0]))
212 == WAPI_HANDLE_COUNT);
214 _wapi_fd_reserve = getdtablesize();
217 _wapi_private_handles [idx++] = g_new0 (struct _WapiHandleUnshared,
218 _WAPI_HANDLE_INITIAL_COUNT);
220 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
221 } while(_wapi_fd_reserve > _wapi_private_handle_count);
223 _wapi_shm_semaphores_init ();
225 _wapi_shared_layout = _wapi_shm_attach (WAPI_SHM_DATA);
226 g_assert (_wapi_shared_layout != NULL);
228 _wapi_fileshare_layout = _wapi_shm_attach (WAPI_SHM_FILESHARE);
229 g_assert (_wapi_fileshare_layout != NULL);
231 _wapi_collection_init ();
233 thr_ret = pthread_cond_init(&_wapi_global_signal_cond, NULL);
234 g_assert (thr_ret == 0);
236 thr_ret = mono_mutex_init(&_wapi_global_signal_mutex, NULL);
237 g_assert (thr_ret == 0);
239 /* Using g_atexit here instead of an explicit function call in
240 * a cleanup routine lets us cope when a third-party library
241 * calls exit (eg if an X client loses the connection to its
244 g_atexit (handle_cleanup);
247 static void _wapi_handle_init_shared (struct _WapiHandleShared *handle,
249 gpointer handle_specific)
251 g_assert (_wapi_has_shut_down == FALSE);
254 handle->timestamp = (guint32)(time (NULL) & 0xFFFFFFFF);
255 handle->signalled = FALSE;
256 handle->handle_refs = 1;
258 if (handle_specific != NULL) {
259 memcpy (&handle->u, handle_specific, sizeof (handle->u));
263 static void _wapi_handle_init (struct _WapiHandleUnshared *handle,
264 WapiHandleType type, gpointer handle_specific)
268 g_assert (_wapi_has_shut_down == FALSE);
271 handle->signalled = FALSE;
274 if (!_WAPI_SHARED_HANDLE(type)) {
275 thr_ret = pthread_cond_init (&handle->signal_cond, NULL);
276 g_assert (thr_ret == 0);
278 thr_ret = mono_mutex_init (&handle->signal_mutex, NULL);
279 g_assert (thr_ret == 0);
281 if (handle_specific != NULL) {
282 memcpy (&handle->u, handle_specific,
288 static guint32 _wapi_handle_new_shared (WapiHandleType type,
289 gpointer handle_specific)
292 static guint32 last = 1;
295 g_assert (_wapi_has_shut_down == FALSE);
297 /* Leave the first slot empty as a guard */
299 /* FIXME: expandable array */
300 for(offset = last; offset <_WAPI_HANDLE_INITIAL_COUNT; offset++) {
301 struct _WapiHandleShared *handle = &_wapi_shared_layout->handles[offset];
303 if(handle->type == WAPI_HANDLE_UNUSED) {
304 thr_ret = _wapi_handle_lock_shared_handles ();
305 g_assert (thr_ret == 0);
307 if (InterlockedCompareExchange ((gint32 *)&handle->type, type, WAPI_HANDLE_UNUSED) == WAPI_HANDLE_UNUSED) {
310 _wapi_handle_init_shared (handle, type,
313 _wapi_handle_unlock_shared_handles ();
317 /* Someone else beat us to it, just
322 _wapi_handle_unlock_shared_handles ();
327 /* Try again from the beginning */
332 /* Will need to expand the array. The caller will sort it out */
338 * _wapi_handle_new_internal:
339 * @type: Init handle to this type
341 * Search for a free handle and initialize it. Return the handle on
342 * success and 0 on failure. This is only called from
343 * _wapi_handle_new, and scan_mutex must be held.
345 static guint32 _wapi_handle_new_internal (WapiHandleType type,
346 gpointer handle_specific)
349 static guint32 last = 0;
350 gboolean retry = FALSE;
352 g_assert (_wapi_has_shut_down == FALSE);
354 /* A linear scan should be fast enough. Start from the last
355 * allocation, assuming that handles are allocated more often
356 * than they're freed. Leave the space reserved for file
360 if (last < _wapi_fd_reserve) {
361 last = _wapi_fd_reserve;
368 for(i = SLOT_INDEX (count); _wapi_private_handles [i] != NULL; i++) {
369 for (k = SLOT_OFFSET (count); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
370 struct _WapiHandleUnshared *handle = &_wapi_private_handles [i][k];
372 if(handle->type == WAPI_HANDLE_UNUSED) {
375 _wapi_handle_init (handle, type, handle_specific);
382 if(retry && last > _wapi_fd_reserve) {
383 /* Try again from the beginning */
384 last = _wapi_fd_reserve;
388 /* Will need to expand the array. The caller will sort it out */
393 gpointer _wapi_handle_new (WapiHandleType type, gpointer handle_specific)
395 guint32 handle_idx = 0;
399 g_assert (_wapi_has_shut_down == FALSE);
401 mono_once (&shared_init_once, shared_init);
404 g_message ("%s: Creating new handle of type %s", __func__,
405 _wapi_handle_typename[type]);
408 g_assert(!_WAPI_FD_HANDLE(type));
410 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
411 (void *)&scan_mutex);
412 thr_ret = mono_mutex_lock (&scan_mutex);
413 g_assert (thr_ret == 0);
415 while ((handle_idx = _wapi_handle_new_internal (type, handle_specific)) == 0) {
416 /* Try and expand the array, and have another go */
417 int idx = SLOT_INDEX (_wapi_private_handle_count);
418 if (idx >= _WAPI_PRIVATE_MAX_SLOTS) {
422 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
423 _WAPI_HANDLE_INITIAL_COUNT);
425 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
428 thr_ret = mono_mutex_unlock (&scan_mutex);
429 g_assert (thr_ret == 0);
430 pthread_cleanup_pop (0);
432 if (handle_idx == 0) {
433 /* We ran out of slots */
434 handle = _WAPI_HANDLE_INVALID;
438 /* Make sure we left the space for fd mappings */
439 g_assert (handle_idx >= _wapi_fd_reserve);
441 handle = GUINT_TO_POINTER (handle_idx);
444 g_message ("%s: Allocated new handle %p", __func__, handle);
447 if (_WAPI_SHARED_HANDLE(type)) {
448 /* Add the shared section too */
451 ref = _wapi_handle_new_shared (type, handle_specific);
453 _wapi_handle_collect ();
454 ref = _wapi_handle_new_shared (type, handle_specific);
456 /* FIXME: grow the arrays */
457 handle = _WAPI_HANDLE_INVALID;
462 _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = ref;
464 g_message ("%s: New shared handle at offset 0x%x", __func__,
473 gpointer _wapi_handle_new_from_offset (WapiHandleType type, guint32 offset,
476 guint32 handle_idx = 0;
477 gpointer handle = INVALID_HANDLE_VALUE;
479 struct _WapiHandleShared *shared;
480 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
482 g_assert (_wapi_has_shut_down == FALSE);
484 mono_once (&shared_init_once, shared_init);
487 g_message ("%s: Creating new handle of type %s to offset %d", __func__,
488 _wapi_handle_typename[type], offset);
491 g_assert(!_WAPI_FD_HANDLE(type));
492 g_assert(_WAPI_SHARED_HANDLE(type));
493 g_assert(offset != 0);
495 shared = &_wapi_shared_layout->handles[offset];
497 /* Bump up the timestamp for this offset */
498 InterlockedExchange ((gint32 *)&shared->timestamp, now);
501 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
502 (void *)&scan_mutex);
503 thr_ret = mono_mutex_lock (&scan_mutex);
504 g_assert (thr_ret == 0);
506 for (i = SLOT_INDEX (0); _wapi_private_handles [i] != NULL; i++) {
507 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
508 struct _WapiHandleUnshared *handle_data = &_wapi_private_handles [i][k];
510 if (handle_data->type == type &&
511 handle_data->u.shared.offset == offset) {
512 handle = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
513 goto first_pass_done;
519 thr_ret = mono_mutex_unlock (&scan_mutex);
520 g_assert (thr_ret == 0);
521 pthread_cleanup_pop (0);
523 if (handle != INVALID_HANDLE_VALUE) {
524 _wapi_handle_ref (handle);
527 g_message ("%s: Returning old handle %p referencing 0x%x",
528 __func__, handle, offset);
533 /* Prevent entries expiring under us as we search */
534 thr_ret = _wapi_handle_lock_shared_handles ();
535 g_assert (thr_ret == 0);
537 if (shared->type == WAPI_HANDLE_UNUSED) {
538 /* Someone deleted this handle while we were working */
540 g_message ("%s: Handle at 0x%x unused", __func__, offset);
545 if (shared->type != type) {
547 g_message ("%s: Wrong type at %d 0x%x! Found %s wanted %s",
548 __func__, offset, offset,
549 _wapi_handle_typename[shared->type],
550 _wapi_handle_typename[type]);
555 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
556 (void *)&scan_mutex);
557 thr_ret = mono_mutex_lock (&scan_mutex);
558 g_assert (thr_ret == 0);
560 while ((handle_idx = _wapi_handle_new_internal (type, NULL)) == 0) {
561 /* Try and expand the array, and have another go */
562 int idx = SLOT_INDEX (_wapi_private_handle_count);
563 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
564 _WAPI_HANDLE_INITIAL_COUNT);
566 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
569 thr_ret = mono_mutex_unlock (&scan_mutex);
570 g_assert (thr_ret == 0);
571 pthread_cleanup_pop (0);
573 /* Make sure we left the space for fd mappings */
574 g_assert (handle_idx >= _wapi_fd_reserve);
576 handle = GUINT_TO_POINTER (handle_idx);
578 _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = offset;
579 InterlockedIncrement ((gint32 *)&shared->handle_refs);
582 g_message ("%s: Allocated new handle %p referencing 0x%x (shared refs %d)", __func__, handle, offset, shared->handle_refs);
586 _wapi_handle_unlock_shared_handles ();
591 gpointer _wapi_handle_new_fd (WapiHandleType type, int fd,
592 gpointer handle_specific)
594 struct _WapiHandleUnshared *handle;
597 g_assert (_wapi_has_shut_down == FALSE);
599 mono_once (&shared_init_once, shared_init);
602 g_message ("%s: Creating new handle of type %s", __func__,
603 _wapi_handle_typename[type]);
606 g_assert(_WAPI_FD_HANDLE(type));
607 g_assert(!_WAPI_SHARED_HANDLE(type));
609 if (fd >= _wapi_fd_reserve) {
611 g_message ("%s: fd %d is too big", __func__, fd);
614 return(GUINT_TO_POINTER (_WAPI_HANDLE_INVALID));
617 handle = &_WAPI_PRIVATE_HANDLES(fd);
619 if (handle->type != WAPI_HANDLE_UNUSED) {
621 g_message ("%s: fd %d is already in use!", __func__, fd);
623 /* FIXME: clean up this handle? We can't do anything
624 * with the fd, cos thats the new one
629 g_message ("%s: Assigning new fd handle %d", __func__, fd);
632 /* Prevent file share entries racing with us, when the file
633 * handle is only half initialised
635 thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
636 g_assert(thr_ret == 0);
638 _wapi_handle_init (handle, type, handle_specific);
640 thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
642 return(GUINT_TO_POINTER(fd));
645 gboolean _wapi_lookup_handle (gpointer handle, WapiHandleType type,
646 gpointer *handle_specific)
648 struct _WapiHandleUnshared *handle_data;
649 guint32 handle_idx = GPOINTER_TO_UINT(handle);
651 if (!_WAPI_PRIVATE_VALID_SLOT (handle_idx)) {
655 handle_data = &_WAPI_PRIVATE_HANDLES(handle_idx);
657 if (handle_data->type != type) {
661 if (handle_specific == NULL) {
665 if (_WAPI_SHARED_HANDLE(type)) {
666 struct _WapiHandle_shared_ref *ref;
667 struct _WapiHandleShared *shared_handle_data;
669 ref = &handle_data->u.shared;
670 shared_handle_data = &_wapi_shared_layout->handles[ref->offset];
672 if (shared_handle_data->type != type) {
673 /* The handle must have been deleted on us
678 *handle_specific = &shared_handle_data->u;
680 *handle_specific = &handle_data->u;
687 _wapi_handle_foreach (WapiHandleType type,
688 gboolean (*on_each)(gpointer test, gpointer user),
691 struct _WapiHandleUnshared *handle_data = NULL;
696 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
697 (void *)&scan_mutex);
698 thr_ret = mono_mutex_lock (&scan_mutex);
699 g_assert (thr_ret == 0);
701 for (i = SLOT_INDEX (0); _wapi_private_handles [i] != NULL; i++) {
702 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
703 handle_data = &_wapi_private_handles [i][k];
705 if (handle_data->type == type) {
706 ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
707 if (on_each (ret, user_data) == TRUE)
713 thr_ret = mono_mutex_unlock (&scan_mutex);
714 g_assert (thr_ret == 0);
715 pthread_cleanup_pop (0);
718 /* This might list some shared handles twice if they are already
719 * opened by this process, and the check function returns FALSE the
720 * first time. Shared handles that are created during the search are
721 * unreffed if the check function returns FALSE, so callers must not
722 * rely on the handle persisting (unless the check function returns
725 gpointer _wapi_search_handle (WapiHandleType type,
726 gboolean (*check)(gpointer test, gpointer user),
728 gpointer *handle_specific,
729 gboolean search_shared)
731 struct _WapiHandleUnshared *handle_data = NULL;
732 struct _WapiHandleShared *shared;
735 gboolean found = FALSE;
738 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
739 (void *)&scan_mutex);
740 thr_ret = mono_mutex_lock (&scan_mutex);
741 g_assert (thr_ret == 0);
743 for (i = SLOT_INDEX (0); !found && _wapi_private_handles [i] != NULL; i++) {
744 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
745 handle_data = &_wapi_private_handles [i][k];
747 if (handle_data->type == type) {
748 ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
749 if (check (ret, user_data) == TRUE) {
750 _wapi_handle_ref (ret);
753 if (_WAPI_SHARED_HANDLE (type)) {
754 shared = &_wapi_shared_layout->handles[i];
763 thr_ret = mono_mutex_unlock (&scan_mutex);
764 g_assert (thr_ret == 0);
765 pthread_cleanup_pop (0);
767 if (!found && search_shared && _WAPI_SHARED_HANDLE (type)) {
768 /* Not found yet, so search the shared memory too */
770 g_message ("%s: Looking at other shared handles...", __func__);
773 for (i = 0; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
774 shared = &_wapi_shared_layout->handles[i];
776 if (shared->type == type) {
777 /* Tell new_from_offset to not
778 * timestamp this handle, because
779 * otherwise it will ping every handle
780 * in the list and they will never
783 ret = _wapi_handle_new_from_offset (type, i,
785 if (ret == INVALID_HANDLE_VALUE) {
786 /* This handle was deleted
787 * while we were looking at it
793 g_message ("%s: Opened tmp handle %p (type %s) from offset %d", __func__, ret, _wapi_handle_typename[type], i);
796 /* It's possible that the shared part
797 * of this handle has now been blown
798 * away (after new_from_offset
799 * successfully opened it,) if its
800 * timestamp is too old. The check
801 * function needs to be aware of this,
802 * and cope if the handle has
805 if (check (ret, user_data) == TRUE) {
806 /* Timestamp this handle, but make
807 * sure it still exists first
809 thr_ret = _wapi_handle_lock_shared_handles ();
810 g_assert (thr_ret == 0);
812 if (shared->type == type) {
813 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
814 InterlockedExchange ((gint32 *)&shared->timestamp, now);
817 handle_data = &_WAPI_PRIVATE_HANDLES(GPOINTER_TO_UINT(ret));
819 _wapi_handle_unlock_shared_handles ();
822 /* It's been deleted,
826 _wapi_handle_unlock_shared_handles ();
830 /* This isn't the handle we're looking
831 * for, so drop the reference we took
832 * in _wapi_handle_new_from_offset ()
834 _wapi_handle_unref (ret);
844 if(handle_specific != NULL) {
845 if (_WAPI_SHARED_HANDLE(type)) {
846 g_assert(shared->type == type);
848 *handle_specific = &shared->u;
850 *handle_specific = &handle_data->u;
858 /* Returns the offset of the metadata array, or -1 on error, or 0 for
859 * not found (0 is not a valid offset)
861 gint32 _wapi_search_handle_namespace (WapiHandleType type,
864 struct _WapiHandleShared *shared_handle_data;
869 g_assert(_WAPI_SHARED_HANDLE(type));
872 g_message ("%s: Lookup for handle named [%s] type %s", __func__,
873 utf8_name, _wapi_handle_typename[type]);
876 /* Do a handle collection before starting to look, so that any
877 * stale cruft gets removed
879 _wapi_handle_collect ();
881 thr_ret = _wapi_handle_lock_shared_handles ();
882 g_assert (thr_ret == 0);
884 for(i = 1; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
885 WapiSharedNamespace *sharedns;
887 shared_handle_data = &_wapi_shared_layout->handles[i];
889 /* Check mutex, event, semaphore, timer, job and
890 * file-mapping object names. So far only mutex,
891 * semaphore and event are implemented.
893 if (!_WAPI_SHARED_NAMESPACE (shared_handle_data->type)) {
898 g_message ("%s: found a shared namespace handle at 0x%x (type %s)", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
901 sharedns=(WapiSharedNamespace *)&shared_handle_data->u;
904 g_message ("%s: name is [%s]", __func__, sharedns->name);
907 if (strcmp (sharedns->name, utf8_name) == 0) {
908 if (shared_handle_data->type != type) {
909 /* Its the wrong type, so fail now */
911 g_message ("%s: handle 0x%x matches name but is wrong type: %s", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
917 g_message ("%s: handle 0x%x matches name and type", __func__, i);
926 _wapi_handle_unlock_shared_handles ();
931 void _wapi_handle_ref (gpointer handle)
933 guint32 idx = GPOINTER_TO_UINT(handle);
934 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
935 struct _WapiHandleUnshared *handle_data;
937 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
941 if (_wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) {
942 g_warning ("%s: Attempting to ref unused handle %p", __func__,
947 handle_data = &_WAPI_PRIVATE_HANDLES(idx);
949 InterlockedIncrement ((gint32 *)&handle_data->ref);
951 /* It's possible for processes to exit before getting around
952 * to updating timestamps in the collection thread, so if a
953 * shared handle is reffed do the timestamp here as well just
956 if (_WAPI_SHARED_HANDLE(handle_data->type)) {
957 struct _WapiHandleShared *shared_data = &_wapi_shared_layout->handles[handle_data->u.shared.offset];
959 InterlockedExchange ((gint32 *)&shared_data->timestamp, now);
963 g_message ("%s: %s handle %p ref now %d", __func__,
964 _wapi_handle_typename[_WAPI_PRIVATE_HANDLES (idx).type],
966 _WAPI_PRIVATE_HANDLES(idx).ref);
970 /* The handle must not be locked on entry to this function */
971 void _wapi_handle_unref (gpointer handle)
973 guint32 idx = GPOINTER_TO_UINT(handle);
974 gboolean destroy = FALSE;
977 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
981 if (_wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) {
982 g_warning ("%s: Attempting to unref unused handle %p",
987 /* Possible race condition here if another thread refs the
988 * handle between here and setting the type to UNUSED. I
989 * could lock a mutex, but I'm not sure that allowing a handle
990 * reference to reach 0 isn't an application bug anyway.
992 destroy = (InterlockedDecrement ((gint32 *)&_WAPI_PRIVATE_HANDLES(idx).ref) ==0);
995 g_message ("%s: %s handle %p ref now %d (destroy %s)", __func__,
996 _wapi_handle_typename[_WAPI_PRIVATE_HANDLES (idx).type],
998 _WAPI_PRIVATE_HANDLES(idx).ref, destroy?"TRUE":"FALSE");
1002 /* Need to copy the handle info, reset the slot in the
1003 * array, and _only then_ call the close function to
1004 * avoid race conditions (eg file descriptors being
1005 * closed, and another file being opened getting the
1006 * same fd racing the memset())
1008 struct _WapiHandleUnshared handle_data;
1009 struct _WapiHandleShared shared_handle_data;
1010 WapiHandleType type = _WAPI_PRIVATE_HANDLES(idx).type;
1011 void (*close_func)(gpointer, gpointer) = _wapi_handle_ops_get_close_func (type);
1012 gboolean is_shared = _WAPI_SHARED_HANDLE(type);
1015 /* If this is a shared handle we need to take
1016 * the shared lock outside of the scan_mutex
1017 * lock to avoid deadlocks
1019 thr_ret = _wapi_handle_lock_shared_handles ();
1020 g_assert (thr_ret == 0);
1023 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup, (void *)&scan_mutex);
1024 thr_ret = mono_mutex_lock (&scan_mutex);
1027 g_message ("%s: Destroying handle %p", __func__, handle);
1030 memcpy (&handle_data, &_WAPI_PRIVATE_HANDLES(idx),
1031 sizeof (struct _WapiHandleUnshared));
1033 memset (&_WAPI_PRIVATE_HANDLES(idx).u, '\0',
1034 sizeof(_WAPI_PRIVATE_HANDLES(idx).u));
1036 _WAPI_PRIVATE_HANDLES(idx).type = WAPI_HANDLE_UNUSED;
1039 /* Destroy the mutex and cond var. We hope nobody
1040 * tried to grab them between the handle unlock and
1041 * now, but pthreads doesn't have a
1042 * "unlock_and_destroy" atomic function.
1044 thr_ret = mono_mutex_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_mutex);
1045 g_assert (thr_ret == 0);
1047 thr_ret = pthread_cond_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_cond);
1048 g_assert (thr_ret == 0);
1050 struct _WapiHandleShared *shared = &_wapi_shared_layout->handles[handle_data.u.shared.offset];
1052 memcpy (&shared_handle_data, shared,
1053 sizeof (struct _WapiHandleShared));
1055 /* It's possible that this handle is already
1056 * pointing at a deleted shared section
1059 g_message ("%s: %s handle %p shared refs before dec %d", __func__, _wapi_handle_typename[type], handle, shared->handle_refs);
1062 if (shared->handle_refs > 0) {
1063 shared->handle_refs--;
1064 if (shared->handle_refs == 0) {
1065 memset (shared, '\0', sizeof (struct _WapiHandleShared));
1070 thr_ret = mono_mutex_unlock (&scan_mutex);
1071 g_assert (thr_ret == 0);
1072 pthread_cleanup_pop (0);
1075 _wapi_handle_unlock_shared_handles ();
1078 if (close_func != NULL) {
1080 close_func (handle, &shared_handle_data.u);
1082 close_func (handle, &handle_data.u);
1088 void _wapi_handle_register_capabilities (WapiHandleType type,
1089 WapiHandleCapability caps)
1091 handle_caps[type] = caps;
1094 gboolean _wapi_handle_test_capabilities (gpointer handle,
1095 WapiHandleCapability caps)
1097 guint32 idx = GPOINTER_TO_UINT(handle);
1098 WapiHandleType type;
1100 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1104 type = _WAPI_PRIVATE_HANDLES(idx).type;
1107 g_message ("%s: testing 0x%x against 0x%x (%d)", __func__,
1108 handle_caps[type], caps, handle_caps[type] & caps);
1111 return((handle_caps[type] & caps) != 0);
1114 static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer)
1116 if (handle_ops[type] != NULL &&
1117 handle_ops[type]->close != NULL) {
1118 return (handle_ops[type]->close);
1124 void _wapi_handle_ops_close (gpointer handle, gpointer data)
1126 guint32 idx = GPOINTER_TO_UINT(handle);
1127 WapiHandleType type;
1129 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1133 type = _WAPI_PRIVATE_HANDLES(idx).type;
1135 if (handle_ops[type] != NULL &&
1136 handle_ops[type]->close != NULL) {
1137 handle_ops[type]->close (handle, data);
1141 void _wapi_handle_ops_signal (gpointer handle)
1143 guint32 idx = GPOINTER_TO_UINT(handle);
1144 WapiHandleType type;
1146 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1150 type = _WAPI_PRIVATE_HANDLES(idx).type;
1152 if (handle_ops[type] != NULL && handle_ops[type]->signal != NULL) {
1153 handle_ops[type]->signal (handle);
1157 gboolean _wapi_handle_ops_own (gpointer handle)
1159 guint32 idx = GPOINTER_TO_UINT(handle);
1160 WapiHandleType type;
1162 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1166 type = _WAPI_PRIVATE_HANDLES(idx).type;
1168 if (handle_ops[type] != NULL && handle_ops[type]->own_handle != NULL) {
1169 return(handle_ops[type]->own_handle (handle));
1175 gboolean _wapi_handle_ops_isowned (gpointer handle)
1177 guint32 idx = GPOINTER_TO_UINT(handle);
1178 WapiHandleType type;
1180 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1184 type = _WAPI_PRIVATE_HANDLES(idx).type;
1186 if (handle_ops[type] != NULL && handle_ops[type]->is_owned != NULL) {
1187 return(handle_ops[type]->is_owned (handle));
1193 guint32 _wapi_handle_ops_special_wait (gpointer handle, guint32 timeout)
1195 guint32 idx = GPOINTER_TO_UINT(handle);
1196 WapiHandleType type;
1198 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1199 return(WAIT_FAILED);
1202 type = _WAPI_PRIVATE_HANDLES(idx).type;
1204 if (handle_ops[type] != NULL &&
1205 handle_ops[type]->special_wait != NULL) {
1206 return(handle_ops[type]->special_wait (handle, timeout));
1208 return(WAIT_FAILED);
1212 void _wapi_handle_ops_prewait (gpointer handle)
1214 guint32 idx = GPOINTER_TO_UINT (handle);
1215 WapiHandleType type;
1217 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1221 type = _WAPI_PRIVATE_HANDLES (idx).type;
1223 if (handle_ops[type] != NULL &&
1224 handle_ops[type]->prewait != NULL) {
1225 handle_ops[type]->prewait (handle);
1232 * @handle: The handle to release
1234 * Closes and invalidates @handle, releasing any resources it
1235 * consumes. When the last handle to a temporary or non-persistent
1236 * object is closed, that object can be deleted. Closing the same
1237 * handle twice is an error.
1239 * Return value: %TRUE on success, %FALSE otherwise.
1241 gboolean CloseHandle(gpointer handle)
1243 if (handle == NULL) {
1244 /* Problem: because we map file descriptors to the
1245 * same-numbered handle we can't tell the difference
1246 * between a bogus handle and the handle to stdin.
1247 * Assume that it's the console handle if that handle
1250 if (_WAPI_PRIVATE_HANDLES (0).type != WAPI_HANDLE_CONSOLE) {
1251 SetLastError (ERROR_INVALID_PARAMETER);
1255 if (handle == _WAPI_HANDLE_INVALID){
1256 SetLastError (ERROR_INVALID_PARAMETER);
1260 _wapi_handle_unref (handle);
1265 /* Lots more to implement here, but this is all we need at the moment */
1266 gboolean DuplicateHandle (gpointer srcprocess, gpointer src,
1267 gpointer targetprocess, gpointer *target,
1268 guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, guint32 options G_GNUC_UNUSED)
1270 if (srcprocess != _WAPI_PROCESS_CURRENT ||
1271 targetprocess != _WAPI_PROCESS_CURRENT) {
1272 /* Duplicating other process's handles is not supported */
1273 SetLastError (ERROR_INVALID_HANDLE);
1277 if (src == _WAPI_PROCESS_CURRENT) {
1278 *target = _wapi_process_duplicate ();
1279 } else if (src == _WAPI_THREAD_CURRENT) {
1280 *target = _wapi_thread_duplicate ();
1282 _wapi_handle_ref (src);
1289 gboolean _wapi_handle_count_signalled_handles (guint32 numhandles,
1295 guint32 count, i, iter=0;
1298 WapiHandleType type;
1300 /* Lock all the handles, with backoff */
1302 thr_ret = _wapi_handle_lock_shared_handles ();
1303 g_assert (thr_ret == 0);
1305 for(i=0; i<numhandles; i++) {
1306 gpointer handle = handles[i];
1307 guint32 idx = GPOINTER_TO_UINT(handle);
1310 g_message ("%s: attempting to lock %p", __func__, handle);
1313 type = _WAPI_PRIVATE_HANDLES(idx).type;
1315 thr_ret = _wapi_handle_trylock_handle (handle);
1321 g_message ("%s: attempt failed for %p: %s", __func__,
1322 handle, strerror (thr_ret));
1325 thr_ret = _wapi_handle_unlock_shared_handles ();
1326 g_assert (thr_ret == 0);
1329 handle = handles[i];
1330 idx = GPOINTER_TO_UINT(handle);
1332 thr_ret = _wapi_handle_unlock_handle (handle);
1333 g_assert (thr_ret == 0);
1336 /* If iter ever reaches 100 the nanosleep will
1337 * return EINVAL immediately, but we have a
1338 * design flaw if that happens.
1342 g_warning ("%s: iteration overflow!",
1348 g_message ("%s: Backing off for %d ms", __func__,
1351 _wapi_handle_spin (10 * iter);
1358 g_message ("%s: Locked all handles", __func__);
1364 for(i=0; i<numhandles; i++) {
1365 gpointer handle = handles[i];
1366 guint32 idx = GPOINTER_TO_UINT(handle);
1368 type = _WAPI_PRIVATE_HANDLES(idx).type;
1370 _wapi_handle_ref (handle);
1373 g_message ("%s: Checking handle %p", __func__, handle);
1376 if(((_wapi_handle_test_capabilities (handle, WAPI_HANDLE_CAP_OWN)==TRUE) &&
1377 (_wapi_handle_ops_isowned (handle) == TRUE)) ||
1378 (_WAPI_SHARED_HANDLE(type) &&
1379 WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) ||
1380 (!_WAPI_SHARED_HANDLE(type) &&
1381 _WAPI_PRIVATE_HANDLES(idx).signalled == TRUE)) {
1385 g_message ("%s: Handle %p signalled", __func__,
1395 g_message ("%s: %d event handles signalled", __func__, count);
1398 if ((waitall == TRUE && count == numhandles) ||
1399 (waitall == FALSE && count > 0)) {
1406 g_message ("%s: Returning %d", __func__, ret);
1414 void _wapi_handle_unlock_handles (guint32 numhandles, gpointer *handles)
1419 thr_ret = _wapi_handle_unlock_shared_handles ();
1420 g_assert (thr_ret == 0);
1422 for(i=0; i<numhandles; i++) {
1423 gpointer handle = handles[i];
1426 g_message ("%s: unlocking handle %p", __func__, handle);
1429 thr_ret = _wapi_handle_unlock_handle (handle);
1430 g_assert (thr_ret == 0);
1434 static int timedwait_signal_poll_cond (pthread_cond_t *cond, mono_mutex_t *mutex, struct timespec *timeout, gboolean alertable)
1436 struct timespec fake_timeout;
1441 ret=mono_cond_timedwait (cond, mutex, timeout);
1443 ret=mono_cond_wait (cond, mutex);
1445 _wapi_calc_timeout (&fake_timeout, 100);
1447 if (timeout != NULL && ((fake_timeout.tv_sec > timeout->tv_sec) ||
1448 (fake_timeout.tv_sec == timeout->tv_sec &&
1449 fake_timeout.tv_nsec > timeout->tv_nsec))) {
1450 /* Real timeout is less than 100ms time */
1451 ret=mono_cond_timedwait (cond, mutex, timeout);
1453 ret=mono_cond_timedwait (cond, mutex, &fake_timeout);
1455 /* Mask the fake timeout, this will cause
1456 * another poll if the cond was not really signaled
1458 if (ret==ETIMEDOUT) {
1467 int _wapi_handle_wait_signal (void)
1469 return timedwait_signal_poll_cond (&_wapi_global_signal_cond, &_wapi_global_signal_mutex, NULL, TRUE);
1472 int _wapi_handle_timedwait_signal (struct timespec *timeout)
1474 return timedwait_signal_poll_cond (&_wapi_global_signal_cond, &_wapi_global_signal_mutex, timeout, TRUE);
1477 int _wapi_handle_wait_signal_handle (gpointer handle, gboolean alertable)
1480 g_message ("%s: waiting for %p", __func__, handle);
1483 return _wapi_handle_timedwait_signal_handle (handle, NULL, alertable);
1486 int _wapi_handle_timedwait_signal_handle (gpointer handle,
1487 struct timespec *timeout, gboolean alertable)
1490 g_message ("%s: waiting for %p (type %s)", __func__, handle,
1491 _wapi_handle_typename[_wapi_handle_type (handle)]);
1494 if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
1495 if (WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) {
1498 if (timeout != NULL) {
1499 struct timespec fake_timeout;
1500 _wapi_calc_timeout (&fake_timeout, 100);
1502 if ((fake_timeout.tv_sec > timeout->tv_sec) ||
1503 (fake_timeout.tv_sec == timeout->tv_sec &&
1504 fake_timeout.tv_nsec > timeout->tv_nsec)) {
1505 /* FIXME: Real timeout is less than
1506 * 100ms time, but is it really worth
1507 * calculating to the exact ms?
1509 _wapi_handle_spin (100);
1511 if (WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) {
1518 _wapi_handle_spin (100);
1522 guint32 idx = GPOINTER_TO_UINT(handle);
1523 return timedwait_signal_poll_cond (&_WAPI_PRIVATE_HANDLES(idx).signal_cond, &_WAPI_PRIVATE_HANDLES(idx).signal_mutex, timeout, alertable);
1527 gboolean _wapi_handle_get_or_set_share (dev_t device, ino_t inode,
1528 guint32 new_sharemode,
1530 guint32 *old_sharemode,
1531 guint32 *old_access,
1532 struct _WapiFileShare **share_info)
1534 struct _WapiFileShare *file_share;
1535 guint32 now = (guint32)(time(NULL) & 0xFFFFFFFF);
1536 int thr_ret, i, first_unused = -1;
1537 gboolean exists = FALSE;
1539 /* Prevents entries from expiring under us as we search
1541 thr_ret = _wapi_handle_lock_shared_handles ();
1542 g_assert (thr_ret == 0);
1544 /* Prevent new entries racing with us */
1545 thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1546 g_assert (thr_ret == 0);
1548 /* If a linear scan gets too slow we'll have to fit a hash
1549 * table onto the shared mem backing store
1552 for (i = 0; i <= _wapi_fileshare_layout->hwm; i++) {
1553 file_share = &_wapi_fileshare_layout->share_info[i];
1555 /* Make a note of an unused slot, in case we need to
1558 if (first_unused == -1 && file_share->handle_refs == 0) {
1563 if (file_share->handle_refs == 0) {
1567 if (file_share->device == device &&
1568 file_share->inode == inode) {
1569 *old_sharemode = file_share->sharemode;
1570 *old_access = file_share->access;
1571 *share_info = file_share;
1573 /* Increment the reference count while we
1574 * still have sole access to the shared area.
1575 * This makes the increment atomic wrt
1578 InterlockedIncrement ((gint32 *)&file_share->handle_refs);
1586 if (i == _WAPI_FILESHARE_SIZE && first_unused == -1) {
1589 if (first_unused == -1) {
1590 file_share = &_wapi_fileshare_layout->share_info[++i];
1591 _wapi_fileshare_layout->hwm = i;
1593 file_share = &_wapi_fileshare_layout->share_info[first_unused];
1596 file_share->device = device;
1597 file_share->inode = inode;
1598 file_share->opened_by_pid = _wapi_getpid ();
1599 file_share->sharemode = new_sharemode;
1600 file_share->access = new_access;
1601 file_share->handle_refs = 1;
1602 *share_info = file_share;
1606 if (*share_info != NULL) {
1607 InterlockedExchange ((gint32 *)&(*share_info)->timestamp, now);
1610 thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1612 _wapi_handle_unlock_shared_handles ();
1617 /* If we don't have the info in /proc, check if the process that
1618 * opened this share info is still there (it's not a perfect method,
1621 static void _wapi_handle_check_share_by_pid (struct _WapiFileShare *share_info)
1623 if (kill (share_info->opened_by_pid, 0) == -1 &&
1626 /* It's gone completely (or there's a new process
1627 * owned by someone else) so mark this share info as
1631 g_message ("%s: Didn't find it, destroying entry", __func__);
1634 memset (share_info, '\0', sizeof(struct _WapiFileShare));
1638 /* Scan /proc/<pids>/fd/ for open file descriptors to the file in
1639 * question. If there are none, reset the share info.
1641 * This implementation is Linux-specific; legacy systems will have to
1642 * implement their own ways of finding out if a particular file is
1643 * open by a process.
1645 void _wapi_handle_check_share (struct _WapiFileShare *share_info, int fd)
1647 gboolean found = FALSE, proc_fds = FALSE;
1648 pid_t self = _wapi_getpid ();
1652 /* Prevents entries from expiring under us if we remove this
1655 thr_ret = _wapi_handle_lock_shared_handles ();
1656 g_assert (thr_ret == 0);
1658 /* Prevent new entries racing with us */
1659 thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1660 g_assert (thr_ret == 0);
1662 /* If there is no /proc, there's nothing more we can do here */
1663 if (access ("/proc", F_OK) == -1) {
1664 _wapi_handle_check_share_by_pid (share_info);
1668 /* If there's another handle that thinks it owns this fd, then even
1669 * if the fd has been closed behind our back consider it still owned.
1670 * See bugs 75764 and 75891
1672 for (i = 0; i < _wapi_fd_reserve; i++) {
1673 struct _WapiHandleUnshared *handle = &_WAPI_PRIVATE_HANDLES(i);
1676 handle->type == WAPI_HANDLE_FILE) {
1677 struct _WapiHandle_file *file_handle = &handle->u.file;
1679 if (file_handle->share_info == share_info) {
1681 g_message ("%s: handle 0x%x has this file open!",
1690 for (i = 0; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
1691 struct _WapiHandleShared *shared;
1692 struct _WapiHandle_process *process_handle;
1694 shared = &_wapi_shared_layout->handles[i];
1696 if (shared->type == WAPI_HANDLE_PROCESS) {
1698 struct dirent *fd_entry;
1699 char subdir[_POSIX_PATH_MAX];
1701 process_handle = &shared->u.process;
1702 pid = process_handle->id;
1704 /* Look in /proc/<pid>/fd/ but ignore
1705 * /proc/<our pid>/fd/<fd>, as we have the
1708 g_snprintf (subdir, _POSIX_PATH_MAX, "/proc/%d/fd",
1711 fd_dir = opendir (subdir);
1712 if (fd_dir == NULL) {
1717 g_message ("%s: Looking in %s", __func__, subdir);
1722 while ((fd_entry = readdir (fd_dir)) != NULL) {
1723 char path[_POSIX_PATH_MAX];
1724 struct stat link_stat;
1726 if (!strcmp (fd_entry->d_name, ".") ||
1727 !strcmp (fd_entry->d_name, "..") ||
1729 fd == atoi (fd_entry->d_name))) {
1733 g_snprintf (path, _POSIX_PATH_MAX,
1734 "/proc/%d/fd/%s", pid,
1737 stat (path, &link_stat);
1738 if (link_stat.st_dev == share_info->device &&
1739 link_stat.st_ino == share_info->inode) {
1741 g_message ("%s: Found it at %s",
1753 if (proc_fds == FALSE) {
1754 _wapi_handle_check_share_by_pid (share_info);
1755 } else if (found == FALSE) {
1756 /* Blank out this entry, as it is stale */
1758 g_message ("%s: Didn't find it, destroying entry", __func__);
1761 memset (share_info, '\0', sizeof(struct _WapiFileShare));
1765 thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1767 _wapi_handle_unlock_shared_handles ();
1770 void _wapi_handle_dump (void)
1772 struct _WapiHandleUnshared *handle_data;
1776 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
1777 (void *)&scan_mutex);
1778 thr_ret = mono_mutex_lock (&scan_mutex);
1779 g_assert (thr_ret == 0);
1781 for(i = SLOT_INDEX (0); _wapi_private_handles [i] != NULL; i++) {
1782 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
1783 handle_data = &_wapi_private_handles [i][k];
1785 if (handle_data->type == WAPI_HANDLE_UNUSED) {
1789 g_print ("%3x [%7s] %s %d ",
1790 i * _WAPI_HANDLE_INITIAL_COUNT + k,
1791 _wapi_handle_typename[handle_data->type],
1792 handle_data->signalled?"Sg":"Un",
1794 handle_details[handle_data->type](&handle_data->u);
1799 thr_ret = mono_mutex_unlock (&scan_mutex);
1800 g_assert (thr_ret == 0);
1801 pthread_cleanup_pop (0);
1804 static void _wapi_shared_details (gpointer handle_info)
1806 struct _WapiHandle_shared_ref *shared = (struct _WapiHandle_shared_ref *)handle_info;
1808 g_print ("offset: 0x%x", shared->offset);
1811 void _wapi_handle_update_refs (void)
1815 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
1817 thr_ret = _wapi_handle_lock_shared_handles ();
1818 g_assert (thr_ret == 0);
1820 /* Prevent file share entries racing with us */
1821 thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1822 g_assert(thr_ret == 0);
1824 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
1825 (void *)&scan_mutex);
1826 thr_ret = mono_mutex_lock (&scan_mutex);
1828 for(i = SLOT_INDEX (0); _wapi_private_handles [i] != NULL; i++) {
1829 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
1830 struct _WapiHandleUnshared *handle = &_wapi_private_handles [i][k];
1832 if (_WAPI_SHARED_HANDLE(handle->type)) {
1833 struct _WapiHandleShared *shared_data;
1836 g_message ("%s: (%d) handle 0x%x is SHARED (%s)", __func__, _wapi_getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k, _wapi_handle_typename[handle->type]);
1839 shared_data = &_wapi_shared_layout->handles[handle->u.shared.offset];
1842 g_message ("%s: (%d) Updating timestamp of handle 0x%x", __func__, _wapi_getpid (), handle->u.shared.offset);
1845 InterlockedExchange ((gint32 *)&shared_data->timestamp, now);
1846 } else if (handle->type == WAPI_HANDLE_FILE) {
1847 struct _WapiHandle_file *file_handle = &handle->u.file;
1850 g_message ("%s: (%d) handle 0x%x is FILE", __func__, _wapi_getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k);
1853 g_assert (file_handle->share_info != NULL);
1856 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));
1859 InterlockedExchange ((gint32 *)&file_handle->share_info->timestamp, now);
1864 thr_ret = mono_mutex_unlock (&scan_mutex);
1865 g_assert (thr_ret == 0);
1866 pthread_cleanup_pop (0);
1868 thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1870 _wapi_handle_unlock_shared_handles ();