2 * handles.c: Generic and internal operations on handles
5 * Dick Porter (dick@ximian.com)
7 * (C) 2002-2011 Novell, Inc.
8 * Copyright 2011 Xamarin Inc
9 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
21 #include <sys/types.h>
22 #ifdef HAVE_SYS_SOCKET_H
23 # include <sys/socket.h>
28 #ifdef HAVE_SYS_MMAN_H
29 # include <sys/mman.h>
35 #ifdef HAVE_SYS_RESOURCE_H
36 # include <sys/resource.h>
39 #include <mono/io-layer/wapi.h>
40 #include <mono/io-layer/wapi-private.h>
41 #include <mono/io-layer/handles-private.h>
42 #include <mono/io-layer/shared.h>
43 #include <mono/io-layer/process-private.h>
44 #include <mono/io-layer/io-trace.h>
46 #include <mono/utils/mono-os-mutex.h>
47 #include <mono/utils/mono-proclib.h>
48 #include <mono/utils/mono-threads.h>
49 #include <mono/utils/mono-once.h>
50 #include <mono/utils/mono-logger-internals.h>
53 static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer);
55 static WapiHandleCapability handle_caps[WAPI_HANDLE_COUNT] = { (WapiHandleCapability)0 };
56 static struct _WapiHandleOps *handle_ops[WAPI_HANDLE_COUNT]={
64 #ifndef DISABLE_SOCKETS
70 &_wapi_namedmutex_ops,
72 &_wapi_namedevent_ops,
75 static void _wapi_shared_details (gpointer handle_info);
77 static void (*handle_details[WAPI_HANDLE_COUNT])(gpointer) = {
80 _wapi_console_details,
81 _wapi_shared_details, /* thread */
85 NULL, /* Nothing useful to see in a socket handle */
86 NULL, /* Nothing useful to see in a find handle */
87 _wapi_shared_details, /* process */
89 _wapi_shared_details, /* namedmutex */
90 _wapi_shared_details, /* namedsem */
91 _wapi_shared_details, /* namedevent */
94 const char *_wapi_handle_typename[] = {
113 * We can hold _WAPI_PRIVATE_MAX_SLOTS * _WAPI_HANDLE_INITIAL_COUNT handles.
114 * If 4M handles are not enough... Oh, well... we will crash.
116 #define SLOT_INDEX(x) (x / _WAPI_HANDLE_INITIAL_COUNT)
117 #define SLOT_OFFSET(x) (x % _WAPI_HANDLE_INITIAL_COUNT)
119 struct _WapiHandleUnshared *_wapi_private_handles [_WAPI_PRIVATE_MAX_SLOTS];
120 static guint32 _wapi_private_handle_count = 0;
121 static guint32 _wapi_private_handle_slot_count = 0;
123 struct _WapiHandleSharedLayout *_wapi_shared_layout = NULL;
126 * If SHM is disabled, this will point to a hash of _WapiFileShare structures, otherwise
127 * it will be NULL. We use this instead of _wapi_fileshare_layout to avoid allocating a
130 static GHashTable *file_share_hash;
131 static mono_mutex_t file_share_hash_mutex;
133 #define file_share_hash_lock() mono_os_mutex_lock (&file_share_hash_mutex)
134 #define file_share_hash_unlock() mono_os_mutex_unlock (&file_share_hash_mutex)
136 guint32 _wapi_fd_reserve;
139 * This is an internal handle which is used for handling waiting for multiple handles.
140 * Threads which wait for multiple handles wait on this one handle, and when a handle
141 * is signalled, this handle is signalled too.
143 static gpointer _wapi_global_signal_handle;
145 /* Point to the mutex/cond inside _wapi_global_signal_handle */
146 mono_mutex_t *_wapi_global_signal_mutex;
147 pthread_cond_t *_wapi_global_signal_cond;
150 gboolean _wapi_has_shut_down = FALSE;
152 /* Use this instead of getpid(), to cope with linuxthreads. It's a
153 * function rather than a variable lookup because we need to get at
154 * this before share_init() might have been called.
156 static pid_t _wapi_pid;
157 static mono_once_t pid_init_once = MONO_ONCE_INIT;
159 static void _wapi_handle_unref_full (gpointer handle, gboolean ignore_private_busy_handles);
161 static void pid_init (void)
163 _wapi_pid = getpid ();
166 pid_t _wapi_getpid (void)
168 mono_once (&pid_init_once, pid_init);
174 static mono_mutex_t scan_mutex;
176 static void handle_cleanup (void)
180 /* Every shared handle we were using ought really to be closed
181 * by now, but to make sure just blow them all away. The
182 * exiting finalizer thread in particular races us to the
183 * program exit and doesn't always win, so it can be left
184 * cluttering up the shared file. Anything else left over is
187 for(i = SLOT_INDEX (0); _wapi_private_handles[i] != NULL; i++) {
188 for(j = SLOT_OFFSET (0); j < _WAPI_HANDLE_INITIAL_COUNT; j++) {
189 struct _WapiHandleUnshared *handle_data = &_wapi_private_handles[i][j];
190 gpointer handle = GINT_TO_POINTER (i*_WAPI_HANDLE_INITIAL_COUNT+j);
192 for(k = handle_data->ref; k > 0; k--) {
193 _wapi_handle_unref_full (handle, TRUE);
198 _wapi_shm_semaphores_remove ();
200 g_free (_wapi_shared_layout);
202 if (file_share_hash) {
203 g_hash_table_destroy (file_share_hash);
204 mono_os_mutex_destroy (&file_share_hash_mutex);
207 for (i = 0; i < _WAPI_PRIVATE_MAX_SLOTS; ++i)
208 g_free (_wapi_private_handles [i]);
212 wapi_getdtablesize (void)
214 return eg_getdtablesize ();
220 * Initialize the io-layer.
225 g_assert ((sizeof (handle_ops) / sizeof (handle_ops[0]))
226 == WAPI_HANDLE_COUNT);
228 _wapi_fd_reserve = wapi_getdtablesize ();
230 /* This is needed by the code in _wapi_handle_new_internal */
231 _wapi_fd_reserve = (_wapi_fd_reserve + (_WAPI_HANDLE_INITIAL_COUNT - 1)) & ~(_WAPI_HANDLE_INITIAL_COUNT - 1);
235 * The entries in _wapi_private_handles reserved for fds are allocated lazily to
239 _wapi_private_handles [idx++] = g_new0 (struct _WapiHandleUnshared,
240 _WAPI_HANDLE_INITIAL_COUNT);
243 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
244 _wapi_private_handle_slot_count ++;
245 } while(_wapi_fd_reserve > _wapi_private_handle_count);
247 _wapi_shm_semaphores_init ();
249 _wapi_shared_layout = (_WapiHandleSharedLayout *)g_malloc0 (sizeof (_WapiHandleSharedLayout));
250 g_assert (_wapi_shared_layout != NULL);
253 mono_os_mutex_init (&scan_mutex);
255 _wapi_global_signal_handle = _wapi_handle_new (WAPI_HANDLE_EVENT, NULL);
257 _wapi_global_signal_cond = &_WAPI_PRIVATE_HANDLES (GPOINTER_TO_UINT (_wapi_global_signal_handle)).signal_cond;
258 _wapi_global_signal_mutex = &_WAPI_PRIVATE_HANDLES (GPOINTER_TO_UINT (_wapi_global_signal_handle)).signal_mutex;
260 wapi_processes_init ();
266 g_assert (_wapi_has_shut_down == FALSE);
268 _wapi_has_shut_down = TRUE;
270 _wapi_error_cleanup ();
271 _wapi_thread_cleanup ();
272 wapi_processes_cleanup ();
276 static void _wapi_handle_init_shared (struct _WapiHandleShared *handle,
278 gpointer handle_specific)
280 g_assert (_wapi_has_shut_down == FALSE);
283 handle->timestamp = (guint32)(time (NULL) & 0xFFFFFFFF);
284 handle->signalled = FALSE;
285 handle->handle_refs = 1;
287 if (handle_specific != NULL) {
288 memcpy (&handle->u, handle_specific, sizeof (handle->u));
292 static size_t _wapi_handle_struct_size (WapiHandleType type)
297 case WAPI_HANDLE_FILE: case WAPI_HANDLE_CONSOLE: case WAPI_HANDLE_PIPE:
298 type_size = sizeof (struct _WapiHandle_file);
300 case WAPI_HANDLE_THREAD:
301 type_size = sizeof (struct _WapiHandle_thread);
303 case WAPI_HANDLE_SEM:
304 type_size = sizeof (struct _WapiHandle_sem);
306 case WAPI_HANDLE_MUTEX:
307 type_size = sizeof (struct _WapiHandle_mutex);
309 case WAPI_HANDLE_EVENT:
310 type_size = sizeof (struct _WapiHandle_event);
312 case WAPI_HANDLE_SOCKET:
313 type_size = sizeof (struct _WapiHandle_socket);
315 case WAPI_HANDLE_FIND:
316 type_size = sizeof (struct _WapiHandle_find);
318 case WAPI_HANDLE_PROCESS:
319 type_size = sizeof (struct _WapiHandle_process);
321 case WAPI_HANDLE_NAMEDMUTEX:
322 type_size = sizeof (struct _WapiHandle_namedmutex);
324 case WAPI_HANDLE_NAMEDSEM:
325 type_size = sizeof (struct _WapiHandle_namedsem);
327 case WAPI_HANDLE_NAMEDEVENT:
328 type_size = sizeof (struct _WapiHandle_namedevent);
332 g_error ("Unknown WapiHandleType: %d\n", type);
338 static void _wapi_handle_init (struct _WapiHandleUnshared *handle,
339 WapiHandleType type, gpointer handle_specific)
344 g_assert (_wapi_has_shut_down == FALSE);
347 handle->signalled = FALSE;
350 if (!_WAPI_SHARED_HANDLE(type)) {
351 thr_ret = pthread_cond_init (&handle->signal_cond, NULL);
352 g_assert (thr_ret == 0);
354 thr_ret = mono_os_mutex_init (&handle->signal_mutex);
355 g_assert (thr_ret == 0);
357 if (handle_specific != NULL) {
358 type_size = _wapi_handle_struct_size (type);
359 memcpy (&handle->u, handle_specific,
365 static guint32 _wapi_handle_new_shared (WapiHandleType type,
366 gpointer handle_specific)
369 static guint32 last = 1;
372 g_assert (_wapi_has_shut_down == FALSE);
374 /* Leave the first slot empty as a guard */
376 /* FIXME: expandable array */
377 for(offset = last; offset <_WAPI_HANDLE_INITIAL_COUNT; offset++) {
378 struct _WapiHandleShared *handle = &_wapi_shared_layout->handles[offset];
380 if(handle->type == WAPI_HANDLE_UNUSED) {
381 thr_ret = _wapi_handle_lock_shared_handles ();
382 g_assert (thr_ret == 0);
384 if (InterlockedCompareExchange ((gint32 *)&handle->type, type, WAPI_HANDLE_UNUSED) == WAPI_HANDLE_UNUSED) {
387 _wapi_handle_init_shared (handle, type,
390 _wapi_handle_unlock_shared_handles ();
394 /* Someone else beat us to it, just
399 _wapi_handle_unlock_shared_handles ();
404 /* Try again from the beginning */
409 /* Will need to expand the array. The caller will sort it out */
415 * _wapi_handle_new_internal:
416 * @type: Init handle to this type
418 * Search for a free handle and initialize it. Return the handle on
419 * success and 0 on failure. This is only called from
420 * _wapi_handle_new, and scan_mutex must be held.
422 static guint32 _wapi_handle_new_internal (WapiHandleType type,
423 gpointer handle_specific)
426 static guint32 last = 0;
427 gboolean retry = FALSE;
429 g_assert (_wapi_has_shut_down == FALSE);
431 /* A linear scan should be fast enough. Start from the last
432 * allocation, assuming that handles are allocated more often
433 * than they're freed. Leave the space reserved for file
437 if (last < _wapi_fd_reserve) {
438 last = _wapi_fd_reserve;
445 for(i = SLOT_INDEX (count); i < _wapi_private_handle_slot_count; i++) {
446 if (_wapi_private_handles [i]) {
447 for (k = SLOT_OFFSET (count); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
448 struct _WapiHandleUnshared *handle = &_wapi_private_handles [i][k];
450 if(handle->type == WAPI_HANDLE_UNUSED) {
453 _wapi_handle_init (handle, type, handle_specific);
461 if(retry && last > _wapi_fd_reserve) {
462 /* Try again from the beginning */
463 last = _wapi_fd_reserve;
467 /* Will need to expand the array. The caller will sort it out */
473 _wapi_handle_new (WapiHandleType type, gpointer handle_specific)
475 guint32 handle_idx = 0;
479 g_assert (_wapi_has_shut_down == FALSE);
481 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Creating new handle of type %s", __func__,
482 _wapi_handle_typename[type]);
484 g_assert(!_WAPI_FD_HANDLE(type));
486 thr_ret = mono_os_mutex_lock (&scan_mutex);
487 g_assert (thr_ret == 0);
489 while ((handle_idx = _wapi_handle_new_internal (type, handle_specific)) == 0) {
490 /* Try and expand the array, and have another go */
491 int idx = SLOT_INDEX (_wapi_private_handle_count);
492 if (idx >= _WAPI_PRIVATE_MAX_SLOTS) {
496 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
497 _WAPI_HANDLE_INITIAL_COUNT);
499 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
500 _wapi_private_handle_slot_count ++;
503 thr_ret = mono_os_mutex_unlock (&scan_mutex);
504 g_assert (thr_ret == 0);
506 if (handle_idx == 0) {
507 /* We ran out of slots */
508 handle = _WAPI_HANDLE_INVALID;
512 /* Make sure we left the space for fd mappings */
513 g_assert (handle_idx >= _wapi_fd_reserve);
515 handle = GUINT_TO_POINTER (handle_idx);
517 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Allocated new handle %p", __func__, handle);
519 if (_WAPI_SHARED_HANDLE(type)) {
520 /* Add the shared section too */
523 ref = _wapi_handle_new_shared (type, handle_specific);
525 ref = _wapi_handle_new_shared (type, handle_specific);
527 /* FIXME: grow the arrays */
528 handle = _WAPI_HANDLE_INVALID;
533 _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = ref;
534 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: New shared handle at offset 0x%x", __func__,
542 gpointer _wapi_handle_new_from_offset (WapiHandleType type, guint32 offset,
545 guint32 handle_idx = 0;
546 gpointer handle = INVALID_HANDLE_VALUE;
548 struct _WapiHandleShared *shared;
550 g_assert (_wapi_has_shut_down == FALSE);
552 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Creating new handle of type %s to offset %d", __func__,
553 _wapi_handle_typename[type], offset);
555 g_assert(!_WAPI_FD_HANDLE(type));
556 g_assert(_WAPI_SHARED_HANDLE(type));
557 g_assert(offset != 0);
559 shared = &_wapi_shared_layout->handles[offset];
561 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
562 /* Bump up the timestamp for this offset */
563 InterlockedExchange ((gint32 *)&shared->timestamp, now);
566 thr_ret = mono_os_mutex_lock (&scan_mutex);
567 g_assert (thr_ret == 0);
569 for (i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
570 if (_wapi_private_handles [i]) {
571 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
572 struct _WapiHandleUnshared *handle_data = &_wapi_private_handles [i][k];
574 if (handle_data->type == type &&
575 handle_data->u.shared.offset == offset) {
576 handle = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
577 goto first_pass_done;
584 thr_ret = mono_os_mutex_unlock (&scan_mutex);
585 g_assert (thr_ret == 0);
587 if (handle != INVALID_HANDLE_VALUE) {
588 _wapi_handle_ref (handle);
590 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Returning old handle %p referencing 0x%x",
591 __func__, handle, offset);
595 /* Prevent entries expiring under us as we search */
596 thr_ret = _wapi_handle_lock_shared_handles ();
597 g_assert (thr_ret == 0);
599 if (shared->type == WAPI_HANDLE_UNUSED) {
600 /* Someone deleted this handle while we were working */
601 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Handle at 0x%x unused", __func__, offset);
605 if (shared->type != type) {
606 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Wrong type at %d 0x%x! Found %s wanted %s",
607 __func__, offset, offset,
608 _wapi_handle_typename[shared->type],
609 _wapi_handle_typename[type]);
613 thr_ret = mono_os_mutex_lock (&scan_mutex);
614 g_assert (thr_ret == 0);
616 while ((handle_idx = _wapi_handle_new_internal (type, NULL)) == 0) {
617 /* Try and expand the array, and have another go */
618 int idx = SLOT_INDEX (_wapi_private_handle_count);
619 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
620 _WAPI_HANDLE_INITIAL_COUNT);
622 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
623 _wapi_private_handle_slot_count ++;
626 thr_ret = mono_os_mutex_unlock (&scan_mutex);
627 g_assert (thr_ret == 0);
629 /* Make sure we left the space for fd mappings */
630 g_assert (handle_idx >= _wapi_fd_reserve);
632 handle = GUINT_TO_POINTER (handle_idx);
634 _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = offset;
635 InterlockedIncrement ((gint32 *)&shared->handle_refs);
637 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Allocated new handle %p referencing 0x%x (shared refs %d)", __func__, handle, offset, shared->handle_refs);
640 _wapi_handle_unlock_shared_handles ();
646 init_handles_slot (int idx)
650 thr_ret = mono_os_mutex_lock (&scan_mutex);
651 g_assert (thr_ret == 0);
653 if (_wapi_private_handles [idx] == NULL) {
654 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
655 _WAPI_HANDLE_INITIAL_COUNT);
656 g_assert (_wapi_private_handles [idx]);
659 thr_ret = mono_os_mutex_unlock (&scan_mutex);
660 g_assert (thr_ret == 0);
663 gpointer _wapi_handle_new_fd (WapiHandleType type, int fd,
664 gpointer handle_specific)
666 struct _WapiHandleUnshared *handle;
669 g_assert (_wapi_has_shut_down == FALSE);
671 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Creating new handle of type %s", __func__,
672 _wapi_handle_typename[type]);
674 g_assert(_WAPI_FD_HANDLE(type));
675 g_assert(!_WAPI_SHARED_HANDLE(type));
677 if (fd >= _wapi_fd_reserve) {
678 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fd %d is too big", __func__, fd);
680 return(GUINT_TO_POINTER (_WAPI_HANDLE_INVALID));
683 /* Initialize the array entries on demand */
684 if (_wapi_private_handles [SLOT_INDEX (fd)] == NULL)
685 init_handles_slot (SLOT_INDEX (fd));
687 handle = &_WAPI_PRIVATE_HANDLES(fd);
689 if (handle->type != WAPI_HANDLE_UNUSED) {
690 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fd %d is already in use!", __func__, fd);
691 /* FIXME: clean up this handle? We can't do anything
692 * with the fd, cos thats the new one
696 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Assigning new fd handle %d", __func__, fd);
698 /* Prevent file share entries racing with us, when the file
699 * handle is only half initialised
701 thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
702 g_assert(thr_ret == 0);
704 _wapi_handle_init (handle, type, handle_specific);
706 thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
708 return(GUINT_TO_POINTER(fd));
711 gboolean _wapi_lookup_handle (gpointer handle, WapiHandleType type,
712 gpointer *handle_specific)
714 struct _WapiHandleUnshared *handle_data;
715 guint32 handle_idx = GPOINTER_TO_UINT(handle);
717 if (!_WAPI_PRIVATE_VALID_SLOT (handle_idx)) {
721 /* Initialize the array entries on demand */
722 if (_wapi_private_handles [SLOT_INDEX (handle_idx)] == NULL)
723 init_handles_slot (SLOT_INDEX (handle_idx));
725 handle_data = &_WAPI_PRIVATE_HANDLES(handle_idx);
727 if (handle_data->type != type) {
731 if (handle_specific == NULL) {
735 if (_WAPI_SHARED_HANDLE(type)) {
736 struct _WapiHandle_shared_ref *ref;
737 struct _WapiHandleShared *shared_handle_data;
739 ref = &handle_data->u.shared;
740 shared_handle_data = &_wapi_shared_layout->handles[ref->offset];
742 if (shared_handle_data->type != type) {
743 /* The handle must have been deleted on us
748 *handle_specific = &shared_handle_data->u;
750 *handle_specific = &handle_data->u;
757 _wapi_handle_foreach (WapiHandleType type,
758 gboolean (*on_each)(gpointer test, gpointer user),
761 struct _WapiHandleUnshared *handle_data = NULL;
766 thr_ret = mono_os_mutex_lock (&scan_mutex);
767 g_assert (thr_ret == 0);
769 for (i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
770 if (_wapi_private_handles [i]) {
771 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
772 handle_data = &_wapi_private_handles [i][k];
774 if (handle_data->type == type) {
775 ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
776 if (on_each (ret, user_data) == TRUE)
783 thr_ret = mono_os_mutex_unlock (&scan_mutex);
784 g_assert (thr_ret == 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
793 * The caller owns the returned handle.
795 gpointer _wapi_search_handle (WapiHandleType type,
796 gboolean (*check)(gpointer test, gpointer user),
798 gpointer *handle_specific,
799 gboolean search_shared)
801 struct _WapiHandleUnshared *handle_data = NULL;
802 struct _WapiHandleShared *shared = NULL;
805 gboolean found = FALSE;
808 thr_ret = mono_os_mutex_lock (&scan_mutex);
809 g_assert (thr_ret == 0);
811 for (i = SLOT_INDEX (0); !found && i < _wapi_private_handle_slot_count; i++) {
812 if (_wapi_private_handles [i]) {
813 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
814 handle_data = &_wapi_private_handles [i][k];
816 if (handle_data->type == type) {
817 ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
818 if (check (ret, user_data) == TRUE) {
819 _wapi_handle_ref (ret);
822 if (_WAPI_SHARED_HANDLE (type)) {
823 shared = &_wapi_shared_layout->handles[i];
833 thr_ret = mono_os_mutex_unlock (&scan_mutex);
834 g_assert (thr_ret == 0);
836 if (!found && search_shared && _WAPI_SHARED_HANDLE (type)) {
837 /* Not found yet, so search the shared memory too */
838 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Looking at other shared handles...", __func__);
840 for (i = 0; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
841 shared = &_wapi_shared_layout->handles[i];
843 if (shared->type == type) {
844 /* Tell new_from_offset to not
845 * timestamp this handle, because
846 * otherwise it will ping every handle
847 * in the list and they will never
850 ret = _wapi_handle_new_from_offset (type, i,
852 if (ret == INVALID_HANDLE_VALUE) {
853 /* This handle was deleted
854 * while we were looking at it
859 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Opened tmp handle %p (type %s) from offset %d", __func__, ret, _wapi_handle_typename[type], i);
861 /* It's possible that the shared part
862 * of this handle has now been blown
863 * away (after new_from_offset
864 * successfully opened it,) if its
865 * timestamp is too old. The check
866 * function needs to be aware of this,
867 * and cope if the handle has
870 if (check (ret, user_data) == TRUE) {
871 /* Timestamp this handle, but make
872 * sure it still exists first
874 thr_ret = _wapi_handle_lock_shared_handles ();
875 g_assert (thr_ret == 0);
877 if (shared->type == type) {
878 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
879 InterlockedExchange ((gint32 *)&shared->timestamp, now);
882 handle_data = &_WAPI_PRIVATE_HANDLES(GPOINTER_TO_UINT(ret));
884 _wapi_handle_unlock_shared_handles ();
887 /* It's been deleted,
891 _wapi_handle_unlock_shared_handles ();
895 /* This isn't the handle we're looking
896 * for, so drop the reference we took
897 * in _wapi_handle_new_from_offset ()
899 _wapi_handle_unref (ret);
909 if(handle_specific != NULL) {
910 if (_WAPI_SHARED_HANDLE(type)) {
911 g_assert(shared->type == type);
913 *handle_specific = &shared->u;
915 *handle_specific = &handle_data->u;
923 /* Returns the offset of the metadata array, or -1 on error, or 0 for
924 * not found (0 is not a valid offset)
926 gint32 _wapi_search_handle_namespace (WapiHandleType type,
929 struct _WapiHandleShared *shared_handle_data;
934 g_assert(_WAPI_SHARED_HANDLE(type));
936 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Lookup for handle named [%s] type %s", __func__,
937 utf8_name, _wapi_handle_typename[type]);
939 thr_ret = _wapi_handle_lock_shared_handles ();
940 g_assert (thr_ret == 0);
942 for(i = 1; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
943 WapiSharedNamespace *sharedns;
945 shared_handle_data = &_wapi_shared_layout->handles[i];
947 /* Check mutex, event, semaphore, timer, job and
948 * file-mapping object names. So far only mutex,
949 * semaphore and event are implemented.
951 if (!_WAPI_SHARED_NAMESPACE (shared_handle_data->type)) {
955 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: found a shared namespace handle at 0x%x (type %s)", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
957 sharedns=(WapiSharedNamespace *)&shared_handle_data->u;
959 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: name is [%s]", __func__, sharedns->name);
961 if (strcmp (sharedns->name, utf8_name) == 0) {
962 if (shared_handle_data->type != type) {
963 /* Its the wrong type, so fail now */
964 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle 0x%x matches name but is wrong type: %s", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
968 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle 0x%x matches name and type", __func__, i);
976 _wapi_handle_unlock_shared_handles ();
981 void _wapi_handle_ref (gpointer handle)
983 guint32 idx = GPOINTER_TO_UINT(handle);
984 struct _WapiHandleUnshared *handle_data;
986 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
990 if (_wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) {
991 g_warning ("%s: Attempting to ref unused handle %p", __func__,
996 handle_data = &_WAPI_PRIVATE_HANDLES(idx);
998 InterlockedIncrement ((gint32 *)&handle_data->ref);
1000 /* It's possible for processes to exit before getting around
1001 * to updating timestamps in the collection thread, so if a
1002 * shared handle is reffed do the timestamp here as well just
1005 if (_WAPI_SHARED_HANDLE(handle_data->type)) {
1006 struct _WapiHandleShared *shared_data = &_wapi_shared_layout->handles[handle_data->u.shared.offset];
1007 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
1008 InterlockedExchange ((gint32 *)&shared_data->timestamp, now);
1012 g_message ("%s: %s handle %p ref now %d", __func__,
1013 _wapi_handle_typename[_WAPI_PRIVATE_HANDLES (idx).type],
1015 _WAPI_PRIVATE_HANDLES(idx).ref);
1019 /* The handle must not be locked on entry to this function */
1020 static void _wapi_handle_unref_full (gpointer handle, gboolean ignore_private_busy_handles)
1022 guint32 idx = GPOINTER_TO_UINT(handle);
1023 gboolean destroy = FALSE, early_exit = FALSE;
1026 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1030 if (_wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) {
1031 g_warning ("%s: Attempting to unref unused handle %p",
1036 /* Possible race condition here if another thread refs the
1037 * handle between here and setting the type to UNUSED. I
1038 * could lock a mutex, but I'm not sure that allowing a handle
1039 * reference to reach 0 isn't an application bug anyway.
1041 destroy = (InterlockedDecrement ((gint32 *)&_WAPI_PRIVATE_HANDLES(idx).ref) ==0);
1044 g_message ("%s: %s handle %p ref now %d (destroy %s)", __func__,
1045 _wapi_handle_typename[_WAPI_PRIVATE_HANDLES (idx).type],
1047 _WAPI_PRIVATE_HANDLES(idx).ref, destroy?"TRUE":"FALSE");
1051 /* Need to copy the handle info, reset the slot in the
1052 * array, and _only then_ call the close function to
1053 * avoid race conditions (eg file descriptors being
1054 * closed, and another file being opened getting the
1055 * same fd racing the memset())
1057 struct _WapiHandleUnshared handle_data;
1058 struct _WapiHandleShared shared_handle_data;
1059 WapiHandleType type = _WAPI_PRIVATE_HANDLES(idx).type;
1060 void (*close_func)(gpointer, gpointer) = _wapi_handle_ops_get_close_func (type);
1061 gboolean is_shared = _WAPI_SHARED_HANDLE(type);
1064 /* If this is a shared handle we need to take
1065 * the shared lock outside of the scan_mutex
1066 * lock to avoid deadlocks
1068 thr_ret = _wapi_handle_lock_shared_handles ();
1069 g_assert (thr_ret == 0);
1072 thr_ret = mono_os_mutex_lock (&scan_mutex);
1074 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Destroying handle %p", __func__, handle);
1076 memcpy (&handle_data, &_WAPI_PRIVATE_HANDLES(idx),
1077 sizeof (struct _WapiHandleUnshared));
1079 memset (&_WAPI_PRIVATE_HANDLES(idx).u, '\0',
1080 sizeof(_WAPI_PRIVATE_HANDLES(idx).u));
1082 _WAPI_PRIVATE_HANDLES(idx).type = WAPI_HANDLE_UNUSED;
1085 /* Destroy the mutex and cond var. We hope nobody
1086 * tried to grab them between the handle unlock and
1087 * now, but pthreads doesn't have a
1088 * "unlock_and_destroy" atomic function.
1090 thr_ret = mono_os_mutex_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_mutex);
1091 /*WARNING gross hack to make cleanup not crash when exiting without the whole runtime teardown.*/
1092 if (thr_ret == EBUSY && ignore_private_busy_handles) {
1096 g_error ("Error destroying handle %p mutex due to %d\n", handle, thr_ret);
1098 thr_ret = pthread_cond_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_cond);
1099 if (thr_ret == EBUSY && ignore_private_busy_handles)
1101 else if (thr_ret != 0)
1102 g_error ("Error destroying handle %p cond var due to %d\n", handle, thr_ret);
1105 struct _WapiHandleShared *shared = &_wapi_shared_layout->handles[handle_data.u.shared.offset];
1107 memcpy (&shared_handle_data, shared,
1108 sizeof (struct _WapiHandleShared));
1110 /* It's possible that this handle is already
1111 * pointing at a deleted shared section
1114 g_message ("%s: %s handle %p shared refs before dec %d", __func__, _wapi_handle_typename[type], handle, shared->handle_refs);
1117 if (shared->handle_refs > 0) {
1118 shared->handle_refs--;
1119 if (shared->handle_refs == 0) {
1120 memset (shared, '\0', sizeof (struct _WapiHandleShared));
1125 thr_ret = mono_os_mutex_unlock (&scan_mutex);
1126 g_assert (thr_ret == 0);
1131 _wapi_handle_unlock_shared_handles ();
1134 if (close_func != NULL) {
1136 close_func (handle, &shared_handle_data.u);
1138 close_func (handle, &handle_data.u);
1144 void _wapi_handle_unref (gpointer handle)
1146 _wapi_handle_unref_full (handle, FALSE);
1149 void _wapi_handle_register_capabilities (WapiHandleType type,
1150 WapiHandleCapability caps)
1152 handle_caps[type] = caps;
1155 gboolean _wapi_handle_test_capabilities (gpointer handle,
1156 WapiHandleCapability caps)
1158 guint32 idx = GPOINTER_TO_UINT(handle);
1159 WapiHandleType type;
1161 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1165 type = _WAPI_PRIVATE_HANDLES(idx).type;
1167 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: testing 0x%x against 0x%x (%d)", __func__,
1168 handle_caps[type], caps, handle_caps[type] & caps);
1170 return((handle_caps[type] & caps) != 0);
1173 static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer)
1175 if (handle_ops[type] != NULL &&
1176 handle_ops[type]->close != NULL) {
1177 return (handle_ops[type]->close);
1183 void _wapi_handle_ops_close (gpointer handle, gpointer data)
1185 guint32 idx = GPOINTER_TO_UINT(handle);
1186 WapiHandleType type;
1188 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1192 type = _WAPI_PRIVATE_HANDLES(idx).type;
1194 if (handle_ops[type] != NULL &&
1195 handle_ops[type]->close != NULL) {
1196 handle_ops[type]->close (handle, data);
1200 void _wapi_handle_ops_signal (gpointer handle)
1202 guint32 idx = GPOINTER_TO_UINT(handle);
1203 WapiHandleType type;
1205 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1209 type = _WAPI_PRIVATE_HANDLES(idx).type;
1211 if (handle_ops[type] != NULL && handle_ops[type]->signal != NULL) {
1212 handle_ops[type]->signal (handle);
1216 gboolean _wapi_handle_ops_own (gpointer handle)
1218 guint32 idx = GPOINTER_TO_UINT(handle);
1219 WapiHandleType type;
1221 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1225 type = _WAPI_PRIVATE_HANDLES(idx).type;
1227 if (handle_ops[type] != NULL && handle_ops[type]->own_handle != NULL) {
1228 return(handle_ops[type]->own_handle (handle));
1234 gboolean _wapi_handle_ops_isowned (gpointer handle)
1236 guint32 idx = GPOINTER_TO_UINT(handle);
1237 WapiHandleType type;
1239 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1243 type = _WAPI_PRIVATE_HANDLES(idx).type;
1245 if (handle_ops[type] != NULL && handle_ops[type]->is_owned != NULL) {
1246 return(handle_ops[type]->is_owned (handle));
1252 guint32 _wapi_handle_ops_special_wait (gpointer handle, guint32 timeout, gboolean alertable)
1254 guint32 idx = GPOINTER_TO_UINT(handle);
1255 WapiHandleType type;
1257 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1258 return(WAIT_FAILED);
1261 type = _WAPI_PRIVATE_HANDLES(idx).type;
1263 if (handle_ops[type] != NULL &&
1264 handle_ops[type]->special_wait != NULL) {
1265 return(handle_ops[type]->special_wait (handle, timeout, alertable));
1267 return(WAIT_FAILED);
1271 void _wapi_handle_ops_prewait (gpointer handle)
1273 guint32 idx = GPOINTER_TO_UINT (handle);
1274 WapiHandleType type;
1276 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1280 type = _WAPI_PRIVATE_HANDLES (idx).type;
1282 if (handle_ops[type] != NULL &&
1283 handle_ops[type]->prewait != NULL) {
1284 handle_ops[type]->prewait (handle);
1291 * @handle: The handle to release
1293 * Closes and invalidates @handle, releasing any resources it
1294 * consumes. When the last handle to a temporary or non-persistent
1295 * object is closed, that object can be deleted. Closing the same
1296 * handle twice is an error.
1298 * Return value: %TRUE on success, %FALSE otherwise.
1300 gboolean CloseHandle(gpointer handle)
1302 if (handle == NULL) {
1303 /* Problem: because we map file descriptors to the
1304 * same-numbered handle we can't tell the difference
1305 * between a bogus handle and the handle to stdin.
1306 * Assume that it's the console handle if that handle
1309 if (_WAPI_PRIVATE_HANDLES (0).type != WAPI_HANDLE_CONSOLE) {
1310 SetLastError (ERROR_INVALID_PARAMETER);
1314 if (handle == _WAPI_HANDLE_INVALID){
1315 SetLastError (ERROR_INVALID_PARAMETER);
1319 _wapi_handle_unref (handle);
1324 /* Lots more to implement here, but this is all we need at the moment */
1325 gboolean DuplicateHandle (gpointer srcprocess, gpointer src,
1326 gpointer targetprocess, gpointer *target,
1327 guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, guint32 options G_GNUC_UNUSED)
1329 if (srcprocess != _WAPI_PROCESS_CURRENT ||
1330 targetprocess != _WAPI_PROCESS_CURRENT) {
1331 /* Duplicating other process's handles is not supported */
1332 SetLastError (ERROR_INVALID_HANDLE);
1336 if (src == _WAPI_PROCESS_CURRENT) {
1337 *target = _wapi_process_duplicate ();
1338 } else if (src == _WAPI_THREAD_CURRENT) {
1339 g_assert_not_reached ();
1341 _wapi_handle_ref (src);
1348 gboolean _wapi_handle_count_signalled_handles (guint32 numhandles,
1354 guint32 count, i, iter=0;
1357 WapiHandleType type;
1359 /* Lock all the handles, with backoff */
1361 thr_ret = _wapi_handle_lock_shared_handles ();
1362 g_assert (thr_ret == 0);
1364 for(i=0; i<numhandles; i++) {
1365 gpointer handle = handles[i];
1366 guint32 idx = GPOINTER_TO_UINT(handle);
1368 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: attempting to lock %p", __func__, handle);
1370 type = _WAPI_PRIVATE_HANDLES(idx).type;
1372 thr_ret = _wapi_handle_trylock_handle (handle);
1377 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: attempt failed for %p: %s", __func__,
1378 handle, strerror (thr_ret));
1380 thr_ret = _wapi_handle_unlock_shared_handles ();
1381 g_assert (thr_ret == 0);
1384 handle = handles[i];
1385 idx = GPOINTER_TO_UINT(handle);
1387 thr_ret = _wapi_handle_unlock_handle (handle);
1388 g_assert (thr_ret == 0);
1391 /* If iter ever reaches 100 the nanosleep will
1392 * return EINVAL immediately, but we have a
1393 * design flaw if that happens.
1397 g_warning ("%s: iteration overflow!",
1402 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Backing off for %d ms", __func__,
1404 _wapi_handle_spin (10 * iter);
1410 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Locked all handles", __func__);
1415 for(i=0; i<numhandles; i++) {
1416 gpointer handle = handles[i];
1417 guint32 idx = GPOINTER_TO_UINT(handle);
1419 type = _WAPI_PRIVATE_HANDLES(idx).type;
1421 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Checking handle %p", __func__, handle);
1423 if(((_wapi_handle_test_capabilities (handle, WAPI_HANDLE_CAP_OWN)==TRUE) &&
1424 (_wapi_handle_ops_isowned (handle) == TRUE)) ||
1425 (_WAPI_SHARED_HANDLE(type) &&
1426 WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) ||
1427 (!_WAPI_SHARED_HANDLE(type) &&
1428 _WAPI_PRIVATE_HANDLES(idx).signalled == TRUE)) {
1431 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Handle %p signalled", __func__,
1439 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: %d event handles signalled", __func__, count);
1441 if ((waitall == TRUE && count == numhandles) ||
1442 (waitall == FALSE && count > 0)) {
1448 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Returning %d", __func__, ret);
1455 void _wapi_handle_unlock_handles (guint32 numhandles, gpointer *handles)
1460 thr_ret = _wapi_handle_unlock_shared_handles ();
1461 g_assert (thr_ret == 0);
1463 for(i=0; i<numhandles; i++) {
1464 gpointer handle = handles[i];
1466 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unlocking handle %p", __func__, handle);
1468 thr_ret = _wapi_handle_unlock_handle (handle);
1469 g_assert (thr_ret == 0);
1474 _wapi_handle_timedwait_signal (guint32 timeout, gboolean poll, gboolean *alerted)
1476 return _wapi_handle_timedwait_signal_handle (_wapi_global_signal_handle, timeout, TRUE, poll, alerted);
1480 signal_handle_and_unref (gpointer handle)
1482 pthread_cond_t *cond;
1483 mono_mutex_t *mutex;
1488 /* If we reach here, then interrupt token is set to the flag value, which
1489 * means that the target thread is either
1490 * - before the first CAS in timedwait, which means it won't enter the wait.
1491 * - it is after the first CAS, so it is already waiting, or it will enter
1492 * the wait, and it will be interrupted by the broadcast. */
1493 idx = GPOINTER_TO_UINT (handle);
1494 cond = &_WAPI_PRIVATE_HANDLES (idx).signal_cond;
1495 mutex = &_WAPI_PRIVATE_HANDLES (idx).signal_mutex;
1497 mono_os_mutex_lock (mutex);
1498 mono_os_cond_broadcast (cond);
1499 mono_os_mutex_unlock (mutex);
1501 _wapi_handle_unref (handle);
1505 _wapi_handle_timedwait_signal_handle (gpointer handle, guint32 timeout, gboolean alertable, gboolean poll, gboolean *alerted)
1507 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: waiting for %p (type %s)", __func__, handle,
1508 _wapi_handle_typename[_wapi_handle_type (handle)]);
1516 if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
1517 if (WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) {
1520 if (timeout != INFINITE) {
1521 if (timeout < 100) {
1522 /* FIXME: Real timeout is less than
1523 * 100ms time, but is it really worth
1524 * calculating to the exact ms?
1526 _wapi_handle_spin (100);
1528 if (WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) {
1535 _wapi_handle_spin (100);
1539 guint32 idx = GPOINTER_TO_UINT(handle);
1541 pthread_cond_t *cond;
1542 mono_mutex_t *mutex;
1545 mono_thread_info_install_interrupt (signal_handle_and_unref, handle, alerted);
1548 _wapi_handle_ref (handle);
1551 cond = &_WAPI_PRIVATE_HANDLES (idx).signal_cond;
1552 mutex = &_WAPI_PRIVATE_HANDLES (idx).signal_mutex;
1555 res = mono_os_cond_timedwait (cond, mutex, timeout);
1557 /* This is needed when waiting for process handles */
1560 * pthread_cond_(timed)wait() can return 0 even if the condition was not
1561 * signalled. This happens at least on Darwin. We surface this, i.e., we
1562 * get spurious wake-ups.
1564 * http://pubs.opengroup.org/onlinepubs/007908775/xsh/pthread_cond_wait.html
1566 res = mono_os_cond_timedwait (cond, mutex, timeout);
1568 if (timeout < 100) {
1569 /* Real timeout is less than 100ms time */
1570 res = mono_os_cond_timedwait (cond, mutex, timeout);
1572 res = mono_os_cond_timedwait (cond, mutex, 100);
1574 /* Mask the fake timeout, this will cause
1575 * another poll if the cond was not really signaled
1577 if (res == ETIMEDOUT)
1584 mono_thread_info_uninstall_interrupt (alerted);
1586 /* if it is alerted, then the handle is unref in the interrupt callback */
1587 _wapi_handle_unref (handle);
1596 _wapi_free_share_info (_WapiFileShare *share_info)
1598 file_share_hash_lock ();
1599 g_hash_table_remove (file_share_hash, share_info);
1600 file_share_hash_unlock ();
1601 /* The hashtable dtor frees share_info */
1605 wapi_share_info_equal (gconstpointer ka, gconstpointer kb)
1607 const _WapiFileShare *s1 = (const _WapiFileShare *)ka;
1608 const _WapiFileShare *s2 = (const _WapiFileShare *)kb;
1610 return (s1->device == s2->device && s1->inode == s2->inode) ? 1 : 0;
1614 wapi_share_info_hash (gconstpointer data)
1616 const _WapiFileShare *s = (const _WapiFileShare *)data;
1621 gboolean _wapi_handle_get_or_set_share (guint64 device, guint64 inode,
1622 guint32 new_sharemode,
1624 guint32 *old_sharemode,
1625 guint32 *old_access,
1626 struct _WapiFileShare **share_info)
1628 struct _WapiFileShare *file_share;
1630 gboolean exists = FALSE;
1632 /* Prevents entries from expiring under us as we search
1634 thr_ret = _wapi_handle_lock_shared_handles ();
1635 g_assert (thr_ret == 0);
1637 /* Prevent new entries racing with us */
1638 thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1639 g_assert (thr_ret == 0);
1644 * Instead of allocating a 4MB array, we use a hash table to keep track of this
1645 * info. This is needed even if SHM is disabled, to track sharing inside
1646 * the current process.
1648 if (!file_share_hash) {
1649 file_share_hash = g_hash_table_new_full (wapi_share_info_hash, wapi_share_info_equal, NULL, g_free);
1650 mono_os_mutex_init_recursive (&file_share_hash_mutex);
1653 tmp.device = device;
1656 file_share_hash_lock ();
1658 file_share = (_WapiFileShare *)g_hash_table_lookup (file_share_hash, &tmp);
1660 *old_sharemode = file_share->sharemode;
1661 *old_access = file_share->access;
1662 *share_info = file_share;
1664 InterlockedIncrement ((gint32 *)&file_share->handle_refs);
1667 file_share = g_new0 (_WapiFileShare, 1);
1669 file_share->device = device;
1670 file_share->inode = inode;
1671 file_share->opened_by_pid = _wapi_getpid ();
1672 file_share->sharemode = new_sharemode;
1673 file_share->access = new_access;
1674 file_share->handle_refs = 1;
1675 *share_info = file_share;
1677 g_hash_table_insert (file_share_hash, file_share, file_share);
1680 file_share_hash_unlock ();
1682 thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1684 _wapi_handle_unlock_shared_handles ();
1689 /* If we don't have the info in /proc, check if the process that
1690 * opened this share info is still there (it's not a perfect method,
1693 static void _wapi_handle_check_share_by_pid (struct _WapiFileShare *share_info)
1695 #if defined(__native_client__)
1696 g_assert_not_reached ();
1697 #elif defined(HAVE_KILL)
1698 if (kill (share_info->opened_by_pid, 0) == -1 &&
1701 /* It's gone completely (or there's a new process
1702 * owned by someone else) so mark this share info as
1705 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Didn't find it, destroying entry", __func__);
1707 _wapi_free_share_info (share_info);
1713 /* Scan /proc/<pids>/fd/ for open file descriptors to the file in
1714 * question. If there are none, reset the share info.
1716 * This implementation is Linux-specific; legacy systems will have to
1717 * implement their own ways of finding out if a particular file is
1718 * open by a process.
1720 void _wapi_handle_check_share (struct _WapiFileShare *share_info, int fd)
1722 gboolean found = FALSE, proc_fds = FALSE;
1725 /* Prevents entries from expiring under us if we remove this
1728 thr_ret = _wapi_handle_lock_shared_handles ();
1729 g_assert (thr_ret == 0);
1731 /* Prevent new entries racing with us */
1732 thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1733 g_assert (thr_ret == 0);
1735 /* If there is no /proc, there's nothing more we can do here */
1736 if (access ("/proc", F_OK) == -1) {
1737 _wapi_handle_check_share_by_pid (share_info);
1741 /* If there's another handle that thinks it owns this fd, then even
1742 * if the fd has been closed behind our back consider it still owned.
1743 * See bugs 75764 and 75891
1745 for (i = 0; i < _wapi_fd_reserve; i++) {
1746 if (_wapi_private_handles [SLOT_INDEX (i)]) {
1747 struct _WapiHandleUnshared *handle = &_WAPI_PRIVATE_HANDLES(i);
1750 handle->type == WAPI_HANDLE_FILE) {
1751 struct _WapiHandle_file *file_handle = &handle->u.file;
1753 if (file_handle->share_info == share_info) {
1754 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle 0x%x has this file open!",
1763 if (proc_fds == FALSE) {
1764 _wapi_handle_check_share_by_pid (share_info);
1765 } else if (found == FALSE) {
1766 /* Blank out this entry, as it is stale */
1767 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Didn't find it, destroying entry", __func__);
1769 _wapi_free_share_info (share_info);
1773 thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1775 _wapi_handle_unlock_shared_handles ();
1779 // Other implementations (non-Linux)
1781 void _wapi_handle_check_share (struct _WapiFileShare *share_info, int fd)
1785 /* Prevents entries from expiring under us if we remove this
1787 thr_ret = _wapi_handle_lock_shared_handles ();
1788 g_assert (thr_ret == 0);
1790 /* Prevent new entries racing with us */
1791 thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1792 g_assert (thr_ret == 0);
1794 _wapi_handle_check_share_by_pid (share_info);
1796 thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1797 _wapi_handle_unlock_shared_handles ();
1801 void _wapi_handle_dump (void)
1803 struct _WapiHandleUnshared *handle_data;
1807 thr_ret = mono_os_mutex_lock (&scan_mutex);
1808 g_assert (thr_ret == 0);
1810 for(i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
1811 if (_wapi_private_handles [i]) {
1812 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
1813 handle_data = &_wapi_private_handles [i][k];
1815 if (handle_data->type == WAPI_HANDLE_UNUSED) {
1819 g_print ("%3x [%7s] %s %d ",
1820 i * _WAPI_HANDLE_INITIAL_COUNT + k,
1821 _wapi_handle_typename[handle_data->type],
1822 handle_data->signalled?"Sg":"Un",
1824 if (handle_details[handle_data->type])
1825 handle_details[handle_data->type](&handle_data->u);
1831 thr_ret = mono_os_mutex_unlock (&scan_mutex);
1832 g_assert (thr_ret == 0);
1835 static void _wapi_shared_details (gpointer handle_info)
1837 struct _WapiHandle_shared_ref *shared = (struct _WapiHandle_shared_ref *)handle_info;
1839 g_print ("offset: 0x%x", shared->offset);