2 * handles.c: Generic and internal operations on handles
5 * Dick Porter (dick@ximian.com)
7 * (C) 2002-2011 Novell, Inc.
8 * Copyright 2011 Xamarin Inc
9 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
21 #include <sys/types.h>
22 #ifdef HAVE_SYS_SOCKET_H
23 # include <sys/socket.h>
28 #ifdef HAVE_SYS_MMAN_H
29 # include <sys/mman.h>
35 #ifdef HAVE_SYS_RESOURCE_H
36 # include <sys/resource.h>
39 #include <mono/io-layer/wapi.h>
40 #include <mono/io-layer/wapi-private.h>
41 #include <mono/io-layer/handles-private.h>
42 #include <mono/io-layer/shared.h>
43 #include <mono/io-layer/process-private.h>
44 #include <mono/io-layer/io-trace.h>
46 #include <mono/utils/mono-os-mutex.h>
47 #include <mono/utils/mono-proclib.h>
48 #include <mono/utils/mono-threads.h>
49 #include <mono/utils/mono-once.h>
50 #include <mono/utils/mono-logger-internals.h>
53 #define _WAPI_PRIVATE_MAX_SLOTS (1024 * 16)
55 /* must be a power of 2 */
56 #define _WAPI_HANDLE_INITIAL_COUNT (256)
62 mono_mutex_t signal_mutex;
63 mono_cond_t signal_cond;
67 static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer);
69 static WapiHandleCapability handle_caps [WAPI_HANDLE_COUNT];
70 static WapiHandleOps *handle_ops [WAPI_HANDLE_COUNT];
73 * We can hold _WAPI_PRIVATE_MAX_SLOTS * _WAPI_HANDLE_INITIAL_COUNT handles.
74 * If 4M handles are not enough... Oh, well... we will crash.
76 #define SLOT_INDEX(x) (x / _WAPI_HANDLE_INITIAL_COUNT)
77 #define SLOT_OFFSET(x) (x % _WAPI_HANDLE_INITIAL_COUNT)
79 WapiHandleBase *_wapi_private_handles [_WAPI_PRIVATE_MAX_SLOTS];
80 static guint32 _wapi_private_handle_count = 0;
81 static guint32 _wapi_private_handle_slot_count = 0;
83 guint32 _wapi_fd_reserve;
86 * This is an internal handle which is used for handling waiting for multiple handles.
87 * Threads which wait for multiple handles wait on this one handle, and when a handle
88 * is signalled, this handle is signalled too.
90 static mono_mutex_t _wapi_global_signal_mutex;
91 static mono_cond_t _wapi_global_signal_cond;
93 static void _wapi_handle_unref_full (gpointer handle, gboolean ignore_private_busy_handles);
96 static mono_mutex_t scan_mutex;
98 #define _WAPI_PRIVATE_HANDLES(x) (&_wapi_private_handles [SLOT_INDEX ((guint32) x)][SLOT_OFFSET ((guint32) x)])
101 _WAPI_PRIVATE_HAVE_SLOT (guint32 x)
103 return (x / _WAPI_PRIVATE_MAX_SLOTS) < _WAPI_PRIVATE_MAX_SLOTS && _wapi_private_handles [SLOT_INDEX (x)];
107 _WAPI_PRIVATE_VALID_SLOT (guint32 x)
109 return SLOT_INDEX (x) < _WAPI_PRIVATE_MAX_SLOTS;
113 _wapi_handle_type (gpointer handle)
115 guint32 idx = GPOINTER_TO_UINT(handle);
117 if (!_WAPI_PRIVATE_VALID_SLOT (idx) || !_WAPI_PRIVATE_HAVE_SLOT (idx))
118 return WAPI_HANDLE_UNUSED; /* An impossible type */
120 return _WAPI_PRIVATE_HANDLES(idx)->type;
124 _wapi_handle_set_signal_state (gpointer handle, gboolean state, gboolean broadcast)
126 guint32 idx = GPOINTER_TO_UINT(handle);
127 WapiHandleBase *handle_data;
130 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
134 handle_data = _WAPI_PRIVATE_HANDLES(idx);
137 g_message ("%s: setting state of %p to %s (broadcast %s)", __func__,
138 handle, state?"TRUE":"FALSE", broadcast?"TRUE":"FALSE");
142 /* Tell everyone blocking on a single handle */
144 /* The condition the global signal cond is waiting on is the signalling of
145 * _any_ handle. So lock it before setting the signalled state.
147 thr_ret = mono_os_mutex_lock (&_wapi_global_signal_mutex);
149 g_warning ("Bad call to mono_os_mutex_lock result %d for global signal mutex", thr_ret);
150 g_assert (thr_ret == 0);
152 /* This function _must_ be called with
153 * handle->signal_mutex locked
155 handle_data->signalled=state;
157 if (broadcast == TRUE) {
158 thr_ret = mono_os_cond_broadcast (&handle_data->signal_cond);
160 g_warning ("Bad call to mono_os_cond_broadcast result %d for handle %p", thr_ret, handle);
161 g_assert (thr_ret == 0);
163 thr_ret = mono_os_cond_signal (&handle_data->signal_cond);
165 g_warning ("Bad call to mono_os_cond_signal result %d for handle %p", thr_ret, handle);
166 g_assert (thr_ret == 0);
169 /* Tell everyone blocking on multiple handles that something
172 thr_ret = mono_os_cond_broadcast (&_wapi_global_signal_cond);
174 g_warning ("Bad call to mono_os_cond_broadcast result %d for handle %p", thr_ret, handle);
175 g_assert (thr_ret == 0);
177 thr_ret = mono_os_mutex_unlock (&_wapi_global_signal_mutex);
179 g_warning ("Bad call to mono_os_mutex_unlock result %d for global signal mutex", thr_ret);
180 g_assert (thr_ret == 0);
182 handle_data->signalled=state;
187 _wapi_handle_issignalled (gpointer handle)
189 guint32 idx = GPOINTER_TO_UINT(handle);
191 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
195 return _WAPI_PRIVATE_HANDLES (idx)->signalled;
199 _wapi_handle_lock_signal_mutex (void)
202 g_message ("%s: lock global signal mutex", __func__);
205 return(mono_os_mutex_lock (&_wapi_global_signal_mutex));
209 _wapi_handle_unlock_signal_mutex (void)
212 g_message ("%s: unlock global signal mutex", __func__);
215 return(mono_os_mutex_unlock (&_wapi_global_signal_mutex));
219 _wapi_handle_lock_handle (gpointer handle)
221 guint32 idx = GPOINTER_TO_UINT(handle);
224 g_message ("%s: locking handle %p", __func__, handle);
227 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
231 _wapi_handle_ref (handle);
233 return(mono_os_mutex_lock (&_WAPI_PRIVATE_HANDLES(idx)->signal_mutex));
237 _wapi_handle_trylock_handle (gpointer handle)
239 guint32 idx = GPOINTER_TO_UINT(handle);
243 g_message ("%s: locking handle %p", __func__, handle);
246 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
250 _wapi_handle_ref (handle);
252 ret = mono_os_mutex_trylock (&_WAPI_PRIVATE_HANDLES(idx)->signal_mutex);
254 _wapi_handle_unref (handle);
261 _wapi_handle_unlock_handle (gpointer handle)
263 guint32 idx = GPOINTER_TO_UINT(handle);
267 g_message ("%s: unlocking handle %p", __func__, handle);
270 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
274 ret = mono_os_mutex_unlock (&_WAPI_PRIVATE_HANDLES(idx)->signal_mutex);
276 _wapi_handle_unref (handle);
282 wapi_getdtablesize (void)
284 return eg_getdtablesize ();
290 * Initialize the io-layer.
293 _wapi_handle_init (void)
295 g_assert ((sizeof (handle_ops) / sizeof (handle_ops[0]))
296 == WAPI_HANDLE_COUNT);
298 _wapi_fd_reserve = wapi_getdtablesize ();
300 /* This is needed by the code in _wapi_handle_new_internal */
301 _wapi_fd_reserve = (_wapi_fd_reserve + (_WAPI_HANDLE_INITIAL_COUNT - 1)) & ~(_WAPI_HANDLE_INITIAL_COUNT - 1);
305 * The entries in _wapi_private_handles reserved for fds are allocated lazily to
309 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
310 _wapi_private_handle_slot_count ++;
311 } while(_wapi_fd_reserve > _wapi_private_handle_count);
313 mono_os_mutex_init (&scan_mutex);
315 mono_os_cond_init (&_wapi_global_signal_cond);
316 mono_os_mutex_init (&_wapi_global_signal_mutex);
320 _wapi_handle_cleanup (void)
324 /* Every shared handle we were using ought really to be closed
325 * by now, but to make sure just blow them all away. The
326 * exiting finalizer thread in particular races us to the
327 * program exit and doesn't always win, so it can be left
328 * cluttering up the shared file. Anything else left over is
331 for(i = SLOT_INDEX (0); _wapi_private_handles[i] != NULL; i++) {
332 for(j = SLOT_OFFSET (0); j < _WAPI_HANDLE_INITIAL_COUNT; j++) {
333 WapiHandleBase *handle_data = &_wapi_private_handles[i][j];
334 gpointer handle = GINT_TO_POINTER (i*_WAPI_HANDLE_INITIAL_COUNT+j);
336 for(k = handle_data->ref; k > 0; k--) {
337 _wapi_handle_unref_full (handle, TRUE);
342 for (i = 0; i < _WAPI_PRIVATE_MAX_SLOTS; ++i)
343 g_free (_wapi_private_handles [i]);
346 static void _wapi_handle_init_handle (WapiHandleBase *handle,
347 WapiHandleType type, gpointer handle_specific)
351 g_assert (_wapi_has_shut_down == FALSE);
354 handle->signalled = FALSE;
357 thr_ret = mono_os_cond_init (&handle->signal_cond);
358 g_assert (thr_ret == 0);
360 thr_ret = mono_os_mutex_init (&handle->signal_mutex);
361 g_assert (thr_ret == 0);
363 if (handle_specific != NULL)
364 handle->data = g_memdup (handle_specific, _wapi_handle_ops_typesize (type));
368 * _wapi_handle_new_internal:
369 * @type: Init handle to this type
371 * Search for a free handle and initialize it. Return the handle on
372 * success and 0 on failure. This is only called from
373 * _wapi_handle_new, and scan_mutex must be held.
375 static guint32 _wapi_handle_new_internal (WapiHandleType type,
376 gpointer handle_specific)
379 static guint32 last = 0;
380 gboolean retry = FALSE;
382 g_assert (_wapi_has_shut_down == FALSE);
384 /* A linear scan should be fast enough. Start from the last
385 * allocation, assuming that handles are allocated more often
386 * than they're freed. Leave the space reserved for file
390 if (last < _wapi_fd_reserve) {
391 last = _wapi_fd_reserve;
398 for(i = SLOT_INDEX (count); i < _wapi_private_handle_slot_count; i++) {
399 if (_wapi_private_handles [i]) {
400 for (k = SLOT_OFFSET (count); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
401 WapiHandleBase *handle = &_wapi_private_handles [i][k];
403 if(handle->type == WAPI_HANDLE_UNUSED) {
406 _wapi_handle_init_handle (handle, type, handle_specific);
414 if(retry && last > _wapi_fd_reserve) {
415 /* Try again from the beginning */
416 last = _wapi_fd_reserve;
420 /* Will need to expand the array. The caller will sort it out */
426 _wapi_handle_new (WapiHandleType type, gpointer handle_specific)
428 guint32 handle_idx = 0;
432 g_assert (_wapi_has_shut_down == FALSE);
434 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Creating new handle of type %s", __func__,
435 _wapi_handle_ops_typename (type));
437 g_assert(!_WAPI_FD_HANDLE(type));
439 thr_ret = mono_os_mutex_lock (&scan_mutex);
440 g_assert (thr_ret == 0);
442 while ((handle_idx = _wapi_handle_new_internal (type, handle_specific)) == 0) {
443 /* Try and expand the array, and have another go */
444 int idx = SLOT_INDEX (_wapi_private_handle_count);
445 if (idx >= _WAPI_PRIVATE_MAX_SLOTS) {
449 _wapi_private_handles [idx] = g_new0 (WapiHandleBase,
450 _WAPI_HANDLE_INITIAL_COUNT);
452 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
453 _wapi_private_handle_slot_count ++;
456 thr_ret = mono_os_mutex_unlock (&scan_mutex);
457 g_assert (thr_ret == 0);
459 if (handle_idx == 0) {
460 /* We ran out of slots */
461 handle = _WAPI_HANDLE_INVALID;
465 /* Make sure we left the space for fd mappings */
466 g_assert (handle_idx >= _wapi_fd_reserve);
468 handle = GUINT_TO_POINTER (handle_idx);
470 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Allocated new handle %p", __func__, handle);
477 init_handles_slot (int idx)
481 thr_ret = mono_os_mutex_lock (&scan_mutex);
482 g_assert (thr_ret == 0);
484 if (_wapi_private_handles [idx] == NULL) {
485 _wapi_private_handles [idx] = g_new0 (WapiHandleBase,
486 _WAPI_HANDLE_INITIAL_COUNT);
489 thr_ret = mono_os_mutex_unlock (&scan_mutex);
490 g_assert (thr_ret == 0);
493 gpointer _wapi_handle_new_fd (WapiHandleType type, int fd,
494 gpointer handle_specific)
496 WapiHandleBase *handle;
499 g_assert (_wapi_has_shut_down == FALSE);
501 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Creating new handle of type %s", __func__,
502 _wapi_handle_ops_typename (type));
504 g_assert(_WAPI_FD_HANDLE(type));
506 if (fd >= _wapi_fd_reserve) {
507 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fd %d is too big", __func__, fd);
509 return(GUINT_TO_POINTER (_WAPI_HANDLE_INVALID));
512 /* Initialize the array entries on demand */
513 if (_wapi_private_handles [SLOT_INDEX (fd)] == NULL)
514 init_handles_slot (SLOT_INDEX (fd));
516 handle = _WAPI_PRIVATE_HANDLES(fd);
518 if (handle->type != WAPI_HANDLE_UNUSED) {
519 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fd %d is already in use!", __func__, fd);
520 /* FIXME: clean up this handle? We can't do anything
521 * with the fd, cos thats the new one
525 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Assigning new fd handle %d", __func__, fd);
527 /* Prevent file share entries racing with us, when the file
528 * handle is only half initialised
530 thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
531 g_assert(thr_ret == 0);
533 _wapi_handle_init_handle (handle, type, handle_specific);
535 thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
537 return(GUINT_TO_POINTER(fd));
541 _wapi_lookup_handle (gpointer handle, WapiHandleType type,
542 gpointer *handle_specific)
544 WapiHandleBase *handle_data;
545 guint32 handle_idx = GPOINTER_TO_UINT(handle);
547 if (!_WAPI_PRIVATE_VALID_SLOT (handle_idx)) {
551 /* Initialize the array entries on demand */
552 if (_wapi_private_handles [SLOT_INDEX (handle_idx)] == NULL)
553 init_handles_slot (SLOT_INDEX (handle_idx));
555 handle_data = _WAPI_PRIVATE_HANDLES(handle_idx);
557 if (handle_data->type != type) {
561 if (handle_specific == NULL) {
565 *handle_specific = handle_data->data;
571 _wapi_handle_foreach (gboolean (*on_each)(gpointer handle, gpointer data, gpointer user_data), gpointer user_data)
573 WapiHandleBase *handle_data = NULL;
578 thr_ret = mono_os_mutex_lock (&scan_mutex);
579 g_assert (thr_ret == 0);
581 for (i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
582 if (_wapi_private_handles [i]) {
583 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
584 handle_data = &_wapi_private_handles [i][k];
585 if (handle_data->type == WAPI_HANDLE_UNUSED)
587 handle = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
588 if (on_each (handle, handle_data->data, user_data) == TRUE)
595 thr_ret = mono_os_mutex_unlock (&scan_mutex);
596 g_assert (thr_ret == 0);
599 /* This might list some shared handles twice if they are already
600 * opened by this process, and the check function returns FALSE the
601 * first time. Shared handles that are created during the search are
602 * unreffed if the check function returns FALSE, so callers must not
603 * rely on the handle persisting (unless the check function returns
605 * The caller owns the returned handle.
607 gpointer _wapi_search_handle (WapiHandleType type,
608 gboolean (*check)(gpointer test, gpointer user),
610 gpointer *handle_specific,
611 gboolean search_shared)
613 WapiHandleBase *handle_data = NULL;
616 gboolean found = FALSE;
619 thr_ret = mono_os_mutex_lock (&scan_mutex);
620 g_assert (thr_ret == 0);
622 for (i = SLOT_INDEX (0); !found && i < _wapi_private_handle_slot_count; i++) {
623 if (_wapi_private_handles [i]) {
624 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
625 handle_data = &_wapi_private_handles [i][k];
627 if (handle_data->type == type) {
628 ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
629 if (check (ret, user_data) == TRUE) {
630 _wapi_handle_ref (ret);
639 thr_ret = mono_os_mutex_unlock (&scan_mutex);
640 g_assert (thr_ret == 0);
647 if(handle_specific != NULL) {
648 *handle_specific = handle_data->data;
655 void _wapi_handle_ref (gpointer handle)
657 guint32 idx = GPOINTER_TO_UINT(handle);
658 WapiHandleBase *handle_data;
660 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
661 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Attempting to ref invalid private handle %p", __func__, handle);
665 if (_wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) {
666 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Attempting to ref unused handle %p", __func__, handle);
670 handle_data = _WAPI_PRIVATE_HANDLES(idx);
672 InterlockedIncrement ((gint32 *)&handle_data->ref);
675 g_message ("%s: %s handle %p ref now %d",
676 __func__, _wapi_handle_ops_typename (handle_data->type), handle, handle_data->ref);
680 /* The handle must not be locked on entry to this function */
681 static void _wapi_handle_unref_full (gpointer handle, gboolean ignore_private_busy_handles)
683 guint32 idx = GPOINTER_TO_UINT(handle);
684 WapiHandleBase *handle_data;
685 gboolean destroy = FALSE, early_exit = FALSE;
688 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
692 handle_data = _WAPI_PRIVATE_HANDLES(idx);
694 if (handle_data->type == WAPI_HANDLE_UNUSED) {
695 g_warning ("%s: Attempting to unref unused handle %p",
700 /* Possible race condition here if another thread refs the
701 * handle between here and setting the type to UNUSED. I
702 * could lock a mutex, but I'm not sure that allowing a handle
703 * reference to reach 0 isn't an application bug anyway.
705 destroy = (InterlockedDecrement ((gint32 *)&handle_data->ref) ==0);
708 g_message ("%s: %s handle %p ref now %d (destroy %s)",
709 __func__, _wapi_handle_ops_typename (handle_data->type), handle, handle_data->ref, destroy?"TRUE":"FALSE");
713 /* Need to copy the handle info, reset the slot in the
714 * array, and _only then_ call the close function to
715 * avoid race conditions (eg file descriptors being
716 * closed, and another file being opened getting the
717 * same fd racing the memset())
721 void (*close_func)(gpointer, gpointer);
723 type = handle_data->type;
724 data = handle_data->data;
726 thr_ret = mono_os_mutex_lock (&scan_mutex);
727 g_assert (thr_ret == 0);
729 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Destroying handle %p", __func__, handle);
731 /* Destroy the mutex and cond var. We hope nobody
732 * tried to grab them between the handle unlock and
733 * now, but pthreads doesn't have a
734 * "unlock_and_destroy" atomic function.
736 thr_ret = mono_os_mutex_destroy (&handle_data->signal_mutex);
737 /*WARNING gross hack to make cleanup not crash when exiting without the whole runtime teardown.*/
738 if (thr_ret == EBUSY && ignore_private_busy_handles) {
742 g_error ("Error destroying handle %p mutex due to %d\n", handle, thr_ret);
744 thr_ret = mono_os_cond_destroy (&handle_data->signal_cond);
745 if (thr_ret == EBUSY && ignore_private_busy_handles)
747 else if (thr_ret != 0)
748 g_error ("Error destroying handle %p cond var due to %d\n", handle, thr_ret);
751 memset (handle_data, 0, sizeof (WapiHandleBase));
753 thr_ret = mono_os_mutex_unlock (&scan_mutex);
754 g_assert (thr_ret == 0);
759 close_func = _wapi_handle_ops_get_close_func (type);
760 if (close_func != NULL) {
761 close_func (handle, data);
768 void _wapi_handle_unref (gpointer handle)
770 _wapi_handle_unref_full (handle, FALSE);
774 _wapi_handle_register_ops (WapiHandleType type, WapiHandleOps *ops)
776 handle_ops [type] = ops;
779 void _wapi_handle_register_capabilities (WapiHandleType type,
780 WapiHandleCapability caps)
782 handle_caps[type] = caps;
785 gboolean _wapi_handle_test_capabilities (gpointer handle,
786 WapiHandleCapability caps)
788 guint32 idx = GPOINTER_TO_UINT(handle);
791 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
795 type = _WAPI_PRIVATE_HANDLES(idx)->type;
797 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: testing 0x%x against 0x%x (%d)", __func__,
798 handle_caps[type], caps, handle_caps[type] & caps);
800 return((handle_caps[type] & caps) != 0);
803 static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer)
805 if (handle_ops[type] != NULL &&
806 handle_ops[type]->close != NULL) {
807 return (handle_ops[type]->close);
813 void _wapi_handle_ops_close (gpointer handle, gpointer data)
815 guint32 idx = GPOINTER_TO_UINT(handle);
818 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
822 type = _WAPI_PRIVATE_HANDLES(idx)->type;
824 if (handle_ops[type] != NULL &&
825 handle_ops[type]->close != NULL) {
826 handle_ops[type]->close (handle, data);
830 void _wapi_handle_ops_details (WapiHandleType type, gpointer data)
832 if (handle_ops[type] != NULL &&
833 handle_ops[type]->details != NULL) {
834 handle_ops[type]->details (data);
838 const gchar* _wapi_handle_ops_typename (WapiHandleType type)
840 g_assert (handle_ops [type]);
841 g_assert (handle_ops [type]->typename);
842 return handle_ops [type]->typename ();
845 gsize _wapi_handle_ops_typesize (WapiHandleType type)
847 g_assert (handle_ops [type]);
848 g_assert (handle_ops [type]->typesize);
849 return handle_ops [type]->typesize ();
852 void _wapi_handle_ops_signal (gpointer handle)
854 guint32 idx = GPOINTER_TO_UINT(handle);
857 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
861 type = _WAPI_PRIVATE_HANDLES(idx)->type;
863 if (handle_ops[type] != NULL && handle_ops[type]->signal != NULL) {
864 handle_ops[type]->signal (handle);
868 gboolean _wapi_handle_ops_own (gpointer handle)
870 guint32 idx = GPOINTER_TO_UINT(handle);
873 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
877 type = _WAPI_PRIVATE_HANDLES(idx)->type;
879 if (handle_ops[type] != NULL && handle_ops[type]->own_handle != NULL) {
880 return(handle_ops[type]->own_handle (handle));
886 gboolean _wapi_handle_ops_isowned (gpointer handle)
888 guint32 idx = GPOINTER_TO_UINT(handle);
891 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
895 type = _WAPI_PRIVATE_HANDLES(idx)->type;
897 if (handle_ops[type] != NULL && handle_ops[type]->is_owned != NULL) {
898 return(handle_ops[type]->is_owned (handle));
904 guint32 _wapi_handle_ops_special_wait (gpointer handle, guint32 timeout, gboolean alertable)
906 guint32 idx = GPOINTER_TO_UINT(handle);
909 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
913 type = _WAPI_PRIVATE_HANDLES(idx)->type;
915 if (handle_ops[type] != NULL &&
916 handle_ops[type]->special_wait != NULL) {
917 return(handle_ops[type]->special_wait (handle, timeout, alertable));
923 void _wapi_handle_ops_prewait (gpointer handle)
925 guint32 idx = GPOINTER_TO_UINT (handle);
928 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
932 type = _WAPI_PRIVATE_HANDLES (idx)->type;
934 if (handle_ops[type] != NULL &&
935 handle_ops[type]->prewait != NULL) {
936 handle_ops[type]->prewait (handle);
943 * @handle: The handle to release
945 * Closes and invalidates @handle, releasing any resources it
946 * consumes. When the last handle to a temporary or non-persistent
947 * object is closed, that object can be deleted. Closing the same
948 * handle twice is an error.
950 * Return value: %TRUE on success, %FALSE otherwise.
952 gboolean CloseHandle(gpointer handle)
954 if (handle == NULL) {
955 /* Problem: because we map file descriptors to the
956 * same-numbered handle we can't tell the difference
957 * between a bogus handle and the handle to stdin.
958 * Assume that it's the console handle if that handle
961 if (_WAPI_PRIVATE_HANDLES (0)->type != WAPI_HANDLE_CONSOLE) {
962 SetLastError (ERROR_INVALID_PARAMETER);
966 if (handle == _WAPI_HANDLE_INVALID){
967 SetLastError (ERROR_INVALID_PARAMETER);
971 _wapi_handle_unref (handle);
976 /* Lots more to implement here, but this is all we need at the moment */
977 gboolean DuplicateHandle (gpointer srcprocess, gpointer src,
978 gpointer targetprocess, gpointer *target,
979 guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, guint32 options G_GNUC_UNUSED)
981 if (srcprocess != _WAPI_PROCESS_CURRENT ||
982 targetprocess != _WAPI_PROCESS_CURRENT) {
983 /* Duplicating other process's handles is not supported */
984 SetLastError (ERROR_INVALID_HANDLE);
988 if (src == _WAPI_PROCESS_CURRENT) {
989 *target = _wapi_process_duplicate ();
990 } else if (src == _WAPI_THREAD_CURRENT) {
991 g_assert_not_reached ();
993 _wapi_handle_ref (src);
1000 gboolean _wapi_handle_count_signalled_handles (guint32 numhandles,
1006 guint32 count, i, iter=0;
1010 /* Lock all the handles, with backoff */
1012 for(i=0; i<numhandles; i++) {
1013 gpointer handle = handles[i];
1015 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: attempting to lock %p", __func__, handle);
1017 thr_ret = _wapi_handle_trylock_handle (handle);
1022 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: attempt failed for %p: %s", __func__,
1023 handle, strerror (thr_ret));
1026 handle = handles[i];
1028 thr_ret = _wapi_handle_unlock_handle (handle);
1029 g_assert (thr_ret == 0);
1032 /* If iter ever reaches 100 the nanosleep will
1033 * return EINVAL immediately, but we have a
1034 * design flaw if that happens.
1038 g_warning ("%s: iteration overflow!",
1043 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Backing off for %d ms", __func__,
1045 _wapi_handle_spin (10 * iter);
1051 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Locked all handles", __func__);
1056 for(i=0; i<numhandles; i++) {
1057 gpointer handle = handles[i];
1059 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Checking handle %p", __func__, handle);
1061 if(((_wapi_handle_test_capabilities (handle, WAPI_HANDLE_CAP_OWN)==TRUE) &&
1062 (_wapi_handle_ops_isowned (handle) == TRUE)) ||
1063 (_wapi_handle_issignalled (handle))) {
1066 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Handle %p signalled", __func__,
1074 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: %d event handles signalled", __func__, count);
1076 if ((waitall == TRUE && count == numhandles) ||
1077 (waitall == FALSE && count > 0)) {
1083 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Returning %d", __func__, ret);
1090 void _wapi_handle_unlock_handles (guint32 numhandles, gpointer *handles)
1095 for(i=0; i<numhandles; i++) {
1096 gpointer handle = handles[i];
1098 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unlocking handle %p", __func__, handle);
1100 thr_ret = _wapi_handle_unlock_handle (handle);
1101 g_assert (thr_ret == 0);
1106 _wapi_handle_timedwait_signal_naked (mono_cond_t *cond, mono_mutex_t *mutex, guint32 timeout, gboolean poll, gboolean *alerted)
1111 res = mono_os_cond_timedwait (cond, mutex, timeout);
1113 /* This is needed when waiting for process handles */
1116 * pthread_cond_(timed)wait() can return 0 even if the condition was not
1117 * signalled. This happens at least on Darwin. We surface this, i.e., we
1118 * get spurious wake-ups.
1120 * http://pubs.opengroup.org/onlinepubs/007908775/xsh/pthread_cond_wait.html
1122 res = mono_os_cond_timedwait (cond, mutex, timeout);
1124 if (timeout < 100) {
1125 /* Real timeout is less than 100ms time */
1126 res = mono_os_cond_timedwait (cond, mutex, timeout);
1128 res = mono_os_cond_timedwait (cond, mutex, 100);
1130 /* Mask the fake timeout, this will cause
1131 * another poll if the cond was not really signaled
1133 if (res == ETIMEDOUT)
1143 signal_global (gpointer unused)
1145 /* If we reach here, then interrupt token is set to the flag value, which
1146 * means that the target thread is either
1147 * - before the first CAS in timedwait, which means it won't enter the wait.
1148 * - it is after the first CAS, so it is already waiting, or it will enter
1149 * the wait, and it will be interrupted by the broadcast. */
1150 mono_os_mutex_lock (&_wapi_global_signal_mutex);
1151 mono_os_cond_broadcast (&_wapi_global_signal_cond);
1152 mono_os_mutex_unlock (&_wapi_global_signal_mutex);
1156 _wapi_handle_timedwait_signal (guint32 timeout, gboolean poll, gboolean *alerted)
1160 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: waiting for global", __func__);
1166 mono_thread_info_install_interrupt (signal_global, NULL, alerted);
1171 res = _wapi_handle_timedwait_signal_naked (&_wapi_global_signal_cond, &_wapi_global_signal_mutex, timeout, poll, alerted);
1174 mono_thread_info_uninstall_interrupt (alerted);
1180 signal_handle_and_unref (gpointer handle)
1182 WapiHandleBase *handle_data;
1184 mono_mutex_t *mutex;
1187 idx = GPOINTER_TO_UINT (handle);
1189 handle_data = _WAPI_PRIVATE_HANDLES (idx);
1190 g_assert (handle_data->type != WAPI_HANDLE_UNUSED);
1192 /* If we reach here, then interrupt token is set to the flag value, which
1193 * means that the target thread is either
1194 * - before the first CAS in timedwait, which means it won't enter the wait.
1195 * - it is after the first CAS, so it is already waiting, or it will enter
1196 * the wait, and it will be interrupted by the broadcast. */
1197 cond = &handle_data->signal_cond;
1198 mutex = &handle_data->signal_mutex;
1200 mono_os_mutex_lock (mutex);
1201 mono_os_cond_broadcast (cond);
1202 mono_os_mutex_unlock (mutex);
1204 _wapi_handle_unref (handle);
1208 _wapi_handle_timedwait_signal_handle (gpointer handle, guint32 timeout, gboolean poll, gboolean *alerted)
1211 WapiHandleBase *handle_data;
1214 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: waiting for %p (type %s)", __func__, handle,
1215 _wapi_handle_ops_typename (_wapi_handle_type (handle)));
1220 idx = GPOINTER_TO_UINT(handle);
1221 handle_data = _WAPI_PRIVATE_HANDLES (idx);
1224 mono_thread_info_install_interrupt (signal_handle_and_unref, handle, alerted);
1227 _wapi_handle_ref (handle);
1230 res = _wapi_handle_timedwait_signal_naked (&handle_data->signal_cond, &handle_data->signal_mutex, timeout, poll, alerted);
1233 mono_thread_info_uninstall_interrupt (alerted);
1235 /* if it is alerted, then the handle is unref in the interrupt callback */
1236 _wapi_handle_unref (handle);
1243 void _wapi_handle_dump (void)
1245 WapiHandleBase *handle_data;
1249 thr_ret = mono_os_mutex_lock (&scan_mutex);
1250 g_assert (thr_ret == 0);
1252 for(i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
1253 if (_wapi_private_handles [i]) {
1254 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
1255 handle_data = &_wapi_private_handles [i][k];
1257 if (handle_data->type == WAPI_HANDLE_UNUSED) {
1261 g_print ("%3x [%7s] %s %d ",
1262 i * _WAPI_HANDLE_INITIAL_COUNT + k,
1263 _wapi_handle_ops_typename (handle_data->type),
1264 handle_data->signalled?"Sg":"Un",
1266 _wapi_handle_ops_details (handle_data->type, handle_data->data);
1272 thr_ret = mono_os_mutex_unlock (&scan_mutex);
1273 g_assert (thr_ret == 0);