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
20 #include <sys/types.h>
21 #ifdef HAVE_SYS_SOCKET_H
22 # include <sys/socket.h>
27 #ifdef HAVE_SYS_MMAN_H
28 # include <sys/mman.h>
34 #ifdef HAVE_SYS_RESOURCE_H
35 # include <sys/resource.h>
38 #include <mono/io-layer/wapi.h>
39 #include <mono/io-layer/wapi-private.h>
40 #include <mono/io-layer/handles-private.h>
41 #include <mono/io-layer/misc-private.h>
42 #include <mono/io-layer/shared.h>
43 #include <mono/io-layer/collection.h>
44 #include <mono/io-layer/process-private.h>
46 #include <mono/utils/mono-mutex.h>
47 #include <mono/utils/mono-proclib.h>
48 #include <mono/utils/mono-threads.h>
52 #define DEBUG(...) g_message(__VA_ARGS__)
57 static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer);
59 static WapiHandleCapability handle_caps[WAPI_HANDLE_COUNT]={0};
60 static struct _WapiHandleOps *handle_ops[WAPI_HANDLE_COUNT]={
68 #ifndef DISABLE_SOCKETS
74 &_wapi_namedmutex_ops,
76 &_wapi_namedevent_ops,
79 static void _wapi_shared_details (gpointer handle_info);
81 static void (*handle_details[WAPI_HANDLE_COUNT])(gpointer) = {
84 _wapi_console_details,
85 _wapi_shared_details, /* thread */
89 NULL, /* Nothing useful to see in a socket handle */
90 NULL, /* Nothing useful to see in a find handle */
91 _wapi_shared_details, /* process */
93 _wapi_shared_details, /* namedmutex */
94 _wapi_shared_details, /* namedsem */
95 _wapi_shared_details, /* namedevent */
98 const char *_wapi_handle_typename[] = {
117 * We can hold _WAPI_PRIVATE_MAX_SLOTS * _WAPI_HANDLE_INITIAL_COUNT handles.
118 * If 4M handles are not enough... Oh, well... we will crash.
120 #define SLOT_INDEX(x) (x / _WAPI_HANDLE_INITIAL_COUNT)
121 #define SLOT_OFFSET(x) (x % _WAPI_HANDLE_INITIAL_COUNT)
123 struct _WapiHandleUnshared *_wapi_private_handles [_WAPI_PRIVATE_MAX_SLOTS];
124 static guint32 _wapi_private_handle_count = 0;
125 static guint32 _wapi_private_handle_slot_count = 0;
127 struct _WapiHandleSharedLayout *_wapi_shared_layout = NULL;
130 * If SHM is enabled, this will point to shared memory, otherwise it will be NULL.
132 struct _WapiFileShareLayout *_wapi_fileshare_layout = NULL;
135 * If SHM is disabled, this will point to a hash of _WapiFileShare structures, otherwise
136 * it will be NULL. We use this instead of _wapi_fileshare_layout to avoid allocating a
139 static GHashTable *file_share_hash;
140 static mono_mutex_t file_share_hash_mutex;
142 #define file_share_hash_lock() mono_mutex_lock (&file_share_hash_mutex)
143 #define file_share_hash_unlock() mono_mutex_unlock (&file_share_hash_mutex)
145 guint32 _wapi_fd_reserve;
148 * This is an internal handle which is used for handling waiting for multiple handles.
149 * Threads which wait for multiple handles wait on this one handle, and when a handle
150 * is signalled, this handle is signalled too.
152 static gpointer _wapi_global_signal_handle;
154 /* Point to the mutex/cond inside _wapi_global_signal_handle */
155 mono_mutex_t *_wapi_global_signal_mutex;
156 pthread_cond_t *_wapi_global_signal_cond;
159 gboolean _wapi_has_shut_down = FALSE;
161 /* Use this instead of getpid(), to cope with linuxthreads. It's a
162 * function rather than a variable lookup because we need to get at
163 * this before share_init() might have been called.
165 static pid_t _wapi_pid;
166 static mono_once_t pid_init_once = MONO_ONCE_INIT;
168 static void _wapi_handle_unref_full (gpointer handle, gboolean ignore_private_busy_handles);
170 static void pid_init (void)
172 _wapi_pid = getpid ();
175 pid_t _wapi_getpid (void)
177 mono_once (&pid_init_once, pid_init);
183 static mono_mutex_t scan_mutex;
185 static void handle_cleanup (void)
189 /* Every shared handle we were using ought really to be closed
190 * by now, but to make sure just blow them all away. The
191 * exiting finalizer thread in particular races us to the
192 * program exit and doesn't always win, so it can be left
193 * cluttering up the shared file. Anything else left over is
196 for(i = SLOT_INDEX (0); _wapi_private_handles[i] != NULL; i++) {
197 for(j = SLOT_OFFSET (0); j < _WAPI_HANDLE_INITIAL_COUNT; j++) {
198 struct _WapiHandleUnshared *handle_data = &_wapi_private_handles[i][j];
199 gpointer handle = GINT_TO_POINTER (i*_WAPI_HANDLE_INITIAL_COUNT+j);
201 for(k = handle_data->ref; k > 0; k--) {
202 DEBUG ("%s: unreffing %s handle %p", __func__, _wapi_handle_typename[type], handle);
204 _wapi_handle_unref_full (handle, TRUE);
209 _wapi_shm_semaphores_remove ();
211 _wapi_shm_detach (WAPI_SHM_DATA);
212 _wapi_shm_detach (WAPI_SHM_FILESHARE);
214 if (file_share_hash) {
215 g_hash_table_destroy (file_share_hash);
216 mono_mutex_destroy (&file_share_hash_mutex);
219 for (i = 0; i < _WAPI_PRIVATE_MAX_SLOTS; ++i)
220 g_free (_wapi_private_handles [i]);
224 wapi_getdtablesize (void)
226 return eg_getdtablesize ();
232 * Initialize the io-layer.
237 g_assert ((sizeof (handle_ops) / sizeof (handle_ops[0]))
238 == WAPI_HANDLE_COUNT);
240 _wapi_fd_reserve = wapi_getdtablesize ();
242 /* This is needed by the code in _wapi_handle_new_internal */
243 _wapi_fd_reserve = (_wapi_fd_reserve + (_WAPI_HANDLE_INITIAL_COUNT - 1)) & ~(_WAPI_HANDLE_INITIAL_COUNT - 1);
247 * The entries in _wapi_private_handles reserved for fds are allocated lazily to
251 _wapi_private_handles [idx++] = g_new0 (struct _WapiHandleUnshared,
252 _WAPI_HANDLE_INITIAL_COUNT);
255 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
256 _wapi_private_handle_slot_count ++;
257 } while(_wapi_fd_reserve > _wapi_private_handle_count);
259 _wapi_shm_semaphores_init ();
261 _wapi_shared_layout = _wapi_shm_attach (WAPI_SHM_DATA);
262 g_assert (_wapi_shared_layout != NULL);
264 if (_wapi_shm_enabled ()) {
265 /* This allocates a 4mb array, so do it only if SHM is enabled */
266 _wapi_fileshare_layout = _wapi_shm_attach (WAPI_SHM_FILESHARE);
267 g_assert (_wapi_fileshare_layout != NULL);
270 #if !defined (DISABLE_SHARED_HANDLES)
271 if (_wapi_shm_enabled ())
272 _wapi_collection_init ();
275 mono_mutex_init (&scan_mutex);
277 _wapi_global_signal_handle = _wapi_handle_new (WAPI_HANDLE_EVENT, NULL);
279 _wapi_global_signal_cond = &_WAPI_PRIVATE_HANDLES (GPOINTER_TO_UINT (_wapi_global_signal_handle)).signal_cond;
280 _wapi_global_signal_mutex = &_WAPI_PRIVATE_HANDLES (GPOINTER_TO_UINT (_wapi_global_signal_handle)).signal_mutex;
282 wapi_processes_init ();
288 g_assert (_wapi_has_shut_down == FALSE);
290 _wapi_has_shut_down = TRUE;
292 _wapi_error_cleanup ();
293 _wapi_thread_cleanup ();
294 wapi_processes_cleanup ();
298 static void _wapi_handle_init_shared (struct _WapiHandleShared *handle,
300 gpointer handle_specific)
302 g_assert (_wapi_has_shut_down == FALSE);
305 handle->timestamp = (guint32)(time (NULL) & 0xFFFFFFFF);
306 handle->signalled = FALSE;
307 handle->handle_refs = 1;
309 if (handle_specific != NULL) {
310 memcpy (&handle->u, handle_specific, sizeof (handle->u));
314 static size_t _wapi_handle_struct_size (WapiHandleType type)
319 case WAPI_HANDLE_FILE: case WAPI_HANDLE_CONSOLE: case WAPI_HANDLE_PIPE:
320 type_size = sizeof (struct _WapiHandle_file);
322 case WAPI_HANDLE_THREAD:
323 type_size = sizeof (struct _WapiHandle_thread);
325 case WAPI_HANDLE_SEM:
326 type_size = sizeof (struct _WapiHandle_sem);
328 case WAPI_HANDLE_MUTEX:
329 type_size = sizeof (struct _WapiHandle_mutex);
331 case WAPI_HANDLE_EVENT:
332 type_size = sizeof (struct _WapiHandle_event);
334 case WAPI_HANDLE_SOCKET:
335 type_size = sizeof (struct _WapiHandle_socket);
337 case WAPI_HANDLE_FIND:
338 type_size = sizeof (struct _WapiHandle_find);
340 case WAPI_HANDLE_PROCESS:
341 type_size = sizeof (struct _WapiHandle_process);
343 case WAPI_HANDLE_NAMEDMUTEX:
344 type_size = sizeof (struct _WapiHandle_namedmutex);
346 case WAPI_HANDLE_NAMEDSEM:
347 type_size = sizeof (struct _WapiHandle_namedsem);
349 case WAPI_HANDLE_NAMEDEVENT:
350 type_size = sizeof (struct _WapiHandle_namedevent);
354 g_error ("Unknown WapiHandleType: %d\n", type);
360 static void _wapi_handle_init (struct _WapiHandleUnshared *handle,
361 WapiHandleType type, gpointer handle_specific)
366 g_assert (_wapi_has_shut_down == FALSE);
369 handle->signalled = FALSE;
372 if (!_WAPI_SHARED_HANDLE(type)) {
373 thr_ret = pthread_cond_init (&handle->signal_cond, NULL);
374 g_assert (thr_ret == 0);
376 thr_ret = mono_mutex_init (&handle->signal_mutex);
377 g_assert (thr_ret == 0);
379 if (handle_specific != NULL) {
380 type_size = _wapi_handle_struct_size (type);
381 memcpy (&handle->u, handle_specific,
387 static guint32 _wapi_handle_new_shared (WapiHandleType type,
388 gpointer handle_specific)
391 static guint32 last = 1;
394 g_assert (_wapi_has_shut_down == FALSE);
396 /* Leave the first slot empty as a guard */
398 /* FIXME: expandable array */
399 for(offset = last; offset <_WAPI_HANDLE_INITIAL_COUNT; offset++) {
400 struct _WapiHandleShared *handle = &_wapi_shared_layout->handles[offset];
402 if(handle->type == WAPI_HANDLE_UNUSED) {
403 thr_ret = _wapi_handle_lock_shared_handles ();
404 g_assert (thr_ret == 0);
406 if (InterlockedCompareExchange ((gint32 *)&handle->type, type, WAPI_HANDLE_UNUSED) == WAPI_HANDLE_UNUSED) {
409 _wapi_handle_init_shared (handle, type,
412 _wapi_handle_unlock_shared_handles ();
416 /* Someone else beat us to it, just
421 _wapi_handle_unlock_shared_handles ();
426 /* Try again from the beginning */
431 /* Will need to expand the array. The caller will sort it out */
437 * _wapi_handle_new_internal:
438 * @type: Init handle to this type
440 * Search for a free handle and initialize it. Return the handle on
441 * success and 0 on failure. This is only called from
442 * _wapi_handle_new, and scan_mutex must be held.
444 static guint32 _wapi_handle_new_internal (WapiHandleType type,
445 gpointer handle_specific)
448 static guint32 last = 0;
449 gboolean retry = FALSE;
451 g_assert (_wapi_has_shut_down == FALSE);
453 /* A linear scan should be fast enough. Start from the last
454 * allocation, assuming that handles are allocated more often
455 * than they're freed. Leave the space reserved for file
459 if (last < _wapi_fd_reserve) {
460 last = _wapi_fd_reserve;
467 for(i = SLOT_INDEX (count); i < _wapi_private_handle_slot_count; i++) {
468 if (_wapi_private_handles [i]) {
469 for (k = SLOT_OFFSET (count); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
470 struct _WapiHandleUnshared *handle = &_wapi_private_handles [i][k];
472 if(handle->type == WAPI_HANDLE_UNUSED) {
475 _wapi_handle_init (handle, type, handle_specific);
483 if(retry && last > _wapi_fd_reserve) {
484 /* Try again from the beginning */
485 last = _wapi_fd_reserve;
489 /* Will need to expand the array. The caller will sort it out */
495 _wapi_handle_new (WapiHandleType type, gpointer handle_specific)
497 guint32 handle_idx = 0;
501 g_assert (_wapi_has_shut_down == FALSE);
503 DEBUG ("%s: Creating new handle of type %s", __func__,
504 _wapi_handle_typename[type]);
506 g_assert(!_WAPI_FD_HANDLE(type));
508 thr_ret = mono_mutex_lock (&scan_mutex);
509 g_assert (thr_ret == 0);
511 while ((handle_idx = _wapi_handle_new_internal (type, handle_specific)) == 0) {
512 /* Try and expand the array, and have another go */
513 int idx = SLOT_INDEX (_wapi_private_handle_count);
514 if (idx >= _WAPI_PRIVATE_MAX_SLOTS) {
518 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
519 _WAPI_HANDLE_INITIAL_COUNT);
521 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
522 _wapi_private_handle_slot_count ++;
525 thr_ret = mono_mutex_unlock (&scan_mutex);
526 g_assert (thr_ret == 0);
528 if (handle_idx == 0) {
529 /* We ran out of slots */
530 handle = _WAPI_HANDLE_INVALID;
534 /* Make sure we left the space for fd mappings */
535 g_assert (handle_idx >= _wapi_fd_reserve);
537 handle = GUINT_TO_POINTER (handle_idx);
539 DEBUG ("%s: Allocated new handle %p", __func__, handle);
541 if (_WAPI_SHARED_HANDLE(type)) {
542 /* Add the shared section too */
545 ref = _wapi_handle_new_shared (type, handle_specific);
547 _wapi_handle_collect ();
548 ref = _wapi_handle_new_shared (type, handle_specific);
550 /* FIXME: grow the arrays */
551 handle = _WAPI_HANDLE_INVALID;
556 _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = ref;
557 DEBUG ("%s: New shared handle at offset 0x%x", __func__,
565 gpointer _wapi_handle_new_from_offset (WapiHandleType type, guint32 offset,
568 guint32 handle_idx = 0;
569 gpointer handle = INVALID_HANDLE_VALUE;
571 struct _WapiHandleShared *shared;
573 g_assert (_wapi_has_shut_down == FALSE);
575 DEBUG ("%s: Creating new handle of type %s to offset %d", __func__,
576 _wapi_handle_typename[type], offset);
578 g_assert(!_WAPI_FD_HANDLE(type));
579 g_assert(_WAPI_SHARED_HANDLE(type));
580 g_assert(offset != 0);
582 shared = &_wapi_shared_layout->handles[offset];
584 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
585 /* Bump up the timestamp for this offset */
586 InterlockedExchange ((gint32 *)&shared->timestamp, now);
589 thr_ret = mono_mutex_lock (&scan_mutex);
590 g_assert (thr_ret == 0);
592 for (i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
593 if (_wapi_private_handles [i]) {
594 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
595 struct _WapiHandleUnshared *handle_data = &_wapi_private_handles [i][k];
597 if (handle_data->type == type &&
598 handle_data->u.shared.offset == offset) {
599 handle = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
600 goto first_pass_done;
607 thr_ret = mono_mutex_unlock (&scan_mutex);
608 g_assert (thr_ret == 0);
610 if (handle != INVALID_HANDLE_VALUE) {
611 _wapi_handle_ref (handle);
613 DEBUG ("%s: Returning old handle %p referencing 0x%x",
614 __func__, handle, offset);
618 /* Prevent entries expiring under us as we search */
619 thr_ret = _wapi_handle_lock_shared_handles ();
620 g_assert (thr_ret == 0);
622 if (shared->type == WAPI_HANDLE_UNUSED) {
623 /* Someone deleted this handle while we were working */
624 DEBUG ("%s: Handle at 0x%x unused", __func__, offset);
628 if (shared->type != type) {
629 DEBUG ("%s: Wrong type at %d 0x%x! Found %s wanted %s",
630 __func__, offset, offset,
631 _wapi_handle_typename[shared->type],
632 _wapi_handle_typename[type]);
636 thr_ret = mono_mutex_lock (&scan_mutex);
637 g_assert (thr_ret == 0);
639 while ((handle_idx = _wapi_handle_new_internal (type, NULL)) == 0) {
640 /* Try and expand the array, and have another go */
641 int idx = SLOT_INDEX (_wapi_private_handle_count);
642 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
643 _WAPI_HANDLE_INITIAL_COUNT);
645 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
646 _wapi_private_handle_slot_count ++;
649 thr_ret = mono_mutex_unlock (&scan_mutex);
650 g_assert (thr_ret == 0);
652 /* Make sure we left the space for fd mappings */
653 g_assert (handle_idx >= _wapi_fd_reserve);
655 handle = GUINT_TO_POINTER (handle_idx);
657 _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = offset;
658 InterlockedIncrement ((gint32 *)&shared->handle_refs);
660 DEBUG ("%s: Allocated new handle %p referencing 0x%x (shared refs %d)", __func__, handle, offset, shared->handle_refs);
663 _wapi_handle_unlock_shared_handles ();
669 init_handles_slot (int idx)
673 thr_ret = mono_mutex_lock (&scan_mutex);
674 g_assert (thr_ret == 0);
676 if (_wapi_private_handles [idx] == NULL) {
677 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
678 _WAPI_HANDLE_INITIAL_COUNT);
679 g_assert (_wapi_private_handles [idx]);
682 thr_ret = mono_mutex_unlock (&scan_mutex);
683 g_assert (thr_ret == 0);
686 gpointer _wapi_handle_new_fd (WapiHandleType type, int fd,
687 gpointer handle_specific)
689 struct _WapiHandleUnshared *handle;
692 g_assert (_wapi_has_shut_down == FALSE);
694 DEBUG ("%s: Creating new handle of type %s", __func__,
695 _wapi_handle_typename[type]);
697 g_assert(_WAPI_FD_HANDLE(type));
698 g_assert(!_WAPI_SHARED_HANDLE(type));
700 if (fd >= _wapi_fd_reserve) {
701 DEBUG ("%s: fd %d is too big", __func__, fd);
703 return(GUINT_TO_POINTER (_WAPI_HANDLE_INVALID));
706 /* Initialize the array entries on demand */
707 if (_wapi_private_handles [SLOT_INDEX (fd)] == NULL)
708 init_handles_slot (SLOT_INDEX (fd));
710 handle = &_WAPI_PRIVATE_HANDLES(fd);
712 if (handle->type != WAPI_HANDLE_UNUSED) {
713 DEBUG ("%s: fd %d is already in use!", __func__, fd);
714 /* FIXME: clean up this handle? We can't do anything
715 * with the fd, cos thats the new one
719 DEBUG ("%s: Assigning new fd handle %d", __func__, fd);
721 /* Prevent file share entries racing with us, when the file
722 * handle is only half initialised
724 thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
725 g_assert(thr_ret == 0);
727 _wapi_handle_init (handle, type, handle_specific);
729 thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
731 return(GUINT_TO_POINTER(fd));
734 gboolean _wapi_lookup_handle (gpointer handle, WapiHandleType type,
735 gpointer *handle_specific)
737 struct _WapiHandleUnshared *handle_data;
738 guint32 handle_idx = GPOINTER_TO_UINT(handle);
740 if (!_WAPI_PRIVATE_VALID_SLOT (handle_idx)) {
744 /* Initialize the array entries on demand */
745 if (_wapi_private_handles [SLOT_INDEX (handle_idx)] == NULL)
746 init_handles_slot (SLOT_INDEX (handle_idx));
748 handle_data = &_WAPI_PRIVATE_HANDLES(handle_idx);
750 if (handle_data->type != type) {
754 if (handle_specific == NULL) {
758 if (_WAPI_SHARED_HANDLE(type)) {
759 struct _WapiHandle_shared_ref *ref;
760 struct _WapiHandleShared *shared_handle_data;
762 ref = &handle_data->u.shared;
763 shared_handle_data = &_wapi_shared_layout->handles[ref->offset];
765 if (shared_handle_data->type != type) {
766 /* The handle must have been deleted on us
771 *handle_specific = &shared_handle_data->u;
773 *handle_specific = &handle_data->u;
780 _wapi_handle_foreach (WapiHandleType type,
781 gboolean (*on_each)(gpointer test, gpointer user),
784 struct _WapiHandleUnshared *handle_data = NULL;
789 thr_ret = mono_mutex_lock (&scan_mutex);
790 g_assert (thr_ret == 0);
792 for (i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
793 if (_wapi_private_handles [i]) {
794 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
795 handle_data = &_wapi_private_handles [i][k];
797 if (handle_data->type == type) {
798 ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
799 if (on_each (ret, user_data) == TRUE)
806 thr_ret = mono_mutex_unlock (&scan_mutex);
807 g_assert (thr_ret == 0);
810 /* This might list some shared handles twice if they are already
811 * opened by this process, and the check function returns FALSE the
812 * first time. Shared handles that are created during the search are
813 * unreffed if the check function returns FALSE, so callers must not
814 * rely on the handle persisting (unless the check function returns
816 * The caller owns the returned handle.
818 gpointer _wapi_search_handle (WapiHandleType type,
819 gboolean (*check)(gpointer test, gpointer user),
821 gpointer *handle_specific,
822 gboolean search_shared)
824 struct _WapiHandleUnshared *handle_data = NULL;
825 struct _WapiHandleShared *shared = NULL;
828 gboolean found = FALSE;
831 thr_ret = mono_mutex_lock (&scan_mutex);
832 g_assert (thr_ret == 0);
834 for (i = SLOT_INDEX (0); !found && i < _wapi_private_handle_slot_count; i++) {
835 if (_wapi_private_handles [i]) {
836 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
837 handle_data = &_wapi_private_handles [i][k];
839 if (handle_data->type == type) {
840 ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
841 if (check (ret, user_data) == TRUE) {
842 _wapi_handle_ref (ret);
845 if (_WAPI_SHARED_HANDLE (type)) {
846 shared = &_wapi_shared_layout->handles[i];
856 thr_ret = mono_mutex_unlock (&scan_mutex);
857 g_assert (thr_ret == 0);
859 if (!found && search_shared && _WAPI_SHARED_HANDLE (type)) {
860 /* Not found yet, so search the shared memory too */
861 DEBUG ("%s: Looking at other shared handles...", __func__);
863 for (i = 0; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
864 shared = &_wapi_shared_layout->handles[i];
866 if (shared->type == type) {
867 /* Tell new_from_offset to not
868 * timestamp this handle, because
869 * otherwise it will ping every handle
870 * in the list and they will never
873 ret = _wapi_handle_new_from_offset (type, i,
875 if (ret == INVALID_HANDLE_VALUE) {
876 /* This handle was deleted
877 * while we were looking at it
882 DEBUG ("%s: Opened tmp handle %p (type %s) from offset %d", __func__, ret, _wapi_handle_typename[type], i);
884 /* It's possible that the shared part
885 * of this handle has now been blown
886 * away (after new_from_offset
887 * successfully opened it,) if its
888 * timestamp is too old. The check
889 * function needs to be aware of this,
890 * and cope if the handle has
893 if (check (ret, user_data) == TRUE) {
894 /* Timestamp this handle, but make
895 * sure it still exists first
897 thr_ret = _wapi_handle_lock_shared_handles ();
898 g_assert (thr_ret == 0);
900 if (shared->type == type) {
901 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
902 InterlockedExchange ((gint32 *)&shared->timestamp, now);
905 handle_data = &_WAPI_PRIVATE_HANDLES(GPOINTER_TO_UINT(ret));
907 _wapi_handle_unlock_shared_handles ();
910 /* It's been deleted,
914 _wapi_handle_unlock_shared_handles ();
918 /* This isn't the handle we're looking
919 * for, so drop the reference we took
920 * in _wapi_handle_new_from_offset ()
922 _wapi_handle_unref (ret);
932 if(handle_specific != NULL) {
933 if (_WAPI_SHARED_HANDLE(type)) {
934 g_assert(shared->type == type);
936 *handle_specific = &shared->u;
938 *handle_specific = &handle_data->u;
946 /* Returns the offset of the metadata array, or -1 on error, or 0 for
947 * not found (0 is not a valid offset)
949 gint32 _wapi_search_handle_namespace (WapiHandleType type,
952 struct _WapiHandleShared *shared_handle_data;
957 g_assert(_WAPI_SHARED_HANDLE(type));
959 DEBUG ("%s: Lookup for handle named [%s] type %s", __func__,
960 utf8_name, _wapi_handle_typename[type]);
962 /* Do a handle collection before starting to look, so that any
963 * stale cruft gets removed
965 _wapi_handle_collect ();
967 thr_ret = _wapi_handle_lock_shared_handles ();
968 g_assert (thr_ret == 0);
970 for(i = 1; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
971 WapiSharedNamespace *sharedns;
973 shared_handle_data = &_wapi_shared_layout->handles[i];
975 /* Check mutex, event, semaphore, timer, job and
976 * file-mapping object names. So far only mutex,
977 * semaphore and event are implemented.
979 if (!_WAPI_SHARED_NAMESPACE (shared_handle_data->type)) {
983 DEBUG ("%s: found a shared namespace handle at 0x%x (type %s)", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
985 sharedns=(WapiSharedNamespace *)&shared_handle_data->u;
987 DEBUG ("%s: name is [%s]", __func__, sharedns->name);
989 if (strcmp (sharedns->name, utf8_name) == 0) {
990 if (shared_handle_data->type != type) {
991 /* Its the wrong type, so fail now */
992 DEBUG ("%s: handle 0x%x matches name but is wrong type: %s", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
996 DEBUG ("%s: handle 0x%x matches name and type", __func__, i);
1004 _wapi_handle_unlock_shared_handles ();
1009 void _wapi_handle_ref (gpointer handle)
1011 guint32 idx = GPOINTER_TO_UINT(handle);
1012 struct _WapiHandleUnshared *handle_data;
1014 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1018 if (_wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) {
1019 g_warning ("%s: Attempting to ref unused handle %p", __func__,
1024 handle_data = &_WAPI_PRIVATE_HANDLES(idx);
1026 InterlockedIncrement ((gint32 *)&handle_data->ref);
1028 /* It's possible for processes to exit before getting around
1029 * to updating timestamps in the collection thread, so if a
1030 * shared handle is reffed do the timestamp here as well just
1033 if (_WAPI_SHARED_HANDLE(handle_data->type)) {
1034 struct _WapiHandleShared *shared_data = &_wapi_shared_layout->handles[handle_data->u.shared.offset];
1035 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
1036 InterlockedExchange ((gint32 *)&shared_data->timestamp, now);
1040 g_message ("%s: %s handle %p ref now %d", __func__,
1041 _wapi_handle_typename[_WAPI_PRIVATE_HANDLES (idx).type],
1043 _WAPI_PRIVATE_HANDLES(idx).ref);
1047 /* The handle must not be locked on entry to this function */
1048 static void _wapi_handle_unref_full (gpointer handle, gboolean ignore_private_busy_handles)
1050 guint32 idx = GPOINTER_TO_UINT(handle);
1051 gboolean destroy = FALSE, early_exit = FALSE;
1054 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1058 if (_wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) {
1059 g_warning ("%s: Attempting to unref unused handle %p",
1064 /* Possible race condition here if another thread refs the
1065 * handle between here and setting the type to UNUSED. I
1066 * could lock a mutex, but I'm not sure that allowing a handle
1067 * reference to reach 0 isn't an application bug anyway.
1069 destroy = (InterlockedDecrement ((gint32 *)&_WAPI_PRIVATE_HANDLES(idx).ref) ==0);
1072 g_message ("%s: %s handle %p ref now %d (destroy %s)", __func__,
1073 _wapi_handle_typename[_WAPI_PRIVATE_HANDLES (idx).type],
1075 _WAPI_PRIVATE_HANDLES(idx).ref, destroy?"TRUE":"FALSE");
1079 /* Need to copy the handle info, reset the slot in the
1080 * array, and _only then_ call the close function to
1081 * avoid race conditions (eg file descriptors being
1082 * closed, and another file being opened getting the
1083 * same fd racing the memset())
1085 struct _WapiHandleUnshared handle_data;
1086 struct _WapiHandleShared shared_handle_data;
1087 WapiHandleType type = _WAPI_PRIVATE_HANDLES(idx).type;
1088 void (*close_func)(gpointer, gpointer) = _wapi_handle_ops_get_close_func (type);
1089 gboolean is_shared = _WAPI_SHARED_HANDLE(type);
1092 /* If this is a shared handle we need to take
1093 * the shared lock outside of the scan_mutex
1094 * lock to avoid deadlocks
1096 thr_ret = _wapi_handle_lock_shared_handles ();
1097 g_assert (thr_ret == 0);
1100 thr_ret = mono_mutex_lock (&scan_mutex);
1102 DEBUG ("%s: Destroying handle %p", __func__, handle);
1104 memcpy (&handle_data, &_WAPI_PRIVATE_HANDLES(idx),
1105 sizeof (struct _WapiHandleUnshared));
1107 memset (&_WAPI_PRIVATE_HANDLES(idx).u, '\0',
1108 sizeof(_WAPI_PRIVATE_HANDLES(idx).u));
1110 _WAPI_PRIVATE_HANDLES(idx).type = WAPI_HANDLE_UNUSED;
1113 /* Destroy the mutex and cond var. We hope nobody
1114 * tried to grab them between the handle unlock and
1115 * now, but pthreads doesn't have a
1116 * "unlock_and_destroy" atomic function.
1118 thr_ret = mono_mutex_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_mutex);
1119 /*WARNING gross hack to make cleanup not crash when exiting without the whole runtime teardown.*/
1120 if (thr_ret == EBUSY && ignore_private_busy_handles) {
1124 g_error ("Error destroying handle %p mutex due to %d\n", handle, thr_ret);
1126 thr_ret = pthread_cond_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_cond);
1127 if (thr_ret == EBUSY && ignore_private_busy_handles)
1129 else if (thr_ret != 0)
1130 g_error ("Error destroying handle %p cond var due to %d\n", handle, thr_ret);
1133 struct _WapiHandleShared *shared = &_wapi_shared_layout->handles[handle_data.u.shared.offset];
1135 memcpy (&shared_handle_data, shared,
1136 sizeof (struct _WapiHandleShared));
1138 /* It's possible that this handle is already
1139 * pointing at a deleted shared section
1142 g_message ("%s: %s handle %p shared refs before dec %d", __func__, _wapi_handle_typename[type], handle, shared->handle_refs);
1145 if (shared->handle_refs > 0) {
1146 shared->handle_refs--;
1147 if (shared->handle_refs == 0) {
1148 memset (shared, '\0', sizeof (struct _WapiHandleShared));
1153 thr_ret = mono_mutex_unlock (&scan_mutex);
1154 g_assert (thr_ret == 0);
1159 _wapi_handle_unlock_shared_handles ();
1162 if (close_func != NULL) {
1164 close_func (handle, &shared_handle_data.u);
1166 close_func (handle, &handle_data.u);
1172 void _wapi_handle_unref (gpointer handle)
1174 _wapi_handle_unref_full (handle, FALSE);
1177 void _wapi_handle_register_capabilities (WapiHandleType type,
1178 WapiHandleCapability caps)
1180 handle_caps[type] = caps;
1183 gboolean _wapi_handle_test_capabilities (gpointer handle,
1184 WapiHandleCapability caps)
1186 guint32 idx = GPOINTER_TO_UINT(handle);
1187 WapiHandleType type;
1189 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1193 type = _WAPI_PRIVATE_HANDLES(idx).type;
1195 DEBUG ("%s: testing 0x%x against 0x%x (%d)", __func__,
1196 handle_caps[type], caps, handle_caps[type] & caps);
1198 return((handle_caps[type] & caps) != 0);
1201 static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer)
1203 if (handle_ops[type] != NULL &&
1204 handle_ops[type]->close != NULL) {
1205 return (handle_ops[type]->close);
1211 void _wapi_handle_ops_close (gpointer handle, gpointer data)
1213 guint32 idx = GPOINTER_TO_UINT(handle);
1214 WapiHandleType type;
1216 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1220 type = _WAPI_PRIVATE_HANDLES(idx).type;
1222 if (handle_ops[type] != NULL &&
1223 handle_ops[type]->close != NULL) {
1224 handle_ops[type]->close (handle, data);
1228 void _wapi_handle_ops_signal (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]->signal != NULL) {
1240 handle_ops[type]->signal (handle);
1244 gboolean _wapi_handle_ops_own (gpointer handle)
1246 guint32 idx = GPOINTER_TO_UINT(handle);
1247 WapiHandleType type;
1249 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1253 type = _WAPI_PRIVATE_HANDLES(idx).type;
1255 if (handle_ops[type] != NULL && handle_ops[type]->own_handle != NULL) {
1256 return(handle_ops[type]->own_handle (handle));
1262 gboolean _wapi_handle_ops_isowned (gpointer handle)
1264 guint32 idx = GPOINTER_TO_UINT(handle);
1265 WapiHandleType type;
1267 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1271 type = _WAPI_PRIVATE_HANDLES(idx).type;
1273 if (handle_ops[type] != NULL && handle_ops[type]->is_owned != NULL) {
1274 return(handle_ops[type]->is_owned (handle));
1280 guint32 _wapi_handle_ops_special_wait (gpointer handle, guint32 timeout, gboolean alertable)
1282 guint32 idx = GPOINTER_TO_UINT(handle);
1283 WapiHandleType type;
1285 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1286 return(WAIT_FAILED);
1289 type = _WAPI_PRIVATE_HANDLES(idx).type;
1291 if (handle_ops[type] != NULL &&
1292 handle_ops[type]->special_wait != NULL) {
1293 return(handle_ops[type]->special_wait (handle, timeout, alertable));
1295 return(WAIT_FAILED);
1299 void _wapi_handle_ops_prewait (gpointer handle)
1301 guint32 idx = GPOINTER_TO_UINT (handle);
1302 WapiHandleType type;
1304 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1308 type = _WAPI_PRIVATE_HANDLES (idx).type;
1310 if (handle_ops[type] != NULL &&
1311 handle_ops[type]->prewait != NULL) {
1312 handle_ops[type]->prewait (handle);
1319 * @handle: The handle to release
1321 * Closes and invalidates @handle, releasing any resources it
1322 * consumes. When the last handle to a temporary or non-persistent
1323 * object is closed, that object can be deleted. Closing the same
1324 * handle twice is an error.
1326 * Return value: %TRUE on success, %FALSE otherwise.
1328 gboolean CloseHandle(gpointer handle)
1330 if (handle == NULL) {
1331 /* Problem: because we map file descriptors to the
1332 * same-numbered handle we can't tell the difference
1333 * between a bogus handle and the handle to stdin.
1334 * Assume that it's the console handle if that handle
1337 if (_WAPI_PRIVATE_HANDLES (0).type != WAPI_HANDLE_CONSOLE) {
1338 SetLastError (ERROR_INVALID_PARAMETER);
1342 if (handle == _WAPI_HANDLE_INVALID){
1343 SetLastError (ERROR_INVALID_PARAMETER);
1347 _wapi_handle_unref (handle);
1352 /* Lots more to implement here, but this is all we need at the moment */
1353 gboolean DuplicateHandle (gpointer srcprocess, gpointer src,
1354 gpointer targetprocess, gpointer *target,
1355 guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, guint32 options G_GNUC_UNUSED)
1357 if (srcprocess != _WAPI_PROCESS_CURRENT ||
1358 targetprocess != _WAPI_PROCESS_CURRENT) {
1359 /* Duplicating other process's handles is not supported */
1360 SetLastError (ERROR_INVALID_HANDLE);
1364 if (src == _WAPI_PROCESS_CURRENT) {
1365 *target = _wapi_process_duplicate ();
1366 } else if (src == _WAPI_THREAD_CURRENT) {
1367 g_assert_not_reached ();
1369 _wapi_handle_ref (src);
1376 gboolean _wapi_handle_count_signalled_handles (guint32 numhandles,
1382 guint32 count, i, iter=0;
1385 WapiHandleType type;
1387 /* Lock all the handles, with backoff */
1389 thr_ret = _wapi_handle_lock_shared_handles ();
1390 g_assert (thr_ret == 0);
1392 for(i=0; i<numhandles; i++) {
1393 gpointer handle = handles[i];
1394 guint32 idx = GPOINTER_TO_UINT(handle);
1396 DEBUG ("%s: attempting to lock %p", __func__, handle);
1398 type = _WAPI_PRIVATE_HANDLES(idx).type;
1400 thr_ret = _wapi_handle_trylock_handle (handle);
1405 DEBUG ("%s: attempt failed for %p: %s", __func__,
1406 handle, strerror (thr_ret));
1408 thr_ret = _wapi_handle_unlock_shared_handles ();
1409 g_assert (thr_ret == 0);
1412 handle = handles[i];
1413 idx = GPOINTER_TO_UINT(handle);
1415 thr_ret = _wapi_handle_unlock_handle (handle);
1416 g_assert (thr_ret == 0);
1419 /* If iter ever reaches 100 the nanosleep will
1420 * return EINVAL immediately, but we have a
1421 * design flaw if that happens.
1425 g_warning ("%s: iteration overflow!",
1430 DEBUG ("%s: Backing off for %d ms", __func__,
1432 _wapi_handle_spin (10 * iter);
1438 DEBUG ("%s: Locked all handles", __func__);
1443 for(i=0; i<numhandles; i++) {
1444 gpointer handle = handles[i];
1445 guint32 idx = GPOINTER_TO_UINT(handle);
1447 type = _WAPI_PRIVATE_HANDLES(idx).type;
1449 DEBUG ("%s: Checking handle %p", __func__, handle);
1451 if(((_wapi_handle_test_capabilities (handle, WAPI_HANDLE_CAP_OWN)==TRUE) &&
1452 (_wapi_handle_ops_isowned (handle) == TRUE)) ||
1453 (_WAPI_SHARED_HANDLE(type) &&
1454 WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) ||
1455 (!_WAPI_SHARED_HANDLE(type) &&
1456 _WAPI_PRIVATE_HANDLES(idx).signalled == TRUE)) {
1459 DEBUG ("%s: Handle %p signalled", __func__,
1467 DEBUG ("%s: %d event handles signalled", __func__, count);
1469 if ((waitall == TRUE && count == numhandles) ||
1470 (waitall == FALSE && count > 0)) {
1476 DEBUG ("%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];
1494 DEBUG ("%s: unlocking handle %p", __func__, handle);
1496 thr_ret = _wapi_handle_unlock_handle (handle);
1497 g_assert (thr_ret == 0);
1501 static int timedwait_signal_poll_cond (pthread_cond_t *cond, mono_mutex_t *mutex, struct timespec *timeout, gboolean alertable)
1503 struct timespec fake_timeout;
1508 * pthread_cond_(timed)wait() can return 0 even if the condition was not
1509 * signalled. This happens at least on Darwin. We surface this, i.e., we
1510 * get spurious wake-ups.
1512 * http://pubs.opengroup.org/onlinepubs/007908775/xsh/pthread_cond_wait.html
1515 ret=mono_cond_timedwait (cond, mutex, timeout);
1517 ret=mono_cond_wait (cond, mutex);
1519 _wapi_calc_timeout (&fake_timeout, 100);
1521 if (timeout != NULL && ((fake_timeout.tv_sec > timeout->tv_sec) ||
1522 (fake_timeout.tv_sec == timeout->tv_sec &&
1523 fake_timeout.tv_nsec > timeout->tv_nsec))) {
1524 /* Real timeout is less than 100ms time */
1525 ret=mono_cond_timedwait (cond, mutex, timeout);
1527 ret=mono_cond_timedwait (cond, mutex, &fake_timeout);
1529 /* Mask the fake timeout, this will cause
1530 * another poll if the cond was not really signaled
1532 if (ret==ETIMEDOUT) {
1542 _wapi_handle_timedwait_signal (struct timespec *timeout, gboolean poll, gboolean *alerted)
1544 return _wapi_handle_timedwait_signal_handle (_wapi_global_signal_handle, timeout, TRUE, poll, alerted);
1548 signal_handle_and_unref (gpointer handle)
1550 pthread_cond_t *cond;
1551 mono_mutex_t *mutex;
1556 /* If we reach here, then interrupt token is set to the flag value, which
1557 * means that the target thread is either
1558 * - before the first CAS in timedwait, which means it won't enter the wait.
1559 * - it is after the first CAS, so it is already waiting, or it will enter
1560 * the wait, and it will be interrupted by the broadcast. */
1561 idx = GPOINTER_TO_UINT (handle);
1562 cond = &_WAPI_PRIVATE_HANDLES (idx).signal_cond;
1563 mutex = &_WAPI_PRIVATE_HANDLES (idx).signal_mutex;
1565 mono_mutex_lock (mutex);
1566 mono_cond_broadcast (cond);
1567 mono_mutex_unlock (mutex);
1569 _wapi_handle_unref (handle);
1573 _wapi_handle_timedwait_signal_handle (gpointer handle, struct timespec *timeout,
1574 gboolean alertable, gboolean poll, gboolean *alerted)
1576 DEBUG ("%s: waiting for %p (type %s)", __func__, handle,
1577 _wapi_handle_typename[_wapi_handle_type (handle)]);
1585 if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
1586 if (WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) {
1589 if (timeout != NULL) {
1590 struct timespec fake_timeout;
1591 _wapi_calc_timeout (&fake_timeout, 100);
1593 if ((fake_timeout.tv_sec > timeout->tv_sec) ||
1594 (fake_timeout.tv_sec == timeout->tv_sec &&
1595 fake_timeout.tv_nsec > timeout->tv_nsec)) {
1596 /* FIXME: Real timeout is less than
1597 * 100ms time, but is it really worth
1598 * calculating to the exact ms?
1600 _wapi_handle_spin (100);
1602 if (WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) {
1609 _wapi_handle_spin (100);
1613 guint32 idx = GPOINTER_TO_UINT(handle);
1615 pthread_cond_t *cond;
1616 mono_mutex_t *mutex;
1619 mono_thread_info_install_interrupt (signal_handle_and_unref, handle, alerted);
1622 _wapi_handle_ref (handle);
1625 cond = &_WAPI_PRIVATE_HANDLES (idx).signal_cond;
1626 mutex = &_WAPI_PRIVATE_HANDLES (idx).signal_mutex;
1629 /* This is needed when waiting for process handles */
1630 res = timedwait_signal_poll_cond (cond, mutex, timeout, alertable);
1633 res = mono_cond_timedwait (cond, mutex, timeout);
1635 res = mono_cond_wait (cond, mutex);
1639 mono_thread_info_uninstall_interrupt (alerted);
1641 /* if it is alerted, then the handle is unref in the interrupt callback */
1642 _wapi_handle_unref (handle);
1651 _wapi_free_share_info (_WapiFileShare *share_info)
1653 if (!_wapi_shm_enabled ()) {
1654 file_share_hash_lock ();
1655 g_hash_table_remove (file_share_hash, share_info);
1656 file_share_hash_unlock ();
1657 /* The hashtable dtor frees share_info */
1659 memset (share_info, '\0', sizeof(struct _WapiFileShare));
1664 wapi_share_info_equal (gconstpointer ka, gconstpointer kb)
1666 const _WapiFileShare *s1 = ka;
1667 const _WapiFileShare *s2 = kb;
1669 return (s1->device == s2->device && s1->inode == s2->inode) ? 1 : 0;
1673 wapi_share_info_hash (gconstpointer data)
1675 const _WapiFileShare *s = data;
1680 gboolean _wapi_handle_get_or_set_share (guint64 device, guint64 inode,
1681 guint32 new_sharemode,
1683 guint32 *old_sharemode,
1684 guint32 *old_access,
1685 struct _WapiFileShare **share_info)
1687 struct _WapiFileShare *file_share;
1688 guint32 now = (guint32)(time(NULL) & 0xFFFFFFFF);
1689 int thr_ret, i, first_unused = -1;
1690 gboolean exists = FALSE;
1692 /* Prevents entries from expiring under us as we search
1694 thr_ret = _wapi_handle_lock_shared_handles ();
1695 g_assert (thr_ret == 0);
1697 /* Prevent new entries racing with us */
1698 thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1699 g_assert (thr_ret == 0);
1701 if (!_wapi_shm_enabled ()) {
1705 * Instead of allocating a 4MB array, we use a hash table to keep track of this
1706 * info. This is needed even if SHM is disabled, to track sharing inside
1707 * the current process.
1709 if (!file_share_hash) {
1710 file_share_hash = g_hash_table_new_full (wapi_share_info_hash, wapi_share_info_equal, NULL, g_free);
1711 mono_mutex_init_recursive (&file_share_hash_mutex);
1714 tmp.device = device;
1717 file_share_hash_lock ();
1719 file_share = g_hash_table_lookup (file_share_hash, &tmp);
1721 *old_sharemode = file_share->sharemode;
1722 *old_access = file_share->access;
1723 *share_info = file_share;
1725 InterlockedIncrement ((gint32 *)&file_share->handle_refs);
1728 file_share = g_new0 (_WapiFileShare, 1);
1730 file_share->device = device;
1731 file_share->inode = inode;
1732 file_share->opened_by_pid = _wapi_getpid ();
1733 file_share->sharemode = new_sharemode;
1734 file_share->access = new_access;
1735 file_share->handle_refs = 1;
1736 *share_info = file_share;
1738 g_hash_table_insert (file_share_hash, file_share, file_share);
1741 file_share_hash_unlock ();
1743 /* If a linear scan gets too slow we'll have to fit a hash
1744 * table onto the shared mem backing store
1747 for (i = 0; i <= _wapi_fileshare_layout->hwm; i++) {
1748 file_share = &_wapi_fileshare_layout->share_info[i];
1750 /* Make a note of an unused slot, in case we need to
1753 if (first_unused == -1 && file_share->handle_refs == 0) {
1758 if (file_share->handle_refs == 0) {
1762 if (file_share->device == device &&
1763 file_share->inode == inode) {
1764 *old_sharemode = file_share->sharemode;
1765 *old_access = file_share->access;
1766 *share_info = file_share;
1768 /* Increment the reference count while we
1769 * still have sole access to the shared area.
1770 * This makes the increment atomic wrt
1773 InterlockedIncrement ((gint32 *)&file_share->handle_refs);
1781 if (i == _WAPI_FILESHARE_SIZE && first_unused == -1) {
1784 if (first_unused == -1) {
1785 file_share = &_wapi_fileshare_layout->share_info[++i];
1786 _wapi_fileshare_layout->hwm = i;
1788 file_share = &_wapi_fileshare_layout->share_info[first_unused];
1791 file_share->device = device;
1792 file_share->inode = inode;
1793 file_share->opened_by_pid = _wapi_getpid ();
1794 file_share->sharemode = new_sharemode;
1795 file_share->access = new_access;
1796 file_share->handle_refs = 1;
1797 *share_info = file_share;
1801 if (*share_info != NULL) {
1802 InterlockedExchange ((gint32 *)&(*share_info)->timestamp, now);
1806 thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1808 _wapi_handle_unlock_shared_handles ();
1813 /* If we don't have the info in /proc, check if the process that
1814 * opened this share info is still there (it's not a perfect method,
1817 static void _wapi_handle_check_share_by_pid (struct _WapiFileShare *share_info)
1819 #if defined(__native_client__)
1820 g_assert_not_reached ();
1821 #elif defined(HAVE_KILL)
1822 if (kill (share_info->opened_by_pid, 0) == -1 &&
1825 /* It's gone completely (or there's a new process
1826 * owned by someone else) so mark this share info as
1829 DEBUG ("%s: Didn't find it, destroying entry", __func__);
1831 _wapi_free_share_info (share_info);
1837 /* Scan /proc/<pids>/fd/ for open file descriptors to the file in
1838 * question. If there are none, reset the share info.
1840 * This implementation is Linux-specific; legacy systems will have to
1841 * implement their own ways of finding out if a particular file is
1842 * open by a process.
1844 void _wapi_handle_check_share (struct _WapiFileShare *share_info, int fd)
1846 gboolean found = FALSE, proc_fds = FALSE;
1849 /* Prevents entries from expiring under us if we remove this
1852 thr_ret = _wapi_handle_lock_shared_handles ();
1853 g_assert (thr_ret == 0);
1855 /* Prevent new entries racing with us */
1856 thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1857 g_assert (thr_ret == 0);
1859 /* If there is no /proc, there's nothing more we can do here */
1860 if (access ("/proc", F_OK) == -1) {
1861 _wapi_handle_check_share_by_pid (share_info);
1865 /* If there's another handle that thinks it owns this fd, then even
1866 * if the fd has been closed behind our back consider it still owned.
1867 * See bugs 75764 and 75891
1869 for (i = 0; i < _wapi_fd_reserve; i++) {
1870 if (_wapi_private_handles [SLOT_INDEX (i)]) {
1871 struct _WapiHandleUnshared *handle = &_WAPI_PRIVATE_HANDLES(i);
1874 handle->type == WAPI_HANDLE_FILE) {
1875 struct _WapiHandle_file *file_handle = &handle->u.file;
1877 if (file_handle->share_info == share_info) {
1878 DEBUG ("%s: handle 0x%x has this file open!",
1887 if (proc_fds == FALSE) {
1888 _wapi_handle_check_share_by_pid (share_info);
1889 } else if (found == FALSE) {
1890 /* Blank out this entry, as it is stale */
1891 DEBUG ("%s: Didn't find it, destroying entry", __func__);
1893 _wapi_free_share_info (share_info);
1897 thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1899 _wapi_handle_unlock_shared_handles ();
1903 // Other implementations (non-Linux)
1905 void _wapi_handle_check_share (struct _WapiFileShare *share_info, int fd)
1909 /* Prevents entries from expiring under us if we remove this
1911 thr_ret = _wapi_handle_lock_shared_handles ();
1912 g_assert (thr_ret == 0);
1914 /* Prevent new entries racing with us */
1915 thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1916 g_assert (thr_ret == 0);
1918 _wapi_handle_check_share_by_pid (share_info);
1920 thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1921 _wapi_handle_unlock_shared_handles ();
1925 void _wapi_handle_dump (void)
1927 struct _WapiHandleUnshared *handle_data;
1931 thr_ret = mono_mutex_lock (&scan_mutex);
1932 g_assert (thr_ret == 0);
1934 for(i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
1935 if (_wapi_private_handles [i]) {
1936 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
1937 handle_data = &_wapi_private_handles [i][k];
1939 if (handle_data->type == WAPI_HANDLE_UNUSED) {
1943 g_print ("%3x [%7s] %s %d ",
1944 i * _WAPI_HANDLE_INITIAL_COUNT + k,
1945 _wapi_handle_typename[handle_data->type],
1946 handle_data->signalled?"Sg":"Un",
1948 if (handle_details[handle_data->type])
1949 handle_details[handle_data->type](&handle_data->u);
1955 thr_ret = mono_mutex_unlock (&scan_mutex);
1956 g_assert (thr_ret == 0);
1959 static void _wapi_shared_details (gpointer handle_info)
1961 struct _WapiHandle_shared_ref *shared = (struct _WapiHandle_shared_ref *)handle_info;
1963 g_print ("offset: 0x%x", shared->offset);
1966 void _wapi_handle_update_refs (void)
1970 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
1972 thr_ret = _wapi_handle_lock_shared_handles ();
1973 g_assert (thr_ret == 0);
1975 /* Prevent file share entries racing with us */
1976 thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1977 g_assert(thr_ret == 0);
1979 thr_ret = mono_mutex_lock (&scan_mutex);
1981 for(i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
1982 if (_wapi_private_handles [i]) {
1983 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
1984 struct _WapiHandleUnshared *handle = &_wapi_private_handles [i][k];
1986 if (_WAPI_SHARED_HANDLE(handle->type)) {
1987 struct _WapiHandleShared *shared_data;
1989 DEBUG ("%s: (%d) handle 0x%x is SHARED (%s)", __func__, _wapi_getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k, _wapi_handle_typename[handle->type]);
1991 shared_data = &_wapi_shared_layout->handles[handle->u.shared.offset];
1993 DEBUG ("%s: (%d) Updating timestamp of handle 0x%x", __func__, _wapi_getpid (), handle->u.shared.offset);
1995 InterlockedExchange ((gint32 *)&shared_data->timestamp, now);
1996 } else if (handle->type == WAPI_HANDLE_FILE) {
1997 struct _WapiHandle_file *file_handle = &handle->u.file;
1999 DEBUG ("%s: (%d) handle 0x%x is FILE", __func__, _wapi_getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k);
2001 g_assert (file_handle->share_info != NULL);
2003 DEBUG ("%s: (%d) Inc refs on fileshare 0x%x", __func__, _wapi_getpid (), (file_handle->share_info - &_wapi_fileshare_layout->share_info[0]) / sizeof(struct _WapiFileShare));
2005 InterlockedExchange ((gint32 *)&file_handle->share_info->timestamp, now);
2011 thr_ret = mono_mutex_unlock (&scan_mutex);
2012 g_assert (thr_ret == 0);
2014 thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
2016 _wapi_handle_unlock_shared_handles ();