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
18 #include <sys/types.h>
19 #ifdef HAVE_SYS_SOCKET_H
20 # include <sys/socket.h>
25 #ifdef HAVE_SYS_MMAN_H
26 # include <sys/mman.h>
32 #ifdef HAVE_SYS_RESOURCE_H
33 # include <sys/resource.h>
36 #include <mono/io-layer/wapi.h>
37 #include <mono/io-layer/wapi-private.h>
38 #include <mono/io-layer/handles-private.h>
39 #include <mono/io-layer/misc-private.h>
40 #include <mono/io-layer/shared.h>
41 #include <mono/io-layer/collection.h>
42 #include <mono/io-layer/process-private.h>
44 #include <mono/utils/mono-mutex.h>
48 #define DEBUG(...) g_message(__VA_ARGS__)
53 static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer);
55 static WapiHandleCapability handle_caps[WAPI_HANDLE_COUNT]={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 enabled, this will point to shared memory, otherwise it will be NULL.
128 struct _WapiFileShareLayout *_wapi_fileshare_layout = NULL;
131 * If SHM is disabled, this will point to a hash of _WapiFileShare structures, otherwise
132 * it will be NULL. We use this instead of _wapi_fileshare_layout to avoid allocating a
135 static GHashTable *file_share_hash;
136 static mono_mutex_t file_share_hash_mutex;
138 #define file_share_hash_lock() mono_mutex_lock (&file_share_hash_mutex)
139 #define file_share_hash_unlock() mono_mutex_unlock (&file_share_hash_mutex)
141 guint32 _wapi_fd_reserve;
144 * This is an internal handle which is used for handling waiting for multiple handles.
145 * Threads which wait for multiple handles wait on this one handle, and when a handle
146 * is signalled, this handle is signalled too.
148 static gpointer _wapi_global_signal_handle;
150 /* Point to the mutex/cond inside _wapi_global_signal_handle */
151 mono_mutex_t *_wapi_global_signal_mutex;
152 pthread_cond_t *_wapi_global_signal_cond;
155 gboolean _wapi_has_shut_down = FALSE;
157 /* Use this instead of getpid(), to cope with linuxthreads. It's a
158 * function rather than a variable lookup because we need to get at
159 * this before share_init() might have been called.
161 static pid_t _wapi_pid;
162 static mono_once_t pid_init_once = MONO_ONCE_INIT;
164 static void _wapi_handle_unref_full (gpointer handle, gboolean ignore_private_busy_handles);
166 static void pid_init (void)
168 _wapi_pid = getpid ();
171 pid_t _wapi_getpid (void)
173 mono_once (&pid_init_once, pid_init);
179 static mono_mutex_t scan_mutex;
181 static void handle_cleanup (void)
185 /* Every shared handle we were using ought really to be closed
186 * by now, but to make sure just blow them all away. The
187 * exiting finalizer thread in particular races us to the
188 * program exit and doesn't always win, so it can be left
189 * cluttering up the shared file. Anything else left over is
192 for(i = SLOT_INDEX (0); _wapi_private_handles[i] != NULL; i++) {
193 for(j = SLOT_OFFSET (0); j < _WAPI_HANDLE_INITIAL_COUNT; j++) {
194 struct _WapiHandleUnshared *handle_data = &_wapi_private_handles[i][j];
195 gpointer handle = GINT_TO_POINTER (i*_WAPI_HANDLE_INITIAL_COUNT+j);
197 for(k = handle_data->ref; k > 0; k--) {
198 DEBUG ("%s: unreffing %s handle %p", __func__, _wapi_handle_typename[type], handle);
200 _wapi_handle_unref_full (handle, TRUE);
205 _wapi_shm_semaphores_remove ();
207 _wapi_shm_detach (WAPI_SHM_DATA);
208 _wapi_shm_detach (WAPI_SHM_FILESHARE);
210 if (file_share_hash) {
211 g_hash_table_destroy (file_share_hash);
212 mono_mutex_destroy (&file_share_hash_mutex);
215 for (i = 0; i < _WAPI_PRIVATE_MAX_SLOTS; ++i)
216 g_free (_wapi_private_handles [i]);
220 wapi_getdtablesize (void)
222 #ifdef HAVE_GETRLIMIT
226 res = getrlimit (RLIMIT_NOFILE, &limit);
228 return limit.rlim_cur;
230 return getdtablesize ();
237 * Initialize the io-layer.
242 g_assert ((sizeof (handle_ops) / sizeof (handle_ops[0]))
243 == WAPI_HANDLE_COUNT);
245 _wapi_fd_reserve = wapi_getdtablesize ();
247 /* This is needed by the code in _wapi_handle_new_internal */
248 _wapi_fd_reserve = (_wapi_fd_reserve + (_WAPI_HANDLE_INITIAL_COUNT - 1)) & ~(_WAPI_HANDLE_INITIAL_COUNT - 1);
252 * The entries in _wapi_private_handles reserved for fds are allocated lazily to
256 _wapi_private_handles [idx++] = g_new0 (struct _WapiHandleUnshared,
257 _WAPI_HANDLE_INITIAL_COUNT);
260 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
261 _wapi_private_handle_slot_count ++;
262 } while(_wapi_fd_reserve > _wapi_private_handle_count);
264 _wapi_shm_semaphores_init ();
266 _wapi_shared_layout = _wapi_shm_attach (WAPI_SHM_DATA);
267 g_assert (_wapi_shared_layout != NULL);
269 if (_wapi_shm_enabled ()) {
270 /* This allocates a 4mb array, so do it only if SHM is enabled */
271 _wapi_fileshare_layout = _wapi_shm_attach (WAPI_SHM_FILESHARE);
272 g_assert (_wapi_fileshare_layout != NULL);
275 #if !defined (DISABLE_SHARED_HANDLES)
276 if (_wapi_shm_enabled ())
277 _wapi_collection_init ();
280 mono_mutex_init (&scan_mutex);
282 _wapi_global_signal_handle = _wapi_handle_new (WAPI_HANDLE_EVENT, NULL);
284 _wapi_global_signal_cond = &_WAPI_PRIVATE_HANDLES (GPOINTER_TO_UINT (_wapi_global_signal_handle)).signal_cond;
285 _wapi_global_signal_mutex = &_WAPI_PRIVATE_HANDLES (GPOINTER_TO_UINT (_wapi_global_signal_handle)).signal_mutex;
287 wapi_processes_init ();
289 /* Using g_atexit here instead of an explicit function call in
290 * a cleanup routine lets us cope when a third-party library
291 * calls exit (eg if an X client loses the connection to its
294 g_atexit (handle_cleanup);
300 g_assert (_wapi_has_shut_down == FALSE);
302 _wapi_has_shut_down = TRUE;
304 _wapi_error_cleanup ();
305 _wapi_thread_cleanup ();
306 wapi_processes_cleanup ();
309 static void _wapi_handle_init_shared (struct _WapiHandleShared *handle,
311 gpointer handle_specific)
313 g_assert (_wapi_has_shut_down == FALSE);
316 handle->timestamp = (guint32)(time (NULL) & 0xFFFFFFFF);
317 handle->signalled = FALSE;
318 handle->handle_refs = 1;
320 if (handle_specific != NULL) {
321 memcpy (&handle->u, handle_specific, sizeof (handle->u));
325 static size_t _wapi_handle_struct_size (WapiHandleType type)
330 case WAPI_HANDLE_FILE: case WAPI_HANDLE_CONSOLE: case WAPI_HANDLE_PIPE:
331 type_size = sizeof (struct _WapiHandle_file);
333 case WAPI_HANDLE_THREAD:
334 type_size = sizeof (struct _WapiHandle_thread);
336 case WAPI_HANDLE_SEM:
337 type_size = sizeof (struct _WapiHandle_sem);
339 case WAPI_HANDLE_MUTEX:
340 type_size = sizeof (struct _WapiHandle_mutex);
342 case WAPI_HANDLE_EVENT:
343 type_size = sizeof (struct _WapiHandle_event);
345 case WAPI_HANDLE_SOCKET:
346 type_size = sizeof (struct _WapiHandle_socket);
348 case WAPI_HANDLE_FIND:
349 type_size = sizeof (struct _WapiHandle_find);
351 case WAPI_HANDLE_PROCESS:
352 type_size = sizeof (struct _WapiHandle_process);
354 case WAPI_HANDLE_NAMEDMUTEX:
355 type_size = sizeof (struct _WapiHandle_namedmutex);
357 case WAPI_HANDLE_NAMEDSEM:
358 type_size = sizeof (struct _WapiHandle_namedsem);
360 case WAPI_HANDLE_NAMEDEVENT:
361 type_size = sizeof (struct _WapiHandle_namedevent);
365 g_error ("Unknown WapiHandleType: %d\n", type);
371 static void _wapi_handle_init (struct _WapiHandleUnshared *handle,
372 WapiHandleType type, gpointer handle_specific)
377 g_assert (_wapi_has_shut_down == FALSE);
380 handle->signalled = FALSE;
383 if (!_WAPI_SHARED_HANDLE(type)) {
384 thr_ret = pthread_cond_init (&handle->signal_cond, NULL);
385 g_assert (thr_ret == 0);
387 thr_ret = mono_mutex_init (&handle->signal_mutex);
388 g_assert (thr_ret == 0);
390 if (handle_specific != NULL) {
391 type_size = _wapi_handle_struct_size (type);
392 memcpy (&handle->u, handle_specific,
398 static guint32 _wapi_handle_new_shared (WapiHandleType type,
399 gpointer handle_specific)
402 static guint32 last = 1;
405 g_assert (_wapi_has_shut_down == FALSE);
407 /* Leave the first slot empty as a guard */
409 /* FIXME: expandable array */
410 for(offset = last; offset <_WAPI_HANDLE_INITIAL_COUNT; offset++) {
411 struct _WapiHandleShared *handle = &_wapi_shared_layout->handles[offset];
413 if(handle->type == WAPI_HANDLE_UNUSED) {
414 thr_ret = _wapi_handle_lock_shared_handles ();
415 g_assert (thr_ret == 0);
417 if (InterlockedCompareExchange ((gint32 *)&handle->type, type, WAPI_HANDLE_UNUSED) == WAPI_HANDLE_UNUSED) {
420 _wapi_handle_init_shared (handle, type,
423 _wapi_handle_unlock_shared_handles ();
427 /* Someone else beat us to it, just
432 _wapi_handle_unlock_shared_handles ();
437 /* Try again from the beginning */
442 /* Will need to expand the array. The caller will sort it out */
448 * _wapi_handle_new_internal:
449 * @type: Init handle to this type
451 * Search for a free handle and initialize it. Return the handle on
452 * success and 0 on failure. This is only called from
453 * _wapi_handle_new, and scan_mutex must be held.
455 static guint32 _wapi_handle_new_internal (WapiHandleType type,
456 gpointer handle_specific)
459 static guint32 last = 0;
460 gboolean retry = FALSE;
462 g_assert (_wapi_has_shut_down == FALSE);
464 /* A linear scan should be fast enough. Start from the last
465 * allocation, assuming that handles are allocated more often
466 * than they're freed. Leave the space reserved for file
470 if (last < _wapi_fd_reserve) {
471 last = _wapi_fd_reserve;
478 for(i = SLOT_INDEX (count); i < _wapi_private_handle_slot_count; i++) {
479 if (_wapi_private_handles [i]) {
480 for (k = SLOT_OFFSET (count); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
481 struct _WapiHandleUnshared *handle = &_wapi_private_handles [i][k];
483 if(handle->type == WAPI_HANDLE_UNUSED) {
486 _wapi_handle_init (handle, type, handle_specific);
494 if(retry && last > _wapi_fd_reserve) {
495 /* Try again from the beginning */
496 last = _wapi_fd_reserve;
500 /* Will need to expand the array. The caller will sort it out */
506 _wapi_handle_new (WapiHandleType type, gpointer handle_specific)
508 guint32 handle_idx = 0;
512 g_assert (_wapi_has_shut_down == FALSE);
514 DEBUG ("%s: Creating new handle of type %s", __func__,
515 _wapi_handle_typename[type]);
517 g_assert(!_WAPI_FD_HANDLE(type));
519 thr_ret = mono_mutex_lock (&scan_mutex);
520 g_assert (thr_ret == 0);
522 while ((handle_idx = _wapi_handle_new_internal (type, handle_specific)) == 0) {
523 /* Try and expand the array, and have another go */
524 int idx = SLOT_INDEX (_wapi_private_handle_count);
525 if (idx >= _WAPI_PRIVATE_MAX_SLOTS) {
529 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
530 _WAPI_HANDLE_INITIAL_COUNT);
532 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
533 _wapi_private_handle_slot_count ++;
536 thr_ret = mono_mutex_unlock (&scan_mutex);
537 g_assert (thr_ret == 0);
539 if (handle_idx == 0) {
540 /* We ran out of slots */
541 handle = _WAPI_HANDLE_INVALID;
545 /* Make sure we left the space for fd mappings */
546 g_assert (handle_idx >= _wapi_fd_reserve);
548 handle = GUINT_TO_POINTER (handle_idx);
550 DEBUG ("%s: Allocated new handle %p", __func__, handle);
552 if (_WAPI_SHARED_HANDLE(type)) {
553 /* Add the shared section too */
556 ref = _wapi_handle_new_shared (type, handle_specific);
558 _wapi_handle_collect ();
559 ref = _wapi_handle_new_shared (type, handle_specific);
561 /* FIXME: grow the arrays */
562 handle = _WAPI_HANDLE_INVALID;
567 _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = ref;
568 DEBUG ("%s: New shared handle at offset 0x%x", __func__,
576 gpointer _wapi_handle_new_from_offset (WapiHandleType type, guint32 offset,
579 guint32 handle_idx = 0;
580 gpointer handle = INVALID_HANDLE_VALUE;
582 struct _WapiHandleShared *shared;
584 g_assert (_wapi_has_shut_down == FALSE);
586 DEBUG ("%s: Creating new handle of type %s to offset %d", __func__,
587 _wapi_handle_typename[type], offset);
589 g_assert(!_WAPI_FD_HANDLE(type));
590 g_assert(_WAPI_SHARED_HANDLE(type));
591 g_assert(offset != 0);
593 shared = &_wapi_shared_layout->handles[offset];
595 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
596 /* Bump up the timestamp for this offset */
597 InterlockedExchange ((gint32 *)&shared->timestamp, now);
600 thr_ret = mono_mutex_lock (&scan_mutex);
601 g_assert (thr_ret == 0);
603 for (i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
604 if (_wapi_private_handles [i]) {
605 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
606 struct _WapiHandleUnshared *handle_data = &_wapi_private_handles [i][k];
608 if (handle_data->type == type &&
609 handle_data->u.shared.offset == offset) {
610 handle = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
611 goto first_pass_done;
618 thr_ret = mono_mutex_unlock (&scan_mutex);
619 g_assert (thr_ret == 0);
621 if (handle != INVALID_HANDLE_VALUE) {
622 _wapi_handle_ref (handle);
624 DEBUG ("%s: Returning old handle %p referencing 0x%x",
625 __func__, handle, offset);
629 /* Prevent entries expiring under us as we search */
630 thr_ret = _wapi_handle_lock_shared_handles ();
631 g_assert (thr_ret == 0);
633 if (shared->type == WAPI_HANDLE_UNUSED) {
634 /* Someone deleted this handle while we were working */
635 DEBUG ("%s: Handle at 0x%x unused", __func__, offset);
639 if (shared->type != type) {
640 DEBUG ("%s: Wrong type at %d 0x%x! Found %s wanted %s",
641 __func__, offset, offset,
642 _wapi_handle_typename[shared->type],
643 _wapi_handle_typename[type]);
647 thr_ret = mono_mutex_lock (&scan_mutex);
648 g_assert (thr_ret == 0);
650 while ((handle_idx = _wapi_handle_new_internal (type, NULL)) == 0) {
651 /* Try and expand the array, and have another go */
652 int idx = SLOT_INDEX (_wapi_private_handle_count);
653 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
654 _WAPI_HANDLE_INITIAL_COUNT);
656 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
657 _wapi_private_handle_slot_count ++;
660 thr_ret = mono_mutex_unlock (&scan_mutex);
661 g_assert (thr_ret == 0);
663 /* Make sure we left the space for fd mappings */
664 g_assert (handle_idx >= _wapi_fd_reserve);
666 handle = GUINT_TO_POINTER (handle_idx);
668 _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = offset;
669 InterlockedIncrement ((gint32 *)&shared->handle_refs);
671 DEBUG ("%s: Allocated new handle %p referencing 0x%x (shared refs %d)", __func__, handle, offset, shared->handle_refs);
674 _wapi_handle_unlock_shared_handles ();
680 init_handles_slot (int idx)
684 thr_ret = mono_mutex_lock (&scan_mutex);
685 g_assert (thr_ret == 0);
687 if (_wapi_private_handles [idx] == NULL) {
688 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
689 _WAPI_HANDLE_INITIAL_COUNT);
690 g_assert (_wapi_private_handles [idx]);
693 thr_ret = mono_mutex_unlock (&scan_mutex);
694 g_assert (thr_ret == 0);
697 gpointer _wapi_handle_new_fd (WapiHandleType type, int fd,
698 gpointer handle_specific)
700 struct _WapiHandleUnshared *handle;
703 g_assert (_wapi_has_shut_down == FALSE);
705 DEBUG ("%s: Creating new handle of type %s", __func__,
706 _wapi_handle_typename[type]);
708 g_assert(_WAPI_FD_HANDLE(type));
709 g_assert(!_WAPI_SHARED_HANDLE(type));
711 if (fd >= _wapi_fd_reserve) {
712 DEBUG ("%s: fd %d is too big", __func__, fd);
714 return(GUINT_TO_POINTER (_WAPI_HANDLE_INVALID));
717 /* Initialize the array entries on demand */
718 if (_wapi_private_handles [SLOT_INDEX (fd)] == NULL)
719 init_handles_slot (SLOT_INDEX (fd));
721 handle = &_WAPI_PRIVATE_HANDLES(fd);
723 if (handle->type != WAPI_HANDLE_UNUSED) {
724 DEBUG ("%s: fd %d is already in use!", __func__, fd);
725 /* FIXME: clean up this handle? We can't do anything
726 * with the fd, cos thats the new one
730 DEBUG ("%s: Assigning new fd handle %d", __func__, fd);
732 /* Prevent file share entries racing with us, when the file
733 * handle is only half initialised
735 thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
736 g_assert(thr_ret == 0);
738 _wapi_handle_init (handle, type, handle_specific);
740 thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
742 return(GUINT_TO_POINTER(fd));
745 gboolean _wapi_lookup_handle (gpointer handle, WapiHandleType type,
746 gpointer *handle_specific)
748 struct _WapiHandleUnshared *handle_data;
749 guint32 handle_idx = GPOINTER_TO_UINT(handle);
751 if (!_WAPI_PRIVATE_VALID_SLOT (handle_idx)) {
755 /* Initialize the array entries on demand */
756 if (_wapi_private_handles [SLOT_INDEX (handle_idx)] == NULL)
757 init_handles_slot (SLOT_INDEX (handle_idx));
759 handle_data = &_WAPI_PRIVATE_HANDLES(handle_idx);
761 if (handle_data->type != type) {
765 if (handle_specific == NULL) {
769 if (_WAPI_SHARED_HANDLE(type)) {
770 struct _WapiHandle_shared_ref *ref;
771 struct _WapiHandleShared *shared_handle_data;
773 ref = &handle_data->u.shared;
774 shared_handle_data = &_wapi_shared_layout->handles[ref->offset];
776 if (shared_handle_data->type != type) {
777 /* The handle must have been deleted on us
782 *handle_specific = &shared_handle_data->u;
784 *handle_specific = &handle_data->u;
791 _wapi_handle_foreach (WapiHandleType type,
792 gboolean (*on_each)(gpointer test, gpointer user),
795 struct _WapiHandleUnshared *handle_data = NULL;
800 thr_ret = mono_mutex_lock (&scan_mutex);
801 g_assert (thr_ret == 0);
803 for (i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
804 if (_wapi_private_handles [i]) {
805 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
806 handle_data = &_wapi_private_handles [i][k];
808 if (handle_data->type == type) {
809 ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
810 if (on_each (ret, user_data) == TRUE)
817 thr_ret = mono_mutex_unlock (&scan_mutex);
818 g_assert (thr_ret == 0);
821 /* This might list some shared handles twice if they are already
822 * opened by this process, and the check function returns FALSE the
823 * first time. Shared handles that are created during the search are
824 * unreffed if the check function returns FALSE, so callers must not
825 * rely on the handle persisting (unless the check function returns
827 * The caller owns the returned handle.
829 gpointer _wapi_search_handle (WapiHandleType type,
830 gboolean (*check)(gpointer test, gpointer user),
832 gpointer *handle_specific,
833 gboolean search_shared)
835 struct _WapiHandleUnshared *handle_data = NULL;
836 struct _WapiHandleShared *shared = NULL;
839 gboolean found = FALSE;
842 thr_ret = mono_mutex_lock (&scan_mutex);
843 g_assert (thr_ret == 0);
845 for (i = SLOT_INDEX (0); !found && i < _wapi_private_handle_slot_count; i++) {
846 if (_wapi_private_handles [i]) {
847 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
848 handle_data = &_wapi_private_handles [i][k];
850 if (handle_data->type == type) {
851 ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
852 if (check (ret, user_data) == TRUE) {
853 _wapi_handle_ref (ret);
856 if (_WAPI_SHARED_HANDLE (type)) {
857 shared = &_wapi_shared_layout->handles[i];
867 thr_ret = mono_mutex_unlock (&scan_mutex);
868 g_assert (thr_ret == 0);
870 if (!found && search_shared && _WAPI_SHARED_HANDLE (type)) {
871 /* Not found yet, so search the shared memory too */
872 DEBUG ("%s: Looking at other shared handles...", __func__);
874 for (i = 0; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
875 shared = &_wapi_shared_layout->handles[i];
877 if (shared->type == type) {
878 /* Tell new_from_offset to not
879 * timestamp this handle, because
880 * otherwise it will ping every handle
881 * in the list and they will never
884 ret = _wapi_handle_new_from_offset (type, i,
886 if (ret == INVALID_HANDLE_VALUE) {
887 /* This handle was deleted
888 * while we were looking at it
893 DEBUG ("%s: Opened tmp handle %p (type %s) from offset %d", __func__, ret, _wapi_handle_typename[type], i);
895 /* It's possible that the shared part
896 * of this handle has now been blown
897 * away (after new_from_offset
898 * successfully opened it,) if its
899 * timestamp is too old. The check
900 * function needs to be aware of this,
901 * and cope if the handle has
904 if (check (ret, user_data) == TRUE) {
905 /* Timestamp this handle, but make
906 * sure it still exists first
908 thr_ret = _wapi_handle_lock_shared_handles ();
909 g_assert (thr_ret == 0);
911 if (shared->type == type) {
912 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
913 InterlockedExchange ((gint32 *)&shared->timestamp, now);
916 handle_data = &_WAPI_PRIVATE_HANDLES(GPOINTER_TO_UINT(ret));
918 _wapi_handle_unlock_shared_handles ();
921 /* It's been deleted,
925 _wapi_handle_unlock_shared_handles ();
929 /* This isn't the handle we're looking
930 * for, so drop the reference we took
931 * in _wapi_handle_new_from_offset ()
933 _wapi_handle_unref (ret);
943 if(handle_specific != NULL) {
944 if (_WAPI_SHARED_HANDLE(type)) {
945 g_assert(shared->type == type);
947 *handle_specific = &shared->u;
949 *handle_specific = &handle_data->u;
957 /* Returns the offset of the metadata array, or -1 on error, or 0 for
958 * not found (0 is not a valid offset)
960 gint32 _wapi_search_handle_namespace (WapiHandleType type,
963 struct _WapiHandleShared *shared_handle_data;
968 g_assert(_WAPI_SHARED_HANDLE(type));
970 DEBUG ("%s: Lookup for handle named [%s] type %s", __func__,
971 utf8_name, _wapi_handle_typename[type]);
973 /* Do a handle collection before starting to look, so that any
974 * stale cruft gets removed
976 _wapi_handle_collect ();
978 thr_ret = _wapi_handle_lock_shared_handles ();
979 g_assert (thr_ret == 0);
981 for(i = 1; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
982 WapiSharedNamespace *sharedns;
984 shared_handle_data = &_wapi_shared_layout->handles[i];
986 /* Check mutex, event, semaphore, timer, job and
987 * file-mapping object names. So far only mutex,
988 * semaphore and event are implemented.
990 if (!_WAPI_SHARED_NAMESPACE (shared_handle_data->type)) {
994 DEBUG ("%s: found a shared namespace handle at 0x%x (type %s)", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
996 sharedns=(WapiSharedNamespace *)&shared_handle_data->u;
998 DEBUG ("%s: name is [%s]", __func__, sharedns->name);
1000 if (strcmp (sharedns->name, utf8_name) == 0) {
1001 if (shared_handle_data->type != type) {
1002 /* Its the wrong type, so fail now */
1003 DEBUG ("%s: handle 0x%x matches name but is wrong type: %s", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
1007 DEBUG ("%s: handle 0x%x matches name and type", __func__, i);
1015 _wapi_handle_unlock_shared_handles ();
1020 void _wapi_handle_ref (gpointer handle)
1022 guint32 idx = GPOINTER_TO_UINT(handle);
1023 struct _WapiHandleUnshared *handle_data;
1025 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1029 if (_wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) {
1030 g_warning ("%s: Attempting to ref unused handle %p", __func__,
1035 handle_data = &_WAPI_PRIVATE_HANDLES(idx);
1037 InterlockedIncrement ((gint32 *)&handle_data->ref);
1039 /* It's possible for processes to exit before getting around
1040 * to updating timestamps in the collection thread, so if a
1041 * shared handle is reffed do the timestamp here as well just
1044 if (_WAPI_SHARED_HANDLE(handle_data->type)) {
1045 struct _WapiHandleShared *shared_data = &_wapi_shared_layout->handles[handle_data->u.shared.offset];
1046 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
1047 InterlockedExchange ((gint32 *)&shared_data->timestamp, now);
1051 g_message ("%s: %s handle %p ref now %d", __func__,
1052 _wapi_handle_typename[_WAPI_PRIVATE_HANDLES (idx).type],
1054 _WAPI_PRIVATE_HANDLES(idx).ref);
1058 /* The handle must not be locked on entry to this function */
1059 static void _wapi_handle_unref_full (gpointer handle, gboolean ignore_private_busy_handles)
1061 guint32 idx = GPOINTER_TO_UINT(handle);
1062 gboolean destroy = FALSE, early_exit = FALSE;
1065 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1069 if (_wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) {
1070 g_warning ("%s: Attempting to unref unused handle %p",
1075 /* Possible race condition here if another thread refs the
1076 * handle between here and setting the type to UNUSED. I
1077 * could lock a mutex, but I'm not sure that allowing a handle
1078 * reference to reach 0 isn't an application bug anyway.
1080 destroy = (InterlockedDecrement ((gint32 *)&_WAPI_PRIVATE_HANDLES(idx).ref) ==0);
1083 g_message ("%s: %s handle %p ref now %d (destroy %s)", __func__,
1084 _wapi_handle_typename[_WAPI_PRIVATE_HANDLES (idx).type],
1086 _WAPI_PRIVATE_HANDLES(idx).ref, destroy?"TRUE":"FALSE");
1090 /* Need to copy the handle info, reset the slot in the
1091 * array, and _only then_ call the close function to
1092 * avoid race conditions (eg file descriptors being
1093 * closed, and another file being opened getting the
1094 * same fd racing the memset())
1096 struct _WapiHandleUnshared handle_data;
1097 struct _WapiHandleShared shared_handle_data;
1098 WapiHandleType type = _WAPI_PRIVATE_HANDLES(idx).type;
1099 void (*close_func)(gpointer, gpointer) = _wapi_handle_ops_get_close_func (type);
1100 gboolean is_shared = _WAPI_SHARED_HANDLE(type);
1103 /* If this is a shared handle we need to take
1104 * the shared lock outside of the scan_mutex
1105 * lock to avoid deadlocks
1107 thr_ret = _wapi_handle_lock_shared_handles ();
1108 g_assert (thr_ret == 0);
1111 thr_ret = mono_mutex_lock (&scan_mutex);
1113 DEBUG ("%s: Destroying handle %p", __func__, handle);
1115 memcpy (&handle_data, &_WAPI_PRIVATE_HANDLES(idx),
1116 sizeof (struct _WapiHandleUnshared));
1118 memset (&_WAPI_PRIVATE_HANDLES(idx).u, '\0',
1119 sizeof(_WAPI_PRIVATE_HANDLES(idx).u));
1121 _WAPI_PRIVATE_HANDLES(idx).type = WAPI_HANDLE_UNUSED;
1124 /* Destroy the mutex and cond var. We hope nobody
1125 * tried to grab them between the handle unlock and
1126 * now, but pthreads doesn't have a
1127 * "unlock_and_destroy" atomic function.
1129 thr_ret = mono_mutex_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_mutex);
1130 /*WARNING gross hack to make cleanup not crash when exiting without the whole runtime teardown.*/
1131 if (thr_ret == EBUSY && ignore_private_busy_handles) {
1135 g_error ("Error destroying handle %p mutex due to %d\n", handle, thr_ret);
1137 thr_ret = pthread_cond_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_cond);
1138 if (thr_ret == EBUSY && ignore_private_busy_handles)
1140 else if (thr_ret != 0)
1141 g_error ("Error destroying handle %p cond var due to %d\n", handle, thr_ret);
1144 struct _WapiHandleShared *shared = &_wapi_shared_layout->handles[handle_data.u.shared.offset];
1146 memcpy (&shared_handle_data, shared,
1147 sizeof (struct _WapiHandleShared));
1149 /* It's possible that this handle is already
1150 * pointing at a deleted shared section
1153 g_message ("%s: %s handle %p shared refs before dec %d", __func__, _wapi_handle_typename[type], handle, shared->handle_refs);
1156 if (shared->handle_refs > 0) {
1157 shared->handle_refs--;
1158 if (shared->handle_refs == 0) {
1159 memset (shared, '\0', sizeof (struct _WapiHandleShared));
1164 thr_ret = mono_mutex_unlock (&scan_mutex);
1165 g_assert (thr_ret == 0);
1170 _wapi_handle_unlock_shared_handles ();
1173 if (close_func != NULL) {
1175 close_func (handle, &shared_handle_data.u);
1177 close_func (handle, &handle_data.u);
1183 void _wapi_handle_unref (gpointer handle)
1185 _wapi_handle_unref_full (handle, FALSE);
1188 void _wapi_handle_register_capabilities (WapiHandleType type,
1189 WapiHandleCapability caps)
1191 handle_caps[type] = caps;
1194 gboolean _wapi_handle_test_capabilities (gpointer handle,
1195 WapiHandleCapability caps)
1197 guint32 idx = GPOINTER_TO_UINT(handle);
1198 WapiHandleType type;
1200 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1204 type = _WAPI_PRIVATE_HANDLES(idx).type;
1206 DEBUG ("%s: testing 0x%x against 0x%x (%d)", __func__,
1207 handle_caps[type], caps, handle_caps[type] & caps);
1209 return((handle_caps[type] & caps) != 0);
1212 static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer)
1214 if (handle_ops[type] != NULL &&
1215 handle_ops[type]->close != NULL) {
1216 return (handle_ops[type]->close);
1222 void _wapi_handle_ops_close (gpointer handle, gpointer data)
1224 guint32 idx = GPOINTER_TO_UINT(handle);
1225 WapiHandleType type;
1227 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1231 type = _WAPI_PRIVATE_HANDLES(idx).type;
1233 if (handle_ops[type] != NULL &&
1234 handle_ops[type]->close != NULL) {
1235 handle_ops[type]->close (handle, data);
1239 void _wapi_handle_ops_signal (gpointer handle)
1241 guint32 idx = GPOINTER_TO_UINT(handle);
1242 WapiHandleType type;
1244 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1248 type = _WAPI_PRIVATE_HANDLES(idx).type;
1250 if (handle_ops[type] != NULL && handle_ops[type]->signal != NULL) {
1251 handle_ops[type]->signal (handle);
1255 gboolean _wapi_handle_ops_own (gpointer handle)
1257 guint32 idx = GPOINTER_TO_UINT(handle);
1258 WapiHandleType type;
1260 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1264 type = _WAPI_PRIVATE_HANDLES(idx).type;
1266 if (handle_ops[type] != NULL && handle_ops[type]->own_handle != NULL) {
1267 return(handle_ops[type]->own_handle (handle));
1273 gboolean _wapi_handle_ops_isowned (gpointer handle)
1275 guint32 idx = GPOINTER_TO_UINT(handle);
1276 WapiHandleType type;
1278 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1282 type = _WAPI_PRIVATE_HANDLES(idx).type;
1284 if (handle_ops[type] != NULL && handle_ops[type]->is_owned != NULL) {
1285 return(handle_ops[type]->is_owned (handle));
1291 guint32 _wapi_handle_ops_special_wait (gpointer handle, guint32 timeout, gboolean alertable)
1293 guint32 idx = GPOINTER_TO_UINT(handle);
1294 WapiHandleType type;
1296 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1297 return(WAIT_FAILED);
1300 type = _WAPI_PRIVATE_HANDLES(idx).type;
1302 if (handle_ops[type] != NULL &&
1303 handle_ops[type]->special_wait != NULL) {
1304 return(handle_ops[type]->special_wait (handle, timeout, alertable));
1306 return(WAIT_FAILED);
1310 void _wapi_handle_ops_prewait (gpointer handle)
1312 guint32 idx = GPOINTER_TO_UINT (handle);
1313 WapiHandleType type;
1315 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1319 type = _WAPI_PRIVATE_HANDLES (idx).type;
1321 if (handle_ops[type] != NULL &&
1322 handle_ops[type]->prewait != NULL) {
1323 handle_ops[type]->prewait (handle);
1330 * @handle: The handle to release
1332 * Closes and invalidates @handle, releasing any resources it
1333 * consumes. When the last handle to a temporary or non-persistent
1334 * object is closed, that object can be deleted. Closing the same
1335 * handle twice is an error.
1337 * Return value: %TRUE on success, %FALSE otherwise.
1339 gboolean CloseHandle(gpointer handle)
1341 if (handle == NULL) {
1342 /* Problem: because we map file descriptors to the
1343 * same-numbered handle we can't tell the difference
1344 * between a bogus handle and the handle to stdin.
1345 * Assume that it's the console handle if that handle
1348 if (_WAPI_PRIVATE_HANDLES (0).type != WAPI_HANDLE_CONSOLE) {
1349 SetLastError (ERROR_INVALID_PARAMETER);
1353 if (handle == _WAPI_HANDLE_INVALID){
1354 SetLastError (ERROR_INVALID_PARAMETER);
1358 _wapi_handle_unref (handle);
1363 /* Lots more to implement here, but this is all we need at the moment */
1364 gboolean DuplicateHandle (gpointer srcprocess, gpointer src,
1365 gpointer targetprocess, gpointer *target,
1366 guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, guint32 options G_GNUC_UNUSED)
1368 if (srcprocess != _WAPI_PROCESS_CURRENT ||
1369 targetprocess != _WAPI_PROCESS_CURRENT) {
1370 /* Duplicating other process's handles is not supported */
1371 SetLastError (ERROR_INVALID_HANDLE);
1375 if (src == _WAPI_PROCESS_CURRENT) {
1376 *target = _wapi_process_duplicate ();
1377 } else if (src == _WAPI_THREAD_CURRENT) {
1378 g_assert_not_reached ();
1380 _wapi_handle_ref (src);
1387 gboolean _wapi_handle_count_signalled_handles (guint32 numhandles,
1393 guint32 count, i, iter=0;
1396 WapiHandleType type;
1398 /* Lock all the handles, with backoff */
1400 thr_ret = _wapi_handle_lock_shared_handles ();
1401 g_assert (thr_ret == 0);
1403 for(i=0; i<numhandles; i++) {
1404 gpointer handle = handles[i];
1405 guint32 idx = GPOINTER_TO_UINT(handle);
1407 DEBUG ("%s: attempting to lock %p", __func__, handle);
1409 type = _WAPI_PRIVATE_HANDLES(idx).type;
1411 thr_ret = _wapi_handle_trylock_handle (handle);
1416 DEBUG ("%s: attempt failed for %p: %s", __func__,
1417 handle, strerror (thr_ret));
1419 thr_ret = _wapi_handle_unlock_shared_handles ();
1420 g_assert (thr_ret == 0);
1423 handle = handles[i];
1424 idx = GPOINTER_TO_UINT(handle);
1426 thr_ret = _wapi_handle_unlock_handle (handle);
1427 g_assert (thr_ret == 0);
1430 /* If iter ever reaches 100 the nanosleep will
1431 * return EINVAL immediately, but we have a
1432 * design flaw if that happens.
1436 g_warning ("%s: iteration overflow!",
1441 DEBUG ("%s: Backing off for %d ms", __func__,
1443 _wapi_handle_spin (10 * iter);
1449 DEBUG ("%s: Locked all handles", __func__);
1454 for(i=0; i<numhandles; i++) {
1455 gpointer handle = handles[i];
1456 guint32 idx = GPOINTER_TO_UINT(handle);
1458 type = _WAPI_PRIVATE_HANDLES(idx).type;
1460 DEBUG ("%s: Checking handle %p", __func__, handle);
1462 if(((_wapi_handle_test_capabilities (handle, WAPI_HANDLE_CAP_OWN)==TRUE) &&
1463 (_wapi_handle_ops_isowned (handle) == TRUE)) ||
1464 (_WAPI_SHARED_HANDLE(type) &&
1465 WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) ||
1466 (!_WAPI_SHARED_HANDLE(type) &&
1467 _WAPI_PRIVATE_HANDLES(idx).signalled == TRUE)) {
1470 DEBUG ("%s: Handle %p signalled", __func__,
1478 DEBUG ("%s: %d event handles signalled", __func__, count);
1480 if ((waitall == TRUE && count == numhandles) ||
1481 (waitall == FALSE && count > 0)) {
1487 DEBUG ("%s: Returning %d", __func__, ret);
1494 void _wapi_handle_unlock_handles (guint32 numhandles, gpointer *handles)
1499 thr_ret = _wapi_handle_unlock_shared_handles ();
1500 g_assert (thr_ret == 0);
1502 for(i=0; i<numhandles; i++) {
1503 gpointer handle = handles[i];
1505 DEBUG ("%s: unlocking handle %p", __func__, handle);
1507 thr_ret = _wapi_handle_unlock_handle (handle);
1508 g_assert (thr_ret == 0);
1512 static int timedwait_signal_poll_cond (pthread_cond_t *cond, mono_mutex_t *mutex, struct timespec *timeout, gboolean alertable)
1514 struct timespec fake_timeout;
1519 ret=mono_cond_timedwait (cond, mutex, timeout);
1521 ret=mono_cond_wait (cond, mutex);
1523 _wapi_calc_timeout (&fake_timeout, 100);
1525 if (timeout != NULL && ((fake_timeout.tv_sec > timeout->tv_sec) ||
1526 (fake_timeout.tv_sec == timeout->tv_sec &&
1527 fake_timeout.tv_nsec > timeout->tv_nsec))) {
1528 /* Real timeout is less than 100ms time */
1529 ret=mono_cond_timedwait (cond, mutex, timeout);
1531 ret=mono_cond_timedwait (cond, mutex, &fake_timeout);
1533 /* Mask the fake timeout, this will cause
1534 * another poll if the cond was not really signaled
1536 if (ret==ETIMEDOUT) {
1545 int _wapi_handle_wait_signal (gboolean poll)
1547 return _wapi_handle_timedwait_signal_handle (_wapi_global_signal_handle, NULL, TRUE, poll);
1550 int _wapi_handle_timedwait_signal (struct timespec *timeout, gboolean poll)
1552 return _wapi_handle_timedwait_signal_handle (_wapi_global_signal_handle, timeout, TRUE, poll);
1555 int _wapi_handle_wait_signal_handle (gpointer handle, gboolean alertable)
1557 DEBUG ("%s: waiting for %p", __func__, handle);
1559 return _wapi_handle_timedwait_signal_handle (handle, NULL, alertable, FALSE);
1562 int _wapi_handle_timedwait_signal_handle (gpointer handle,
1563 struct timespec *timeout, gboolean alertable, gboolean poll)
1565 DEBUG ("%s: waiting for %p (type %s)", __func__, handle,
1566 _wapi_handle_typename[_wapi_handle_type (handle)]);
1568 if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
1569 if (WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) {
1572 if (timeout != NULL) {
1573 struct timespec fake_timeout;
1574 _wapi_calc_timeout (&fake_timeout, 100);
1576 if ((fake_timeout.tv_sec > timeout->tv_sec) ||
1577 (fake_timeout.tv_sec == timeout->tv_sec &&
1578 fake_timeout.tv_nsec > timeout->tv_nsec)) {
1579 /* FIXME: Real timeout is less than
1580 * 100ms time, but is it really worth
1581 * calculating to the exact ms?
1583 _wapi_handle_spin (100);
1585 if (WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) {
1592 _wapi_handle_spin (100);
1596 guint32 idx = GPOINTER_TO_UINT(handle);
1598 pthread_cond_t *cond;
1599 mono_mutex_t *mutex;
1601 if (alertable && !wapi_thread_set_wait_handle (handle))
1604 cond = &_WAPI_PRIVATE_HANDLES (idx).signal_cond;
1605 mutex = &_WAPI_PRIVATE_HANDLES (idx).signal_mutex;
1608 /* This is needed when waiting for process handles */
1609 res = timedwait_signal_poll_cond (cond, mutex, timeout, alertable);
1612 res = mono_cond_timedwait (cond, mutex, timeout);
1614 res = mono_cond_wait (cond, mutex);
1618 wapi_thread_clear_wait_handle (handle);
1625 _wapi_free_share_info (_WapiFileShare *share_info)
1627 if (!_wapi_shm_enabled ()) {
1628 file_share_hash_lock ();
1629 g_hash_table_remove (file_share_hash, share_info);
1630 file_share_hash_unlock ();
1631 /* The hashtable dtor frees share_info */
1633 memset (share_info, '\0', sizeof(struct _WapiFileShare));
1638 wapi_share_info_equal (gconstpointer ka, gconstpointer kb)
1640 const _WapiFileShare *s1 = ka;
1641 const _WapiFileShare *s2 = kb;
1643 return (s1->device == s2->device && s1->inode == s2->inode) ? 1 : 0;
1647 wapi_share_info_hash (gconstpointer data)
1649 const _WapiFileShare *s = data;
1654 gboolean _wapi_handle_get_or_set_share (dev_t device, ino_t inode,
1655 guint32 new_sharemode,
1657 guint32 *old_sharemode,
1658 guint32 *old_access,
1659 struct _WapiFileShare **share_info)
1661 struct _WapiFileShare *file_share;
1662 guint32 now = (guint32)(time(NULL) & 0xFFFFFFFF);
1663 int thr_ret, i, first_unused = -1;
1664 gboolean exists = FALSE;
1666 /* Prevents entries from expiring under us as we search
1668 thr_ret = _wapi_handle_lock_shared_handles ();
1669 g_assert (thr_ret == 0);
1671 /* Prevent new entries racing with us */
1672 thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1673 g_assert (thr_ret == 0);
1675 if (!_wapi_shm_enabled ()) {
1679 * Instead of allocating a 4MB array, we use a hash table to keep track of this
1680 * info. This is needed even if SHM is disabled, to track sharing inside
1681 * the current process.
1683 if (!file_share_hash) {
1684 file_share_hash = g_hash_table_new_full (wapi_share_info_hash, wapi_share_info_equal, NULL, g_free);
1685 mono_mutex_init_recursive (&file_share_hash_mutex);
1688 tmp.device = device;
1691 file_share_hash_lock ();
1693 file_share = g_hash_table_lookup (file_share_hash, &tmp);
1695 *old_sharemode = file_share->sharemode;
1696 *old_access = file_share->access;
1697 *share_info = file_share;
1699 InterlockedIncrement ((gint32 *)&file_share->handle_refs);
1702 file_share = g_new0 (_WapiFileShare, 1);
1704 file_share->device = device;
1705 file_share->inode = inode;
1706 file_share->opened_by_pid = _wapi_getpid ();
1707 file_share->sharemode = new_sharemode;
1708 file_share->access = new_access;
1709 file_share->handle_refs = 1;
1710 *share_info = file_share;
1712 g_hash_table_insert (file_share_hash, file_share, file_share);
1715 file_share_hash_unlock ();
1717 /* If a linear scan gets too slow we'll have to fit a hash
1718 * table onto the shared mem backing store
1721 for (i = 0; i <= _wapi_fileshare_layout->hwm; i++) {
1722 file_share = &_wapi_fileshare_layout->share_info[i];
1724 /* Make a note of an unused slot, in case we need to
1727 if (first_unused == -1 && file_share->handle_refs == 0) {
1732 if (file_share->handle_refs == 0) {
1736 if (file_share->device == device &&
1737 file_share->inode == inode) {
1738 *old_sharemode = file_share->sharemode;
1739 *old_access = file_share->access;
1740 *share_info = file_share;
1742 /* Increment the reference count while we
1743 * still have sole access to the shared area.
1744 * This makes the increment atomic wrt
1747 InterlockedIncrement ((gint32 *)&file_share->handle_refs);
1755 if (i == _WAPI_FILESHARE_SIZE && first_unused == -1) {
1758 if (first_unused == -1) {
1759 file_share = &_wapi_fileshare_layout->share_info[++i];
1760 _wapi_fileshare_layout->hwm = i;
1762 file_share = &_wapi_fileshare_layout->share_info[first_unused];
1765 file_share->device = device;
1766 file_share->inode = inode;
1767 file_share->opened_by_pid = _wapi_getpid ();
1768 file_share->sharemode = new_sharemode;
1769 file_share->access = new_access;
1770 file_share->handle_refs = 1;
1771 *share_info = file_share;
1775 if (*share_info != NULL) {
1776 InterlockedExchange ((gint32 *)&(*share_info)->timestamp, now);
1780 thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1782 _wapi_handle_unlock_shared_handles ();
1787 /* If we don't have the info in /proc, check if the process that
1788 * opened this share info is still there (it's not a perfect method,
1791 static void _wapi_handle_check_share_by_pid (struct _WapiFileShare *share_info)
1793 #if defined(__native_client__)
1794 g_assert_not_reached ();
1796 if (kill (share_info->opened_by_pid, 0) == -1 &&
1799 /* It's gone completely (or there's a new process
1800 * owned by someone else) so mark this share info as
1803 DEBUG ("%s: Didn't find it, destroying entry", __func__);
1805 _wapi_free_share_info (share_info);
1811 /* Scan /proc/<pids>/fd/ for open file descriptors to the file in
1812 * question. If there are none, reset the share info.
1814 * This implementation is Linux-specific; legacy systems will have to
1815 * implement their own ways of finding out if a particular file is
1816 * open by a process.
1818 void _wapi_handle_check_share (struct _WapiFileShare *share_info, int fd)
1820 gboolean found = FALSE, proc_fds = FALSE;
1821 pid_t self = _wapi_getpid ();
1825 /* Prevents entries from expiring under us if we remove this
1828 thr_ret = _wapi_handle_lock_shared_handles ();
1829 g_assert (thr_ret == 0);
1831 /* Prevent new entries racing with us */
1832 thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1833 g_assert (thr_ret == 0);
1835 /* If there is no /proc, there's nothing more we can do here */
1836 if (access ("/proc", F_OK) == -1) {
1837 _wapi_handle_check_share_by_pid (share_info);
1841 /* If there's another handle that thinks it owns this fd, then even
1842 * if the fd has been closed behind our back consider it still owned.
1843 * See bugs 75764 and 75891
1845 for (i = 0; i < _wapi_fd_reserve; i++) {
1846 if (_wapi_private_handles [SLOT_INDEX (i)]) {
1847 struct _WapiHandleUnshared *handle = &_WAPI_PRIVATE_HANDLES(i);
1850 handle->type == WAPI_HANDLE_FILE) {
1851 struct _WapiHandle_file *file_handle = &handle->u.file;
1853 if (file_handle->share_info == share_info) {
1854 DEBUG ("%s: handle 0x%x has this file open!",
1863 if (proc_fds == FALSE) {
1864 _wapi_handle_check_share_by_pid (share_info);
1865 } else if (found == FALSE) {
1866 /* Blank out this entry, as it is stale */
1867 DEBUG ("%s: Didn't find it, destroying entry", __func__);
1869 _wapi_free_share_info (share_info);
1873 thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1875 _wapi_handle_unlock_shared_handles ();
1879 // Other implementations (non-Linux)
1881 void _wapi_handle_check_share (struct _WapiFileShare *share_info, int fd)
1885 /* Prevents entries from expiring under us if we remove this
1887 thr_ret = _wapi_handle_lock_shared_handles ();
1888 g_assert (thr_ret == 0);
1890 /* Prevent new entries racing with us */
1891 thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1892 g_assert (thr_ret == 0);
1894 _wapi_handle_check_share_by_pid (share_info);
1896 thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1897 _wapi_handle_unlock_shared_handles ();
1901 void _wapi_handle_dump (void)
1903 struct _WapiHandleUnshared *handle_data;
1907 thr_ret = mono_mutex_lock (&scan_mutex);
1908 g_assert (thr_ret == 0);
1910 for(i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
1911 if (_wapi_private_handles [i]) {
1912 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
1913 handle_data = &_wapi_private_handles [i][k];
1915 if (handle_data->type == WAPI_HANDLE_UNUSED) {
1919 g_print ("%3x [%7s] %s %d ",
1920 i * _WAPI_HANDLE_INITIAL_COUNT + k,
1921 _wapi_handle_typename[handle_data->type],
1922 handle_data->signalled?"Sg":"Un",
1924 handle_details[handle_data->type](&handle_data->u);
1930 thr_ret = mono_mutex_unlock (&scan_mutex);
1931 g_assert (thr_ret == 0);
1934 static void _wapi_shared_details (gpointer handle_info)
1936 struct _WapiHandle_shared_ref *shared = (struct _WapiHandle_shared_ref *)handle_info;
1938 g_print ("offset: 0x%x", shared->offset);
1941 void _wapi_handle_update_refs (void)
1945 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
1947 thr_ret = _wapi_handle_lock_shared_handles ();
1948 g_assert (thr_ret == 0);
1950 /* Prevent file share entries racing with us */
1951 thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1952 g_assert(thr_ret == 0);
1954 thr_ret = mono_mutex_lock (&scan_mutex);
1956 for(i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
1957 if (_wapi_private_handles [i]) {
1958 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
1959 struct _WapiHandleUnshared *handle = &_wapi_private_handles [i][k];
1961 if (_WAPI_SHARED_HANDLE(handle->type)) {
1962 struct _WapiHandleShared *shared_data;
1964 DEBUG ("%s: (%d) handle 0x%x is SHARED (%s)", __func__, _wapi_getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k, _wapi_handle_typename[handle->type]);
1966 shared_data = &_wapi_shared_layout->handles[handle->u.shared.offset];
1968 DEBUG ("%s: (%d) Updating timestamp of handle 0x%x", __func__, _wapi_getpid (), handle->u.shared.offset);
1970 InterlockedExchange ((gint32 *)&shared_data->timestamp, now);
1971 } else if (handle->type == WAPI_HANDLE_FILE) {
1972 struct _WapiHandle_file *file_handle = &handle->u.file;
1974 DEBUG ("%s: (%d) handle 0x%x is FILE", __func__, _wapi_getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k);
1976 g_assert (file_handle->share_info != NULL);
1978 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));
1980 InterlockedExchange ((gint32 *)&file_handle->share_info->timestamp, now);
1986 thr_ret = mono_mutex_unlock (&scan_mutex);
1987 g_assert (thr_ret == 0);
1989 thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1991 _wapi_handle_unlock_shared_handles ();