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 #ifdef HAVE_SYS_SOCKET_H
18 # include <sys/socket.h>
23 #ifdef HAVE_SYS_MMAN_H
24 # include <sys/mman.h>
31 #include <mono/io-layer/wapi.h>
32 #include <mono/io-layer/wapi-private.h>
33 #include <mono/io-layer/handles-private.h>
34 #include <mono/io-layer/mono-mutex.h>
35 #include <mono/io-layer/misc-private.h>
36 #include <mono/io-layer/shared.h>
37 #include <mono/io-layer/collection.h>
38 #include <mono/io-layer/process-private.h>
39 #include <mono/io-layer/critical-section-private.h>
44 static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer);
46 static WapiHandleCapability handle_caps[WAPI_HANDLE_COUNT]={0};
47 static struct _WapiHandleOps *handle_ops[WAPI_HANDLE_COUNT]={
55 #ifndef DISABLE_SOCKETS
61 &_wapi_namedmutex_ops,
63 &_wapi_namedevent_ops,
66 static void _wapi_shared_details (gpointer handle_info);
68 static void (*handle_details[WAPI_HANDLE_COUNT])(gpointer) = {
71 _wapi_console_details,
72 _wapi_shared_details, /* thread */
76 NULL, /* Nothing useful to see in a socket handle */
77 NULL, /* Nothing useful to see in a find handle */
78 _wapi_shared_details, /* process */
80 _wapi_shared_details, /* namedmutex */
81 _wapi_shared_details, /* namedsem */
82 _wapi_shared_details, /* namedevent */
85 const char *_wapi_handle_typename[] = {
104 * We can hold _WAPI_PRIVATE_MAX_SLOTS * _WAPI_HANDLE_INITIAL_COUNT handles.
105 * If 4M handles are not enough... Oh, well... we will crash.
107 #define SLOT_INDEX(x) (x / _WAPI_HANDLE_INITIAL_COUNT)
108 #define SLOT_OFFSET(x) (x % _WAPI_HANDLE_INITIAL_COUNT)
110 struct _WapiHandleUnshared *_wapi_private_handles [_WAPI_PRIVATE_MAX_SLOTS];
111 static guint32 _wapi_private_handle_count = 0;
112 static guint32 _wapi_private_handle_slot_count = 0;
114 struct _WapiHandleSharedLayout *_wapi_shared_layout = NULL;
115 struct _WapiFileShareLayout *_wapi_fileshare_layout = NULL;
117 guint32 _wapi_fd_reserve;
120 * This is an internal handle which is used for handling waiting for multiple handles.
121 * Threads which wait for multiple handles wait on this one handle, and when a handle
122 * is signalled, this handle is signalled too.
124 static gpointer _wapi_global_signal_handle;
126 /* Point to the mutex/cond inside _wapi_global_signal_handle */
127 mono_mutex_t *_wapi_global_signal_mutex;
128 pthread_cond_t *_wapi_global_signal_cond;
131 gboolean _wapi_has_shut_down = FALSE;
133 /* Use this instead of getpid(), to cope with linuxthreads. It's a
134 * function rather than a variable lookup because we need to get at
135 * this before share_init() might have been called.
137 static pid_t _wapi_pid;
138 static mono_once_t pid_init_once = MONO_ONCE_INIT;
140 static gpointer _wapi_handle_real_new (WapiHandleType type, gpointer handle_specific);
142 static void pid_init (void)
144 _wapi_pid = getpid ();
147 pid_t _wapi_getpid (void)
149 mono_once (&pid_init_once, pid_init);
155 static mono_mutex_t scan_mutex = MONO_MUTEX_INITIALIZER;
157 static void handle_cleanup (void)
161 _wapi_process_signal_self ();
163 /* Every shared handle we were using ought really to be closed
164 * by now, but to make sure just blow them all away. The
165 * exiting finalizer thread in particular races us to the
166 * program exit and doesn't always win, so it can be left
167 * cluttering up the shared file. Anything else left over is
170 for(i = SLOT_INDEX (0); _wapi_private_handles[i] != NULL; i++) {
171 for(j = SLOT_OFFSET (0); j < _WAPI_HANDLE_INITIAL_COUNT; j++) {
172 struct _WapiHandleUnshared *handle_data = &_wapi_private_handles[i][j];
173 int type = handle_data->type;
176 if (_WAPI_SHARED_HANDLE (type)) {
177 gpointer handle = GINT_TO_POINTER (i*_WAPI_HANDLE_INITIAL_COUNT+j);
179 if (type == WAPI_HANDLE_THREAD) {
180 /* Special-case thread handles
181 * because they need extra
182 * cleanup. This also avoids
183 * a race condition between
184 * the application exit and
185 * the finalizer thread - if
186 * it finishes up between now
187 * and actual app termination
188 * it will find all its handle
189 * details have been blown
190 * away, so this sets those
193 _wapi_thread_set_termination_details (handle, 0);
196 for(k = handle_data->ref; k > 0; k--) {
198 g_message ("%s: unreffing %s handle %p", __func__, _wapi_handle_typename[type], handle);
201 _wapi_handle_unref (handle);
207 _wapi_shm_semaphores_remove ();
210 void _wapi_cleanup ()
212 g_assert (_wapi_has_shut_down == FALSE);
214 _wapi_has_shut_down = TRUE;
216 _wapi_critical_section_cleanup ();
217 _wapi_error_cleanup ();
218 _wapi_thread_cleanup ();
221 static mono_once_t shared_init_once = MONO_ONCE_INIT;
222 static void shared_init (void)
224 g_assert ((sizeof (handle_ops) / sizeof (handle_ops[0]))
225 == WAPI_HANDLE_COUNT);
227 _wapi_fd_reserve = getdtablesize();
229 /* This is needed by the code in _wapi_handle_new_internal */
230 _wapi_fd_reserve = (_wapi_fd_reserve + (_WAPI_HANDLE_INITIAL_COUNT - 1)) & ~(_WAPI_HANDLE_INITIAL_COUNT - 1);
234 * The entries in _wapi_private_handles reserved for fds are allocated lazily to
238 _wapi_private_handles [idx++] = g_new0 (struct _WapiHandleUnshared,
239 _WAPI_HANDLE_INITIAL_COUNT);
242 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
243 _wapi_private_handle_slot_count ++;
244 } while(_wapi_fd_reserve > _wapi_private_handle_count);
246 _wapi_shm_semaphores_init ();
248 _wapi_shared_layout = _wapi_shm_attach (WAPI_SHM_DATA);
249 g_assert (_wapi_shared_layout != NULL);
251 _wapi_fileshare_layout = _wapi_shm_attach (WAPI_SHM_FILESHARE);
252 g_assert (_wapi_fileshare_layout != NULL);
254 #if !defined (DISABLE_SHARED_HANDLES)
255 if (!g_getenv ("MONO_DISABLE_SHM"))
256 _wapi_collection_init ();
259 /* Can't call wapi_handle_new as it calls us recursively */
260 _wapi_global_signal_handle = _wapi_handle_real_new (WAPI_HANDLE_EVENT, NULL);
262 _wapi_global_signal_cond = &_WAPI_PRIVATE_HANDLES (GPOINTER_TO_UINT (_wapi_global_signal_handle)).signal_cond;
263 _wapi_global_signal_mutex = &_WAPI_PRIVATE_HANDLES (GPOINTER_TO_UINT (_wapi_global_signal_handle)).signal_mutex;
265 /* Using g_atexit here instead of an explicit function call in
266 * a cleanup routine lets us cope when a third-party library
267 * calls exit (eg if an X client loses the connection to its
270 g_atexit (handle_cleanup);
273 static void _wapi_handle_init_shared (struct _WapiHandleShared *handle,
275 gpointer handle_specific)
277 g_assert (_wapi_has_shut_down == FALSE);
280 handle->timestamp = (guint32)(time (NULL) & 0xFFFFFFFF);
281 handle->signalled = FALSE;
282 handle->handle_refs = 1;
284 if (handle_specific != NULL) {
285 memcpy (&handle->u, handle_specific, sizeof (handle->u));
289 static void _wapi_handle_init (struct _WapiHandleUnshared *handle,
290 WapiHandleType type, gpointer handle_specific)
294 g_assert (_wapi_has_shut_down == FALSE);
297 handle->signalled = FALSE;
300 if (!_WAPI_SHARED_HANDLE(type)) {
301 thr_ret = pthread_cond_init (&handle->signal_cond, NULL);
302 g_assert (thr_ret == 0);
304 thr_ret = mono_mutex_init (&handle->signal_mutex, NULL);
305 g_assert (thr_ret == 0);
307 if (handle_specific != NULL) {
308 memcpy (&handle->u, handle_specific,
314 static guint32 _wapi_handle_new_shared (WapiHandleType type,
315 gpointer handle_specific)
318 static guint32 last = 1;
321 g_assert (_wapi_has_shut_down == FALSE);
323 /* Leave the first slot empty as a guard */
325 /* FIXME: expandable array */
326 for(offset = last; offset <_WAPI_HANDLE_INITIAL_COUNT; offset++) {
327 struct _WapiHandleShared *handle = &_wapi_shared_layout->handles[offset];
329 if(handle->type == WAPI_HANDLE_UNUSED) {
330 thr_ret = _wapi_handle_lock_shared_handles ();
331 g_assert (thr_ret == 0);
333 if (InterlockedCompareExchange ((gint32 *)&handle->type, type, WAPI_HANDLE_UNUSED) == WAPI_HANDLE_UNUSED) {
336 _wapi_handle_init_shared (handle, type,
339 _wapi_handle_unlock_shared_handles ();
343 /* Someone else beat us to it, just
348 _wapi_handle_unlock_shared_handles ();
353 /* Try again from the beginning */
358 /* Will need to expand the array. The caller will sort it out */
364 * _wapi_handle_new_internal:
365 * @type: Init handle to this type
367 * Search for a free handle and initialize it. Return the handle on
368 * success and 0 on failure. This is only called from
369 * _wapi_handle_new, and scan_mutex must be held.
371 static guint32 _wapi_handle_new_internal (WapiHandleType type,
372 gpointer handle_specific)
375 static guint32 last = 0;
376 gboolean retry = FALSE;
378 g_assert (_wapi_has_shut_down == FALSE);
380 /* A linear scan should be fast enough. Start from the last
381 * allocation, assuming that handles are allocated more often
382 * than they're freed. Leave the space reserved for file
386 if (last < _wapi_fd_reserve) {
387 last = _wapi_fd_reserve;
394 for(i = SLOT_INDEX (count); i < _wapi_private_handle_slot_count; i++) {
395 if (_wapi_private_handles [i]) {
396 for (k = SLOT_OFFSET (count); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
397 struct _WapiHandleUnshared *handle = &_wapi_private_handles [i][k];
399 if(handle->type == WAPI_HANDLE_UNUSED) {
402 _wapi_handle_init (handle, type, handle_specific);
410 if(retry && last > _wapi_fd_reserve) {
411 /* Try again from the beginning */
412 last = _wapi_fd_reserve;
416 /* Will need to expand the array. The caller will sort it out */
421 static gpointer _wapi_handle_real_new (WapiHandleType type, gpointer handle_specific)
423 guint32 handle_idx = 0;
428 g_message ("%s: Creating new handle of type %s", __func__,
429 _wapi_handle_typename[type]);
432 g_assert(!_WAPI_FD_HANDLE(type));
434 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
435 (void *)&scan_mutex);
436 thr_ret = mono_mutex_lock (&scan_mutex);
437 g_assert (thr_ret == 0);
439 while ((handle_idx = _wapi_handle_new_internal (type, handle_specific)) == 0) {
440 /* Try and expand the array, and have another go */
441 int idx = SLOT_INDEX (_wapi_private_handle_count);
442 if (idx >= _WAPI_PRIVATE_MAX_SLOTS) {
446 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
447 _WAPI_HANDLE_INITIAL_COUNT);
449 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
450 _wapi_private_handle_slot_count ++;
453 thr_ret = mono_mutex_unlock (&scan_mutex);
454 g_assert (thr_ret == 0);
455 pthread_cleanup_pop (0);
457 if (handle_idx == 0) {
458 /* We ran out of slots */
459 handle = _WAPI_HANDLE_INVALID;
463 /* Make sure we left the space for fd mappings */
464 g_assert (handle_idx >= _wapi_fd_reserve);
466 handle = GUINT_TO_POINTER (handle_idx);
469 g_message ("%s: Allocated new handle %p", __func__, handle);
472 if (_WAPI_SHARED_HANDLE(type)) {
473 /* Add the shared section too */
476 ref = _wapi_handle_new_shared (type, handle_specific);
478 _wapi_handle_collect ();
479 _wapi_process_reap ();
480 ref = _wapi_handle_new_shared (type, handle_specific);
482 /* FIXME: grow the arrays */
483 handle = _WAPI_HANDLE_INVALID;
488 _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = ref;
490 g_message ("%s: New shared handle at offset 0x%x", __func__,
499 gpointer _wapi_handle_new (WapiHandleType type, gpointer handle_specific)
501 g_assert (_wapi_has_shut_down == FALSE);
503 mono_once (&shared_init_once, shared_init);
505 return _wapi_handle_real_new (type, handle_specific);
508 gpointer _wapi_handle_new_from_offset (WapiHandleType type, guint32 offset,
511 guint32 handle_idx = 0;
512 gpointer handle = INVALID_HANDLE_VALUE;
514 struct _WapiHandleShared *shared;
515 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
517 g_assert (_wapi_has_shut_down == FALSE);
519 mono_once (&shared_init_once, shared_init);
522 g_message ("%s: Creating new handle of type %s to offset %d", __func__,
523 _wapi_handle_typename[type], offset);
526 g_assert(!_WAPI_FD_HANDLE(type));
527 g_assert(_WAPI_SHARED_HANDLE(type));
528 g_assert(offset != 0);
530 shared = &_wapi_shared_layout->handles[offset];
532 /* Bump up the timestamp for this offset */
533 InterlockedExchange ((gint32 *)&shared->timestamp, now);
536 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
537 (void *)&scan_mutex);
538 thr_ret = mono_mutex_lock (&scan_mutex);
539 g_assert (thr_ret == 0);
541 for (i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
542 if (_wapi_private_handles [i]) {
543 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
544 struct _WapiHandleUnshared *handle_data = &_wapi_private_handles [i][k];
546 if (handle_data->type == type &&
547 handle_data->u.shared.offset == offset) {
548 handle = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
549 goto first_pass_done;
556 thr_ret = mono_mutex_unlock (&scan_mutex);
557 g_assert (thr_ret == 0);
558 pthread_cleanup_pop (0);
560 if (handle != INVALID_HANDLE_VALUE) {
561 _wapi_handle_ref (handle);
564 g_message ("%s: Returning old handle %p referencing 0x%x",
565 __func__, handle, offset);
570 /* Prevent entries expiring under us as we search */
571 thr_ret = _wapi_handle_lock_shared_handles ();
572 g_assert (thr_ret == 0);
574 if (shared->type == WAPI_HANDLE_UNUSED) {
575 /* Someone deleted this handle while we were working */
577 g_message ("%s: Handle at 0x%x unused", __func__, offset);
582 if (shared->type != type) {
584 g_message ("%s: Wrong type at %d 0x%x! Found %s wanted %s",
585 __func__, offset, offset,
586 _wapi_handle_typename[shared->type],
587 _wapi_handle_typename[type]);
592 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
593 (void *)&scan_mutex);
594 thr_ret = mono_mutex_lock (&scan_mutex);
595 g_assert (thr_ret == 0);
597 while ((handle_idx = _wapi_handle_new_internal (type, NULL)) == 0) {
598 /* Try and expand the array, and have another go */
599 int idx = SLOT_INDEX (_wapi_private_handle_count);
600 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
601 _WAPI_HANDLE_INITIAL_COUNT);
603 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
604 _wapi_private_handle_slot_count ++;
607 thr_ret = mono_mutex_unlock (&scan_mutex);
608 g_assert (thr_ret == 0);
609 pthread_cleanup_pop (0);
611 /* Make sure we left the space for fd mappings */
612 g_assert (handle_idx >= _wapi_fd_reserve);
614 handle = GUINT_TO_POINTER (handle_idx);
616 _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = offset;
617 InterlockedIncrement ((gint32 *)&shared->handle_refs);
620 g_message ("%s: Allocated new handle %p referencing 0x%x (shared refs %d)", __func__, handle, offset, shared->handle_refs);
624 _wapi_handle_unlock_shared_handles ();
630 init_handles_slot (int idx)
634 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
635 (void *)&scan_mutex);
636 thr_ret = mono_mutex_lock (&scan_mutex);
637 g_assert (thr_ret == 0);
639 if (_wapi_private_handles [idx] == NULL) {
640 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
641 _WAPI_HANDLE_INITIAL_COUNT);
642 g_assert (_wapi_private_handles [idx]);
645 thr_ret = mono_mutex_unlock (&scan_mutex);
646 g_assert (thr_ret == 0);
647 pthread_cleanup_pop (0);
650 gpointer _wapi_handle_new_fd (WapiHandleType type, int fd,
651 gpointer handle_specific)
653 struct _WapiHandleUnshared *handle;
656 g_assert (_wapi_has_shut_down == FALSE);
658 mono_once (&shared_init_once, shared_init);
661 g_message ("%s: Creating new handle of type %s", __func__,
662 _wapi_handle_typename[type]);
665 g_assert(_WAPI_FD_HANDLE(type));
666 g_assert(!_WAPI_SHARED_HANDLE(type));
668 if (fd >= _wapi_fd_reserve) {
670 g_message ("%s: fd %d is too big", __func__, fd);
673 return(GUINT_TO_POINTER (_WAPI_HANDLE_INVALID));
676 /* Initialize the array entries on demand */
677 if (_wapi_private_handles [SLOT_INDEX (fd)] == NULL)
678 init_handles_slot (SLOT_INDEX (fd));
680 handle = &_WAPI_PRIVATE_HANDLES(fd);
682 if (handle->type != WAPI_HANDLE_UNUSED) {
684 g_message ("%s: fd %d is already in use!", __func__, fd);
686 /* FIXME: clean up this handle? We can't do anything
687 * with the fd, cos thats the new one
692 g_message ("%s: Assigning new fd handle %d", __func__, fd);
695 /* Prevent file share entries racing with us, when the file
696 * handle is only half initialised
698 thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
699 g_assert(thr_ret == 0);
701 _wapi_handle_init (handle, type, handle_specific);
703 thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
705 return(GUINT_TO_POINTER(fd));
708 gboolean _wapi_lookup_handle (gpointer handle, WapiHandleType type,
709 gpointer *handle_specific)
711 struct _WapiHandleUnshared *handle_data;
712 guint32 handle_idx = GPOINTER_TO_UINT(handle);
714 if (!_WAPI_PRIVATE_VALID_SLOT (handle_idx)) {
718 /* Initialize the array entries on demand */
719 if (_wapi_private_handles [SLOT_INDEX (handle_idx)] == NULL)
720 init_handles_slot (SLOT_INDEX (handle_idx));
722 handle_data = &_WAPI_PRIVATE_HANDLES(handle_idx);
724 if (handle_data->type != type) {
728 if (handle_specific == NULL) {
732 if (_WAPI_SHARED_HANDLE(type)) {
733 struct _WapiHandle_shared_ref *ref;
734 struct _WapiHandleShared *shared_handle_data;
736 ref = &handle_data->u.shared;
737 shared_handle_data = &_wapi_shared_layout->handles[ref->offset];
739 if (shared_handle_data->type != type) {
740 /* The handle must have been deleted on us
745 *handle_specific = &shared_handle_data->u;
747 *handle_specific = &handle_data->u;
754 _wapi_handle_foreach (WapiHandleType type,
755 gboolean (*on_each)(gpointer test, gpointer user),
758 struct _WapiHandleUnshared *handle_data = NULL;
763 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
764 (void *)&scan_mutex);
765 thr_ret = mono_mutex_lock (&scan_mutex);
766 g_assert (thr_ret == 0);
768 for (i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
769 if (_wapi_private_handles [i]) {
770 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
771 handle_data = &_wapi_private_handles [i][k];
773 if (handle_data->type == type) {
774 ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
775 if (on_each (ret, user_data) == TRUE)
782 thr_ret = mono_mutex_unlock (&scan_mutex);
783 g_assert (thr_ret == 0);
784 pthread_cleanup_pop (0);
787 /* This might list some shared handles twice if they are already
788 * opened by this process, and the check function returns FALSE the
789 * first time. Shared handles that are created during the search are
790 * unreffed if the check function returns FALSE, so callers must not
791 * rely on the handle persisting (unless the check function returns
794 gpointer _wapi_search_handle (WapiHandleType type,
795 gboolean (*check)(gpointer test, gpointer user),
797 gpointer *handle_specific,
798 gboolean search_shared)
800 struct _WapiHandleUnshared *handle_data = NULL;
801 struct _WapiHandleShared *shared = NULL;
804 gboolean found = FALSE;
807 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
808 (void *)&scan_mutex);
809 thr_ret = mono_mutex_lock (&scan_mutex);
810 g_assert (thr_ret == 0);
812 for (i = SLOT_INDEX (0); !found && i < _wapi_private_handle_slot_count; i++) {
813 if (_wapi_private_handles [i]) {
814 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
815 handle_data = &_wapi_private_handles [i][k];
817 if (handle_data->type == type) {
818 ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
819 if (check (ret, user_data) == TRUE) {
820 _wapi_handle_ref (ret);
823 if (_WAPI_SHARED_HANDLE (type)) {
824 shared = &_wapi_shared_layout->handles[i];
834 thr_ret = mono_mutex_unlock (&scan_mutex);
835 g_assert (thr_ret == 0);
836 pthread_cleanup_pop (0);
838 if (!found && search_shared && _WAPI_SHARED_HANDLE (type)) {
839 /* Not found yet, so search the shared memory too */
841 g_message ("%s: Looking at other shared handles...", __func__);
844 for (i = 0; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
845 shared = &_wapi_shared_layout->handles[i];
847 if (shared->type == type) {
848 /* Tell new_from_offset to not
849 * timestamp this handle, because
850 * otherwise it will ping every handle
851 * in the list and they will never
854 ret = _wapi_handle_new_from_offset (type, i,
856 if (ret == INVALID_HANDLE_VALUE) {
857 /* This handle was deleted
858 * while we were looking at it
864 g_message ("%s: Opened tmp handle %p (type %s) from offset %d", __func__, ret, _wapi_handle_typename[type], i);
867 /* It's possible that the shared part
868 * of this handle has now been blown
869 * away (after new_from_offset
870 * successfully opened it,) if its
871 * timestamp is too old. The check
872 * function needs to be aware of this,
873 * and cope if the handle has
876 if (check (ret, user_data) == TRUE) {
877 /* Timestamp this handle, but make
878 * sure it still exists first
880 thr_ret = _wapi_handle_lock_shared_handles ();
881 g_assert (thr_ret == 0);
883 if (shared->type == type) {
884 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
885 InterlockedExchange ((gint32 *)&shared->timestamp, now);
888 handle_data = &_WAPI_PRIVATE_HANDLES(GPOINTER_TO_UINT(ret));
890 _wapi_handle_unlock_shared_handles ();
893 /* It's been deleted,
897 _wapi_handle_unlock_shared_handles ();
901 /* This isn't the handle we're looking
902 * for, so drop the reference we took
903 * in _wapi_handle_new_from_offset ()
905 _wapi_handle_unref (ret);
915 if(handle_specific != NULL) {
916 if (_WAPI_SHARED_HANDLE(type)) {
917 g_assert(shared->type == type);
919 *handle_specific = &shared->u;
921 *handle_specific = &handle_data->u;
929 /* Returns the offset of the metadata array, or -1 on error, or 0 for
930 * not found (0 is not a valid offset)
932 gint32 _wapi_search_handle_namespace (WapiHandleType type,
935 struct _WapiHandleShared *shared_handle_data;
940 g_assert(_WAPI_SHARED_HANDLE(type));
943 g_message ("%s: Lookup for handle named [%s] type %s", __func__,
944 utf8_name, _wapi_handle_typename[type]);
947 /* Do a handle collection before starting to look, so that any
948 * stale cruft gets removed
950 _wapi_handle_collect ();
952 thr_ret = _wapi_handle_lock_shared_handles ();
953 g_assert (thr_ret == 0);
955 for(i = 1; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
956 WapiSharedNamespace *sharedns;
958 shared_handle_data = &_wapi_shared_layout->handles[i];
960 /* Check mutex, event, semaphore, timer, job and
961 * file-mapping object names. So far only mutex,
962 * semaphore and event are implemented.
964 if (!_WAPI_SHARED_NAMESPACE (shared_handle_data->type)) {
969 g_message ("%s: found a shared namespace handle at 0x%x (type %s)", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
972 sharedns=(WapiSharedNamespace *)&shared_handle_data->u;
975 g_message ("%s: name is [%s]", __func__, sharedns->name);
978 if (strcmp (sharedns->name, utf8_name) == 0) {
979 if (shared_handle_data->type != type) {
980 /* Its the wrong type, so fail now */
982 g_message ("%s: handle 0x%x matches name but is wrong type: %s", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
988 g_message ("%s: handle 0x%x matches name and type", __func__, i);
997 _wapi_handle_unlock_shared_handles ();
1002 void _wapi_handle_ref (gpointer handle)
1004 guint32 idx = GPOINTER_TO_UINT(handle);
1005 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
1006 struct _WapiHandleUnshared *handle_data;
1008 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1012 if (_wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) {
1013 g_warning ("%s: Attempting to ref unused handle %p", __func__,
1018 handle_data = &_WAPI_PRIVATE_HANDLES(idx);
1020 InterlockedIncrement ((gint32 *)&handle_data->ref);
1022 /* It's possible for processes to exit before getting around
1023 * to updating timestamps in the collection thread, so if a
1024 * shared handle is reffed do the timestamp here as well just
1027 if (_WAPI_SHARED_HANDLE(handle_data->type)) {
1028 struct _WapiHandleShared *shared_data = &_wapi_shared_layout->handles[handle_data->u.shared.offset];
1030 InterlockedExchange ((gint32 *)&shared_data->timestamp, now);
1034 g_message ("%s: %s handle %p ref now %d", __func__,
1035 _wapi_handle_typename[_WAPI_PRIVATE_HANDLES (idx).type],
1037 _WAPI_PRIVATE_HANDLES(idx).ref);
1041 /* The handle must not be locked on entry to this function */
1042 void _wapi_handle_unref (gpointer handle)
1044 guint32 idx = GPOINTER_TO_UINT(handle);
1045 gboolean destroy = FALSE;
1048 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1052 if (_wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) {
1053 g_warning ("%s: Attempting to unref unused handle %p",
1058 /* Possible race condition here if another thread refs the
1059 * handle between here and setting the type to UNUSED. I
1060 * could lock a mutex, but I'm not sure that allowing a handle
1061 * reference to reach 0 isn't an application bug anyway.
1063 destroy = (InterlockedDecrement ((gint32 *)&_WAPI_PRIVATE_HANDLES(idx).ref) ==0);
1066 g_message ("%s: %s handle %p ref now %d (destroy %s)", __func__,
1067 _wapi_handle_typename[_WAPI_PRIVATE_HANDLES (idx).type],
1069 _WAPI_PRIVATE_HANDLES(idx).ref, destroy?"TRUE":"FALSE");
1073 /* Need to copy the handle info, reset the slot in the
1074 * array, and _only then_ call the close function to
1075 * avoid race conditions (eg file descriptors being
1076 * closed, and another file being opened getting the
1077 * same fd racing the memset())
1079 struct _WapiHandleUnshared handle_data;
1080 struct _WapiHandleShared shared_handle_data;
1081 WapiHandleType type = _WAPI_PRIVATE_HANDLES(idx).type;
1082 void (*close_func)(gpointer, gpointer) = _wapi_handle_ops_get_close_func (type);
1083 gboolean is_shared = _WAPI_SHARED_HANDLE(type);
1086 /* If this is a shared handle we need to take
1087 * the shared lock outside of the scan_mutex
1088 * lock to avoid deadlocks
1090 thr_ret = _wapi_handle_lock_shared_handles ();
1091 g_assert (thr_ret == 0);
1094 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup, (void *)&scan_mutex);
1095 thr_ret = mono_mutex_lock (&scan_mutex);
1098 g_message ("%s: Destroying handle %p", __func__, handle);
1101 memcpy (&handle_data, &_WAPI_PRIVATE_HANDLES(idx),
1102 sizeof (struct _WapiHandleUnshared));
1104 memset (&_WAPI_PRIVATE_HANDLES(idx).u, '\0',
1105 sizeof(_WAPI_PRIVATE_HANDLES(idx).u));
1107 _WAPI_PRIVATE_HANDLES(idx).type = WAPI_HANDLE_UNUSED;
1110 /* Destroy the mutex and cond var. We hope nobody
1111 * tried to grab them between the handle unlock and
1112 * now, but pthreads doesn't have a
1113 * "unlock_and_destroy" atomic function.
1115 thr_ret = mono_mutex_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_mutex);
1116 g_assert (thr_ret == 0);
1118 thr_ret = pthread_cond_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_cond);
1119 g_assert (thr_ret == 0);
1121 struct _WapiHandleShared *shared = &_wapi_shared_layout->handles[handle_data.u.shared.offset];
1123 memcpy (&shared_handle_data, shared,
1124 sizeof (struct _WapiHandleShared));
1126 /* It's possible that this handle is already
1127 * pointing at a deleted shared section
1130 g_message ("%s: %s handle %p shared refs before dec %d", __func__, _wapi_handle_typename[type], handle, shared->handle_refs);
1133 if (shared->handle_refs > 0) {
1134 shared->handle_refs--;
1135 if (shared->handle_refs == 0) {
1136 memset (shared, '\0', sizeof (struct _WapiHandleShared));
1141 thr_ret = mono_mutex_unlock (&scan_mutex);
1142 g_assert (thr_ret == 0);
1143 pthread_cleanup_pop (0);
1146 _wapi_handle_unlock_shared_handles ();
1149 if (close_func != NULL) {
1151 close_func (handle, &shared_handle_data.u);
1153 close_func (handle, &handle_data.u);
1159 void _wapi_handle_register_capabilities (WapiHandleType type,
1160 WapiHandleCapability caps)
1162 handle_caps[type] = caps;
1165 gboolean _wapi_handle_test_capabilities (gpointer handle,
1166 WapiHandleCapability caps)
1168 guint32 idx = GPOINTER_TO_UINT(handle);
1169 WapiHandleType type;
1171 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1175 type = _WAPI_PRIVATE_HANDLES(idx).type;
1178 g_message ("%s: testing 0x%x against 0x%x (%d)", __func__,
1179 handle_caps[type], caps, handle_caps[type] & caps);
1182 return((handle_caps[type] & caps) != 0);
1185 static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer)
1187 if (handle_ops[type] != NULL &&
1188 handle_ops[type]->close != NULL) {
1189 return (handle_ops[type]->close);
1195 void _wapi_handle_ops_close (gpointer handle, gpointer data)
1197 guint32 idx = GPOINTER_TO_UINT(handle);
1198 WapiHandleType type;
1200 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1204 type = _WAPI_PRIVATE_HANDLES(idx).type;
1206 if (handle_ops[type] != NULL &&
1207 handle_ops[type]->close != NULL) {
1208 handle_ops[type]->close (handle, data);
1212 void _wapi_handle_ops_signal (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 && handle_ops[type]->signal != NULL) {
1224 handle_ops[type]->signal (handle);
1228 gboolean _wapi_handle_ops_own (gpointer handle)
1230 guint32 idx = GPOINTER_TO_UINT(handle);
1231 WapiHandleType type;
1233 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1237 type = _WAPI_PRIVATE_HANDLES(idx).type;
1239 if (handle_ops[type] != NULL && handle_ops[type]->own_handle != NULL) {
1240 return(handle_ops[type]->own_handle (handle));
1246 gboolean _wapi_handle_ops_isowned (gpointer handle)
1248 guint32 idx = GPOINTER_TO_UINT(handle);
1249 WapiHandleType type;
1251 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1255 type = _WAPI_PRIVATE_HANDLES(idx).type;
1257 if (handle_ops[type] != NULL && handle_ops[type]->is_owned != NULL) {
1258 return(handle_ops[type]->is_owned (handle));
1264 guint32 _wapi_handle_ops_special_wait (gpointer handle, guint32 timeout)
1266 guint32 idx = GPOINTER_TO_UINT(handle);
1267 WapiHandleType type;
1269 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1270 return(WAIT_FAILED);
1273 type = _WAPI_PRIVATE_HANDLES(idx).type;
1275 if (handle_ops[type] != NULL &&
1276 handle_ops[type]->special_wait != NULL) {
1277 return(handle_ops[type]->special_wait (handle, timeout));
1279 return(WAIT_FAILED);
1283 void _wapi_handle_ops_prewait (gpointer handle)
1285 guint32 idx = GPOINTER_TO_UINT (handle);
1286 WapiHandleType type;
1288 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1292 type = _WAPI_PRIVATE_HANDLES (idx).type;
1294 if (handle_ops[type] != NULL &&
1295 handle_ops[type]->prewait != NULL) {
1296 handle_ops[type]->prewait (handle);
1303 * @handle: The handle to release
1305 * Closes and invalidates @handle, releasing any resources it
1306 * consumes. When the last handle to a temporary or non-persistent
1307 * object is closed, that object can be deleted. Closing the same
1308 * handle twice is an error.
1310 * Return value: %TRUE on success, %FALSE otherwise.
1312 gboolean CloseHandle(gpointer handle)
1314 if (handle == NULL) {
1315 /* Problem: because we map file descriptors to the
1316 * same-numbered handle we can't tell the difference
1317 * between a bogus handle and the handle to stdin.
1318 * Assume that it's the console handle if that handle
1321 if (_WAPI_PRIVATE_HANDLES (0).type != WAPI_HANDLE_CONSOLE) {
1322 SetLastError (ERROR_INVALID_PARAMETER);
1326 if (handle == _WAPI_HANDLE_INVALID){
1327 SetLastError (ERROR_INVALID_PARAMETER);
1331 _wapi_handle_unref (handle);
1336 /* Lots more to implement here, but this is all we need at the moment */
1337 gboolean DuplicateHandle (gpointer srcprocess, gpointer src,
1338 gpointer targetprocess, gpointer *target,
1339 guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, guint32 options G_GNUC_UNUSED)
1341 if (srcprocess != _WAPI_PROCESS_CURRENT ||
1342 targetprocess != _WAPI_PROCESS_CURRENT) {
1343 /* Duplicating other process's handles is not supported */
1344 SetLastError (ERROR_INVALID_HANDLE);
1348 if (src == _WAPI_PROCESS_CURRENT) {
1349 *target = _wapi_process_duplicate ();
1350 } else if (src == _WAPI_THREAD_CURRENT) {
1351 *target = _wapi_thread_duplicate ();
1353 _wapi_handle_ref (src);
1360 gboolean _wapi_handle_count_signalled_handles (guint32 numhandles,
1366 guint32 count, i, iter=0;
1369 WapiHandleType type;
1371 /* Lock all the handles, with backoff */
1373 thr_ret = _wapi_handle_lock_shared_handles ();
1374 g_assert (thr_ret == 0);
1376 for(i=0; i<numhandles; i++) {
1377 gpointer handle = handles[i];
1378 guint32 idx = GPOINTER_TO_UINT(handle);
1381 g_message ("%s: attempting to lock %p", __func__, handle);
1384 type = _WAPI_PRIVATE_HANDLES(idx).type;
1386 thr_ret = _wapi_handle_trylock_handle (handle);
1392 g_message ("%s: attempt failed for %p: %s", __func__,
1393 handle, strerror (thr_ret));
1396 thr_ret = _wapi_handle_unlock_shared_handles ();
1397 g_assert (thr_ret == 0);
1400 handle = handles[i];
1401 idx = GPOINTER_TO_UINT(handle);
1403 thr_ret = _wapi_handle_unlock_handle (handle);
1404 g_assert (thr_ret == 0);
1407 /* If iter ever reaches 100 the nanosleep will
1408 * return EINVAL immediately, but we have a
1409 * design flaw if that happens.
1413 g_warning ("%s: iteration overflow!",
1419 g_message ("%s: Backing off for %d ms", __func__,
1422 _wapi_handle_spin (10 * iter);
1429 g_message ("%s: Locked all handles", __func__);
1435 for(i=0; i<numhandles; i++) {
1436 gpointer handle = handles[i];
1437 guint32 idx = GPOINTER_TO_UINT(handle);
1439 type = _WAPI_PRIVATE_HANDLES(idx).type;
1442 g_message ("%s: Checking handle %p", __func__, handle);
1445 if(((_wapi_handle_test_capabilities (handle, WAPI_HANDLE_CAP_OWN)==TRUE) &&
1446 (_wapi_handle_ops_isowned (handle) == TRUE)) ||
1447 (_WAPI_SHARED_HANDLE(type) &&
1448 WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) ||
1449 (!_WAPI_SHARED_HANDLE(type) &&
1450 _WAPI_PRIVATE_HANDLES(idx).signalled == TRUE)) {
1454 g_message ("%s: Handle %p signalled", __func__,
1464 g_message ("%s: %d event handles signalled", __func__, count);
1467 if ((waitall == TRUE && count == numhandles) ||
1468 (waitall == FALSE && count > 0)) {
1475 g_message ("%s: Returning %d", __func__, ret);
1483 void _wapi_handle_unlock_handles (guint32 numhandles, gpointer *handles)
1488 thr_ret = _wapi_handle_unlock_shared_handles ();
1489 g_assert (thr_ret == 0);
1491 for(i=0; i<numhandles; i++) {
1492 gpointer handle = handles[i];
1495 g_message ("%s: unlocking handle %p", __func__, handle);
1498 thr_ret = _wapi_handle_unlock_handle (handle);
1499 g_assert (thr_ret == 0);
1503 static int timedwait_signal_poll_cond (pthread_cond_t *cond, mono_mutex_t *mutex, struct timespec *timeout, gboolean alertable)
1505 struct timespec fake_timeout;
1510 ret=mono_cond_timedwait (cond, mutex, timeout);
1512 ret=mono_cond_wait (cond, mutex);
1514 _wapi_calc_timeout (&fake_timeout, 100);
1516 if (timeout != NULL && ((fake_timeout.tv_sec > timeout->tv_sec) ||
1517 (fake_timeout.tv_sec == timeout->tv_sec &&
1518 fake_timeout.tv_nsec > timeout->tv_nsec))) {
1519 /* Real timeout is less than 100ms time */
1520 ret=mono_cond_timedwait (cond, mutex, timeout);
1522 ret=mono_cond_timedwait (cond, mutex, &fake_timeout);
1524 /* Mask the fake timeout, this will cause
1525 * another poll if the cond was not really signaled
1527 if (ret==ETIMEDOUT) {
1536 int _wapi_handle_wait_signal (gboolean poll)
1538 return _wapi_handle_timedwait_signal_handle (_wapi_global_signal_handle, NULL, TRUE, poll);
1541 int _wapi_handle_timedwait_signal (struct timespec *timeout, gboolean poll)
1543 return _wapi_handle_timedwait_signal_handle (_wapi_global_signal_handle, timeout, TRUE, poll);
1546 int _wapi_handle_wait_signal_handle (gpointer handle, gboolean alertable)
1549 g_message ("%s: waiting for %p", __func__, handle);
1552 return _wapi_handle_timedwait_signal_handle (handle, NULL, alertable, FALSE);
1555 int _wapi_handle_timedwait_signal_handle (gpointer handle,
1556 struct timespec *timeout, gboolean alertable, gboolean poll)
1559 g_message ("%s: waiting for %p (type %s)", __func__, handle,
1560 _wapi_handle_typename[_wapi_handle_type (handle)]);
1563 if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
1564 if (WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) {
1567 if (timeout != NULL) {
1568 struct timespec fake_timeout;
1569 _wapi_calc_timeout (&fake_timeout, 100);
1571 if ((fake_timeout.tv_sec > timeout->tv_sec) ||
1572 (fake_timeout.tv_sec == timeout->tv_sec &&
1573 fake_timeout.tv_nsec > timeout->tv_nsec)) {
1574 /* FIXME: Real timeout is less than
1575 * 100ms time, but is it really worth
1576 * calculating to the exact ms?
1578 _wapi_handle_spin (100);
1580 if (WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) {
1587 _wapi_handle_spin (100);
1591 guint32 idx = GPOINTER_TO_UINT(handle);
1593 pthread_cond_t *cond;
1594 mono_mutex_t *mutex;
1596 if (alertable && !wapi_thread_set_wait_handle (handle))
1599 cond = &_WAPI_PRIVATE_HANDLES (idx).signal_cond;
1600 mutex = &_WAPI_PRIVATE_HANDLES (idx).signal_mutex;
1603 /* This is needed when waiting for process handles */
1604 res = timedwait_signal_poll_cond (cond, mutex, timeout, alertable);
1607 res = mono_cond_timedwait (cond, mutex, timeout);
1609 res = mono_cond_wait (cond, mutex);
1613 wapi_thread_clear_wait_handle (handle);
1619 gboolean _wapi_handle_get_or_set_share (dev_t device, ino_t inode,
1620 guint32 new_sharemode,
1622 guint32 *old_sharemode,
1623 guint32 *old_access,
1624 struct _WapiFileShare **share_info)
1626 struct _WapiFileShare *file_share;
1627 guint32 now = (guint32)(time(NULL) & 0xFFFFFFFF);
1628 int thr_ret, i, first_unused = -1;
1629 gboolean exists = FALSE;
1631 /* Prevents entries from expiring under us as we search
1633 thr_ret = _wapi_handle_lock_shared_handles ();
1634 g_assert (thr_ret == 0);
1636 /* Prevent new entries racing with us */
1637 thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1638 g_assert (thr_ret == 0);
1640 /* If a linear scan gets too slow we'll have to fit a hash
1641 * table onto the shared mem backing store
1644 for (i = 0; i <= _wapi_fileshare_layout->hwm; i++) {
1645 file_share = &_wapi_fileshare_layout->share_info[i];
1647 /* Make a note of an unused slot, in case we need to
1650 if (first_unused == -1 && file_share->handle_refs == 0) {
1655 if (file_share->handle_refs == 0) {
1659 if (file_share->device == device &&
1660 file_share->inode == inode) {
1661 *old_sharemode = file_share->sharemode;
1662 *old_access = file_share->access;
1663 *share_info = file_share;
1665 /* Increment the reference count while we
1666 * still have sole access to the shared area.
1667 * This makes the increment atomic wrt
1670 InterlockedIncrement ((gint32 *)&file_share->handle_refs);
1678 if (i == _WAPI_FILESHARE_SIZE && first_unused == -1) {
1681 if (first_unused == -1) {
1682 file_share = &_wapi_fileshare_layout->share_info[++i];
1683 _wapi_fileshare_layout->hwm = i;
1685 file_share = &_wapi_fileshare_layout->share_info[first_unused];
1688 file_share->device = device;
1689 file_share->inode = inode;
1690 file_share->opened_by_pid = _wapi_getpid ();
1691 file_share->sharemode = new_sharemode;
1692 file_share->access = new_access;
1693 file_share->handle_refs = 1;
1694 *share_info = file_share;
1698 if (*share_info != NULL) {
1699 InterlockedExchange ((gint32 *)&(*share_info)->timestamp, now);
1702 thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1704 _wapi_handle_unlock_shared_handles ();
1709 /* If we don't have the info in /proc, check if the process that
1710 * opened this share info is still there (it's not a perfect method,
1713 static void _wapi_handle_check_share_by_pid (struct _WapiFileShare *share_info)
1715 if (kill (share_info->opened_by_pid, 0) == -1 &&
1718 /* It's gone completely (or there's a new process
1719 * owned by someone else) so mark this share info as
1723 g_message ("%s: Didn't find it, destroying entry", __func__);
1726 memset (share_info, '\0', sizeof(struct _WapiFileShare));
1731 /* Scan /proc/<pids>/fd/ for open file descriptors to the file in
1732 * question. If there are none, reset the share info.
1734 * This implementation is Linux-specific; legacy systems will have to
1735 * implement their own ways of finding out if a particular file is
1736 * open by a process.
1738 void _wapi_handle_check_share (struct _WapiFileShare *share_info, int fd)
1740 gboolean found = FALSE, proc_fds = FALSE;
1741 pid_t self = _wapi_getpid ();
1745 /* Prevents entries from expiring under us if we remove this
1748 thr_ret = _wapi_handle_lock_shared_handles ();
1749 g_assert (thr_ret == 0);
1751 /* Prevent new entries racing with us */
1752 thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1753 g_assert (thr_ret == 0);
1755 /* If there is no /proc, there's nothing more we can do here */
1756 if (access ("/proc", F_OK) == -1) {
1757 _wapi_handle_check_share_by_pid (share_info);
1761 /* If there's another handle that thinks it owns this fd, then even
1762 * if the fd has been closed behind our back consider it still owned.
1763 * See bugs 75764 and 75891
1765 for (i = 0; i < _wapi_fd_reserve; i++) {
1766 if (_wapi_private_handles [SLOT_INDEX (i)]) {
1767 struct _WapiHandleUnshared *handle = &_WAPI_PRIVATE_HANDLES(i);
1770 handle->type == WAPI_HANDLE_FILE) {
1771 struct _WapiHandle_file *file_handle = &handle->u.file;
1773 if (file_handle->share_info == share_info) {
1775 g_message ("%s: handle 0x%x has this file open!",
1785 for (i = 0; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
1786 struct _WapiHandleShared *shared;
1787 struct _WapiHandle_process *process_handle;
1789 shared = &_wapi_shared_layout->handles[i];
1791 if (shared->type == WAPI_HANDLE_PROCESS) {
1793 struct dirent *fd_entry;
1794 char subdir[_POSIX_PATH_MAX];
1796 process_handle = &shared->u.process;
1797 pid = process_handle->id;
1799 /* Look in /proc/<pid>/fd/ but ignore
1800 * /proc/<our pid>/fd/<fd>, as we have the
1803 g_snprintf (subdir, _POSIX_PATH_MAX, "/proc/%d/fd",
1806 fd_dir = opendir (subdir);
1807 if (fd_dir == NULL) {
1812 g_message ("%s: Looking in %s", __func__, subdir);
1817 while ((fd_entry = readdir (fd_dir)) != NULL) {
1818 char path[_POSIX_PATH_MAX];
1819 struct stat link_stat;
1821 if (!strcmp (fd_entry->d_name, ".") ||
1822 !strcmp (fd_entry->d_name, "..") ||
1824 fd == atoi (fd_entry->d_name))) {
1828 g_snprintf (path, _POSIX_PATH_MAX,
1829 "/proc/%d/fd/%s", pid,
1832 stat (path, &link_stat);
1833 if (link_stat.st_dev == share_info->device &&
1834 link_stat.st_ino == share_info->inode) {
1836 g_message ("%s: Found it at %s",
1848 if (proc_fds == FALSE) {
1849 _wapi_handle_check_share_by_pid (share_info);
1850 } else if (found == FALSE) {
1851 /* Blank out this entry, as it is stale */
1853 g_message ("%s: Didn't find it, destroying entry", __func__);
1856 memset (share_info, '\0', sizeof(struct _WapiFileShare));
1860 thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1862 _wapi_handle_unlock_shared_handles ();
1866 // Other implementations (non-Linux)
1868 void _wapi_handle_check_share (struct _WapiFileShare *share_info, int fd)
1872 /* Prevents entries from expiring under us if we remove this
1874 thr_ret = _wapi_handle_lock_shared_handles ();
1875 g_assert (thr_ret == 0);
1877 /* Prevent new entries racing with us */
1878 thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1879 g_assert (thr_ret == 0);
1881 _wapi_handle_check_share_by_pid (share_info);
1883 thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1884 _wapi_handle_unlock_shared_handles ();
1888 void _wapi_handle_dump (void)
1890 struct _WapiHandleUnshared *handle_data;
1894 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
1895 (void *)&scan_mutex);
1896 thr_ret = mono_mutex_lock (&scan_mutex);
1897 g_assert (thr_ret == 0);
1899 for(i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
1900 if (_wapi_private_handles [i]) {
1901 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
1902 handle_data = &_wapi_private_handles [i][k];
1904 if (handle_data->type == WAPI_HANDLE_UNUSED) {
1908 g_print ("%3x [%7s] %s %d ",
1909 i * _WAPI_HANDLE_INITIAL_COUNT + k,
1910 _wapi_handle_typename[handle_data->type],
1911 handle_data->signalled?"Sg":"Un",
1913 handle_details[handle_data->type](&handle_data->u);
1919 thr_ret = mono_mutex_unlock (&scan_mutex);
1920 g_assert (thr_ret == 0);
1921 pthread_cleanup_pop (0);
1924 static void _wapi_shared_details (gpointer handle_info)
1926 struct _WapiHandle_shared_ref *shared = (struct _WapiHandle_shared_ref *)handle_info;
1928 g_print ("offset: 0x%x", shared->offset);
1931 void _wapi_handle_update_refs (void)
1935 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
1937 thr_ret = _wapi_handle_lock_shared_handles ();
1938 g_assert (thr_ret == 0);
1940 /* Prevent file share entries racing with us */
1941 thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1942 g_assert(thr_ret == 0);
1944 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
1945 (void *)&scan_mutex);
1946 thr_ret = mono_mutex_lock (&scan_mutex);
1948 for(i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
1949 if (_wapi_private_handles [i]) {
1950 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
1951 struct _WapiHandleUnshared *handle = &_wapi_private_handles [i][k];
1953 if (_WAPI_SHARED_HANDLE(handle->type)) {
1954 struct _WapiHandleShared *shared_data;
1957 g_message ("%s: (%d) handle 0x%x is SHARED (%s)", __func__, _wapi_getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k, _wapi_handle_typename[handle->type]);
1960 shared_data = &_wapi_shared_layout->handles[handle->u.shared.offset];
1963 g_message ("%s: (%d) Updating timestamp of handle 0x%x", __func__, _wapi_getpid (), handle->u.shared.offset);
1966 InterlockedExchange ((gint32 *)&shared_data->timestamp, now);
1967 } else if (handle->type == WAPI_HANDLE_FILE) {
1968 struct _WapiHandle_file *file_handle = &handle->u.file;
1971 g_message ("%s: (%d) handle 0x%x is FILE", __func__, _wapi_getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k);
1974 g_assert (file_handle->share_info != NULL);
1977 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));
1980 InterlockedExchange ((gint32 *)&file_handle->share_info->timestamp, now);
1986 thr_ret = mono_mutex_unlock (&scan_mutex);
1987 g_assert (thr_ret == 0);
1988 pthread_cleanup_pop (0);
1990 thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1992 _wapi_handle_unlock_shared_handles ();