3 * Generic and internal operations on handles
6 * Dick Porter (dick@ximian.com)
7 * Ludovic Henry (luhenry@microsoft.com)
9 * (C) 2002-2011 Novell, Inc.
10 * Copyright 2011 Xamarin Inc
11 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
17 #include "w32handle.h"
19 #include "utils/atomic.h"
20 #include "utils/mono-logger-internals.h"
21 #include "utils/mono-os-mutex.h"
22 #include "utils/mono-proclib.h"
23 #include "utils/mono-threads.h"
24 #include "utils/mono-time.h"
28 #define SLOT_MAX (1024 * 32)
30 /* must be a power of 2 */
31 #define HANDLE_PER_SLOT (256)
34 MonoW32HandleType type;
37 mono_mutex_t signal_mutex;
38 mono_cond_t signal_cond;
42 static MonoW32HandleCapability handle_caps [MONO_W32HANDLE_COUNT];
43 static MonoW32HandleOps *handle_ops [MONO_W32HANDLE_COUNT];
46 * We can hold SLOT_MAX * HANDLE_PER_SLOT handles.
47 * If 4M handles are not enough... Oh, well... we will crash.
49 #define SLOT_INDEX(x) (x / HANDLE_PER_SLOT)
50 #define SLOT_OFFSET(x) (x % HANDLE_PER_SLOT)
52 static MonoW32HandleBase *private_handles [SLOT_MAX];
53 static guint32 private_handles_count = 0;
54 static guint32 private_handles_slots_count = 0;
56 guint32 mono_w32handle_fd_reserve;
59 * This is an internal handle which is used for handling waiting for multiple handles.
60 * Threads which wait for multiple handles wait on this one handle, and when a handle
61 * is signalled, this handle is signalled too.
63 static mono_mutex_t global_signal_mutex;
64 static mono_cond_t global_signal_cond;
66 static mono_mutex_t scan_mutex;
68 static gboolean shutting_down = FALSE;
71 type_is_fd (MonoW32HandleType type)
74 case MONO_W32HANDLE_FILE:
75 case MONO_W32HANDLE_CONSOLE:
76 case MONO_W32HANDLE_SOCKET:
77 case MONO_W32HANDLE_PIPE:
85 mono_w32handle_lookup_data (gpointer handle, MonoW32HandleBase **handle_data)
89 g_assert (handle_data);
91 index = SLOT_INDEX ((gsize) handle);
92 if (index >= SLOT_MAX)
94 if (!private_handles [index])
97 offset = SLOT_OFFSET ((gsize) handle);
98 if (private_handles [index][offset].type == MONO_W32HANDLE_UNUSED)
101 *handle_data = &private_handles [index][offset];
106 mono_w32handle_get_type (gpointer handle)
108 MonoW32HandleBase *handle_data;
110 if (!mono_w32handle_lookup_data (handle, &handle_data))
111 return MONO_W32HANDLE_UNUSED; /* An impossible type */
113 return handle_data->type;
117 mono_w32handle_ops_typename (MonoW32HandleType type);
120 mono_w32handle_get_typename (MonoW32HandleType type)
122 return mono_w32handle_ops_typename (type);
126 mono_w32handle_set_signal_state (gpointer handle, gboolean state, gboolean broadcast)
128 MonoW32HandleBase *handle_data;
130 if (!mono_w32handle_lookup_data (handle, &handle_data)) {
135 g_message ("%s: setting state of %p to %s (broadcast %s)", __func__,
136 handle, state?"TRUE":"FALSE", broadcast?"TRUE":"FALSE");
140 /* Tell everyone blocking on a single handle */
142 /* The condition the global signal cond is waiting on is the signalling of
143 * _any_ handle. So lock it before setting the signalled state.
145 mono_os_mutex_lock (&global_signal_mutex);
147 /* This function _must_ be called with
148 * handle->signal_mutex locked
150 handle_data->signalled=state;
152 if (broadcast == TRUE) {
153 mono_os_cond_broadcast (&handle_data->signal_cond);
155 mono_os_cond_signal (&handle_data->signal_cond);
158 /* Tell everyone blocking on multiple handles that something
161 mono_os_cond_broadcast (&global_signal_cond);
163 mono_os_mutex_unlock (&global_signal_mutex);
165 handle_data->signalled=state;
170 mono_w32handle_issignalled (gpointer handle)
172 MonoW32HandleBase *handle_data;
174 if (!mono_w32handle_lookup_data (handle, &handle_data)) {
178 return handle_data->signalled;
182 mono_w32handle_lock_signal_mutex (void)
185 g_message ("%s: lock global signal mutex", __func__);
188 mono_os_mutex_lock (&global_signal_mutex);
192 mono_w32handle_unlock_signal_mutex (void)
195 g_message ("%s: unlock global signal mutex", __func__);
198 mono_os_mutex_unlock (&global_signal_mutex);
202 mono_w32handle_lock_handle (gpointer handle)
204 MonoW32HandleBase *handle_data;
206 if (!mono_w32handle_lookup_data (handle, &handle_data))
207 g_error ("%s: failed to lookup handle %p", __func__, handle);
209 mono_w32handle_ref (handle);
211 mono_os_mutex_lock (&handle_data->signal_mutex);
213 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: lock handle %p", __func__, handle);
217 mono_w32handle_trylock_handle (gpointer handle)
219 MonoW32HandleBase *handle_data;
222 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: trylock handle %p", __func__, handle);
224 if (!mono_w32handle_lookup_data (handle, &handle_data))
225 g_error ("%s: failed to lookup handle %p", __func__, handle);
227 mono_w32handle_ref (handle);
229 locked = mono_os_mutex_trylock (&handle_data->signal_mutex) == 0;
231 mono_w32handle_unref (handle);
233 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: trylock handle %p, locked: %s", __func__, handle, locked ? "true" : "false");
239 mono_w32handle_unlock_handle (gpointer handle)
241 MonoW32HandleBase *handle_data;
243 if (!mono_w32handle_lookup_data (handle, &handle_data))
244 g_error ("%s: failed to lookup handle %p", __func__, handle);
246 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: unlock handle %p", __func__, handle);
248 mono_os_mutex_unlock (&handle_data->signal_mutex);
250 mono_w32handle_unref (handle);
254 mono_w32handle_init (void)
256 static gboolean initialized = FALSE;
261 g_assert ((sizeof (handle_ops) / sizeof (handle_ops[0]))
262 == MONO_W32HANDLE_COUNT);
264 /* This is needed by the code in mono_w32handle_new_internal */
265 mono_w32handle_fd_reserve = (eg_getdtablesize () + (HANDLE_PER_SLOT - 1)) & ~(HANDLE_PER_SLOT - 1);
269 * The entries in private_handles reserved for fds are allocated lazily to
273 private_handles_count += HANDLE_PER_SLOT;
274 private_handles_slots_count ++;
275 } while(mono_w32handle_fd_reserve > private_handles_count);
277 mono_os_mutex_init (&scan_mutex);
279 mono_os_cond_init (&global_signal_cond);
280 mono_os_mutex_init (&global_signal_mutex);
286 mono_w32handle_cleanup (void)
290 g_assert (!shutting_down);
291 shutting_down = TRUE;
293 /* Every shared handle we were using ought really to be closed
294 * by now, but to make sure just blow them all away. The
295 * exiting finalizer thread in particular races us to the
296 * program exit and doesn't always win, so it can be left
297 * cluttering up the shared file. Anything else left over is
300 for(i = SLOT_INDEX (0); private_handles[i] != NULL; i++) {
301 for(j = SLOT_OFFSET (0); j < HANDLE_PER_SLOT; j++) {
302 MonoW32HandleBase *handle_data = &private_handles[i][j];
303 gpointer handle = GINT_TO_POINTER (i*HANDLE_PER_SLOT+j);
305 for(k = handle_data->ref; k > 0; k--) {
306 mono_w32handle_unref (handle);
311 for (i = 0; i < SLOT_MAX; ++i)
312 g_free (private_handles [i]);
316 mono_w32handle_ops_typesize (MonoW32HandleType type);
318 static void mono_w32handle_init_handle (MonoW32HandleBase *handle,
319 MonoW32HandleType type, gpointer handle_specific)
321 g_assert (handle->ref == 0);
324 handle->signalled = FALSE;
327 mono_os_cond_init (&handle->signal_cond);
328 mono_os_mutex_init (&handle->signal_mutex);
331 handle->specific = g_memdup (handle_specific, mono_w32handle_ops_typesize (type));
335 * mono_w32handle_new_internal:
336 * @type: Init handle to this type
338 * Search for a free handle and initialize it. Return the handle on
339 * success and 0 on failure. This is only called from
340 * mono_w32handle_new, and scan_mutex must be held.
342 static guint32 mono_w32handle_new_internal (MonoW32HandleType type,
343 gpointer handle_specific)
346 static guint32 last = 0;
347 gboolean retry = FALSE;
349 /* A linear scan should be fast enough. Start from the last
350 * allocation, assuming that handles are allocated more often
351 * than they're freed. Leave the space reserved for file
355 if (last < mono_w32handle_fd_reserve) {
356 last = mono_w32handle_fd_reserve;
363 for(i = SLOT_INDEX (count); i < private_handles_slots_count; i++) {
364 if (private_handles [i]) {
365 for (k = SLOT_OFFSET (count); k < HANDLE_PER_SLOT; k++) {
366 MonoW32HandleBase *handle = &private_handles [i][k];
368 if(handle->type == MONO_W32HANDLE_UNUSED) {
371 mono_w32handle_init_handle (handle, type, handle_specific);
379 if(retry && last > mono_w32handle_fd_reserve) {
380 /* Try again from the beginning */
381 last = mono_w32handle_fd_reserve;
385 /* Will need to expand the array. The caller will sort it out */
391 mono_w32handle_new (MonoW32HandleType type, gpointer handle_specific)
393 guint32 handle_idx = 0;
396 g_assert (!shutting_down);
398 g_assert(!type_is_fd(type));
400 mono_os_mutex_lock (&scan_mutex);
402 while ((handle_idx = mono_w32handle_new_internal (type, handle_specific)) == 0) {
403 /* Try and expand the array, and have another go */
404 int idx = SLOT_INDEX (private_handles_count);
405 if (idx >= SLOT_MAX) {
409 private_handles [idx] = g_new0 (MonoW32HandleBase, HANDLE_PER_SLOT);
411 private_handles_count += HANDLE_PER_SLOT;
412 private_handles_slots_count ++;
415 mono_os_mutex_unlock (&scan_mutex);
417 if (handle_idx == 0) {
418 /* We ran out of slots */
419 handle = INVALID_HANDLE_VALUE;
420 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: failed to create %s handle", __func__, mono_w32handle_ops_typename (type));
424 /* Make sure we left the space for fd mappings */
425 g_assert (handle_idx >= mono_w32handle_fd_reserve);
427 handle = GUINT_TO_POINTER (handle_idx);
429 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: create %s handle %p", __func__, mono_w32handle_ops_typename (type), handle);
435 gpointer mono_w32handle_new_fd (MonoW32HandleType type, int fd,
436 gpointer handle_specific)
438 MonoW32HandleBase *handle_data;
439 int fd_index, fd_offset;
441 g_assert (!shutting_down);
443 g_assert(type_is_fd(type));
445 if (fd >= mono_w32handle_fd_reserve) {
446 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: failed to create %s handle, fd is too big", __func__, mono_w32handle_ops_typename (type));
448 return(GUINT_TO_POINTER (INVALID_HANDLE_VALUE));
451 fd_index = SLOT_INDEX (fd);
452 fd_offset = SLOT_OFFSET (fd);
454 /* Initialize the array entries on demand */
455 if (!private_handles [fd_index]) {
456 mono_os_mutex_lock (&scan_mutex);
458 if (!private_handles [fd_index])
459 private_handles [fd_index] = g_new0 (MonoW32HandleBase, HANDLE_PER_SLOT);
461 mono_os_mutex_unlock (&scan_mutex);
464 handle_data = &private_handles [fd_index][fd_offset];
466 if (handle_data->type != MONO_W32HANDLE_UNUSED) {
467 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: failed to create %s handle, fd is already in use", __func__, mono_w32handle_ops_typename (type));
468 /* FIXME: clean up this handle? We can't do anything
469 * with the fd, cos thats the new one
471 return(GUINT_TO_POINTER (INVALID_HANDLE_VALUE));
474 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: create %s handle %p", __func__, mono_w32handle_ops_typename (type), GUINT_TO_POINTER(fd));
476 mono_w32handle_init_handle (handle_data, type, handle_specific);
478 return(GUINT_TO_POINTER(fd));
482 mono_w32handle_close (gpointer handle)
484 if (handle == INVALID_HANDLE_VALUE)
486 if (handle == (gpointer) 0 && mono_w32handle_get_type (handle) != MONO_W32HANDLE_CONSOLE) {
487 /* Problem: because we map file descriptors to the
488 * same-numbered handle we can't tell the difference
489 * between a bogus handle and the handle to stdin.
490 * Assume that it's the console handle if that handle
495 mono_w32handle_unref (handle);
500 mono_w32handle_lookup (gpointer handle, MonoW32HandleType type,
501 gpointer *handle_specific)
503 MonoW32HandleBase *handle_data;
505 g_assert (handle_specific);
507 if (!mono_w32handle_lookup_data (handle, &handle_data)) {
511 if (handle_data->type != type) {
515 *handle_specific = handle_data->specific;
521 mono_w32handle_ref_core (gpointer handle, MonoW32HandleBase *handle_data);
524 mono_w32handle_unref_core (gpointer handle, MonoW32HandleBase *handle_data);
527 w32handle_destroy (gpointer handle);
530 mono_w32handle_foreach (gboolean (*on_each)(gpointer handle, gpointer data, gpointer user_data), gpointer user_data)
532 GPtrArray *handles_to_destroy;
535 handles_to_destroy = NULL;
537 mono_os_mutex_lock (&scan_mutex);
539 for (i = SLOT_INDEX (0); i < private_handles_slots_count; i++) {
540 if (!private_handles [i])
542 for (k = SLOT_OFFSET (0); k < HANDLE_PER_SLOT; k++) {
543 MonoW32HandleBase *handle_data = NULL;
545 gboolean destroy, finished;
547 handle_data = &private_handles [i][k];
548 if (handle_data->type == MONO_W32HANDLE_UNUSED)
551 handle = GUINT_TO_POINTER (i * HANDLE_PER_SLOT + k);
553 if (!mono_w32handle_ref_core (handle, handle_data)) {
554 /* we are racing with mono_w32handle_unref:
555 * the handle ref has been decremented, but it
556 * hasn't yet been destroyed. */
560 finished = on_each (handle, handle_data->specific, user_data);
562 /* we might have to destroy the handle here, as
563 * it could have been unrefed in another thread */
564 destroy = mono_w32handle_unref_core (handle, handle_data);
566 /* we do not destroy it while holding the scan_mutex
567 * lock, because w32handle_destroy also needs to take
568 * the lock, and it calls user code which might lead
570 if (!handles_to_destroy)
571 handles_to_destroy = g_ptr_array_sized_new (4);
572 g_ptr_array_add (handles_to_destroy, handle);
581 mono_os_mutex_unlock (&scan_mutex);
583 if (handles_to_destroy) {
584 for (i = 0; i < handles_to_destroy->len; ++i)
585 w32handle_destroy (handles_to_destroy->pdata [i]);
587 g_ptr_array_free (handles_to_destroy, TRUE);
592 mono_w32handle_ref_core (gpointer handle, MonoW32HandleBase *handle_data)
597 old = handle_data->ref;
602 } while (InterlockedCompareExchange ((gint32*) &handle_data->ref, new, old) != old);
604 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: ref %s handle %p, ref: %d -> %d",
605 __func__, mono_w32handle_ops_typename (handle_data->type), handle, old, new);
611 mono_w32handle_unref_core (gpointer handle, MonoW32HandleBase *handle_data)
613 MonoW32HandleType type;
616 type = handle_data->type;
619 old = handle_data->ref;
621 g_error ("%s: handle %p has ref %d, it should be >= 1", __func__, handle, old);
624 } while (InterlockedCompareExchange ((gint32*) &handle_data->ref, new, old) != old);
626 /* handle_data might contain invalid data from now on, if
627 * another thread is unref'ing this handle at the same time */
629 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: unref %s handle %p, ref: %d -> %d destroy: %s",
630 __func__, mono_w32handle_ops_typename (type), handle, old, new, new == 0 ? "true" : "false");
635 void mono_w32handle_ref (gpointer handle)
637 MonoW32HandleBase *handle_data;
639 if (!mono_w32handle_lookup_data (handle, &handle_data)) {
640 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: failed to ref handle %p, unknown handle", __func__, handle);
644 if (!mono_w32handle_ref_core (handle, handle_data))
645 g_error ("%s: failed to ref handle %p", __func__, handle);
648 static void (*_wapi_handle_ops_get_close_func (MonoW32HandleType type))(gpointer, gpointer);
651 w32handle_destroy (gpointer handle)
653 /* Need to copy the handle info, reset the slot in the
654 * array, and _only then_ call the close function to
655 * avoid race conditions (eg file descriptors being
656 * closed, and another file being opened getting the
657 * same fd racing the memset())
659 MonoW32HandleBase *handle_data;
660 MonoW32HandleType type;
661 gpointer handle_specific;
662 void (*close_func)(gpointer, gpointer);
664 if (!mono_w32handle_lookup_data (handle, &handle_data))
665 g_error ("%s: unknown handle %p", __func__, handle);
667 type = handle_data->type;
668 handle_specific = handle_data->specific;
670 mono_os_mutex_lock (&scan_mutex);
672 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: destroy %s handle %p", __func__, mono_w32handle_ops_typename (type), handle);
674 mono_os_mutex_destroy (&handle_data->signal_mutex);
675 mono_os_cond_destroy (&handle_data->signal_cond);
677 memset (handle_data, 0, sizeof (MonoW32HandleBase));
679 mono_os_mutex_unlock (&scan_mutex);
681 close_func = _wapi_handle_ops_get_close_func (type);
682 if (close_func != NULL) {
683 close_func (handle, handle_specific);
686 g_free (handle_specific);
689 /* The handle must not be locked on entry to this function */
691 mono_w32handle_unref (gpointer handle)
693 MonoW32HandleBase *handle_data;
696 if (!mono_w32handle_lookup_data (handle, &handle_data)) {
697 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: failed to unref handle %p, unknown handle",
702 destroy = mono_w32handle_unref_core (handle, handle_data);
704 w32handle_destroy (handle);
708 mono_w32handle_ops_close (gpointer handle, gpointer data);
711 mono_w32handle_force_close (gpointer handle, gpointer data)
713 mono_w32handle_ops_close (handle, data);
717 mono_w32handle_register_ops (MonoW32HandleType type, MonoW32HandleOps *ops)
719 handle_ops [type] = ops;
722 void mono_w32handle_register_capabilities (MonoW32HandleType type,
723 MonoW32HandleCapability caps)
725 handle_caps[type] = caps;
728 gboolean mono_w32handle_test_capabilities (gpointer handle,
729 MonoW32HandleCapability caps)
731 MonoW32HandleBase *handle_data;
732 MonoW32HandleType type;
734 if (!mono_w32handle_lookup_data (handle, &handle_data)) {
738 type = handle_data->type;
740 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: testing 0x%x against 0x%x (%d)", __func__,
741 handle_caps[type], caps, handle_caps[type] & caps);
743 return((handle_caps[type] & caps) != 0);
746 static void (*_wapi_handle_ops_get_close_func (MonoW32HandleType type))(gpointer, gpointer)
748 if (handle_ops[type] != NULL &&
749 handle_ops[type]->close != NULL) {
750 return (handle_ops[type]->close);
757 mono_w32handle_ops_close (gpointer handle, gpointer data)
759 MonoW32HandleBase *handle_data;
760 MonoW32HandleType type;
762 if (!mono_w32handle_lookup_data (handle, &handle_data)) {
766 type = handle_data->type;
768 if (handle_ops[type] != NULL &&
769 handle_ops[type]->close != NULL) {
770 handle_ops[type]->close (handle, data);
775 mono_w32handle_ops_details (MonoW32HandleType type, gpointer data)
777 if (handle_ops[type] != NULL &&
778 handle_ops[type]->details != NULL) {
779 handle_ops[type]->details (data);
784 mono_w32handle_ops_typename (MonoW32HandleType type)
786 g_assert (handle_ops [type]);
787 g_assert (handle_ops [type]->typename);
788 return handle_ops [type]->typename ();
792 mono_w32handle_ops_typesize (MonoW32HandleType type)
794 g_assert (handle_ops [type]);
795 g_assert (handle_ops [type]->typesize);
796 return handle_ops [type]->typesize ();
800 mono_w32handle_ops_signal (gpointer handle)
802 MonoW32HandleBase *handle_data;
803 MonoW32HandleType type;
805 if (!mono_w32handle_lookup_data (handle, &handle_data)) {
809 type = handle_data->type;
811 if (handle_ops[type] != NULL && handle_ops[type]->signal != NULL) {
812 handle_ops[type]->signal (handle);
817 mono_w32handle_ops_own (gpointer handle, gboolean *abandoned)
819 MonoW32HandleBase *handle_data;
820 MonoW32HandleType type;
822 if (!mono_w32handle_lookup_data (handle, &handle_data)) {
826 type = handle_data->type;
828 if (handle_ops[type] != NULL && handle_ops[type]->own_handle != NULL) {
829 return(handle_ops[type]->own_handle (handle, abandoned));
836 mono_w32handle_ops_isowned (gpointer handle)
838 MonoW32HandleBase *handle_data;
839 MonoW32HandleType type;
841 if (!mono_w32handle_lookup_data (handle, &handle_data)) {
845 type = handle_data->type;
847 if (handle_ops[type] != NULL && handle_ops[type]->is_owned != NULL) {
848 return(handle_ops[type]->is_owned (handle));
854 static MonoW32HandleWaitRet
855 mono_w32handle_ops_specialwait (gpointer handle, guint32 timeout, gboolean *alerted)
857 MonoW32HandleBase *handle_data;
858 MonoW32HandleType type;
860 if (!mono_w32handle_lookup_data (handle, &handle_data)) {
861 return MONO_W32HANDLE_WAIT_RET_FAILED;
864 type = handle_data->type;
866 if (handle_ops[type] != NULL &&
867 handle_ops[type]->special_wait != NULL) {
868 return(handle_ops[type]->special_wait (handle, timeout, alerted));
870 return MONO_W32HANDLE_WAIT_RET_FAILED;
875 mono_w32handle_ops_prewait (gpointer handle)
877 MonoW32HandleBase *handle_data;
878 MonoW32HandleType type;
880 if (!mono_w32handle_lookup_data (handle, &handle_data)) {
884 type = handle_data->type;
886 if (handle_ops[type] != NULL &&
887 handle_ops[type]->prewait != NULL) {
888 handle_ops[type]->prewait (handle);
898 struct timespec sleepytime;
900 g_assert (ms < 1000);
902 sleepytime.tv_sec = 0;
903 sleepytime.tv_nsec = ms * 1000000;
904 nanosleep (&sleepytime, NULL);
905 #endif /* HOST_WIN32 */
909 mono_w32handle_lock_handles (gpointer *handles, gsize numhandles)
913 /* Lock all the handles, with backoff */
915 for(i=0; i<numhandles; i++) {
916 gpointer handle = handles[i];
918 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: attempting to lock %p", __func__, handle);
920 if (!mono_w32handle_trylock_handle (handle)) {
923 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: attempt failed for %p.", __func__,
929 mono_w32handle_unlock_handle (handle);
932 /* If iter ever reaches 100 the nanosleep will
933 * return EINVAL immediately, but we have a
934 * design flaw if that happens.
938 g_warning ("%s: iteration overflow!",
943 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: Backing off for %d ms", __func__,
951 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: Locked all handles", __func__);
955 mono_w32handle_unlock_handles (gpointer *handles, gsize numhandles)
959 for(i=0; i<numhandles; i++) {
960 gpointer handle = handles[i];
962 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: unlocking handle %p", __func__, handle);
964 mono_w32handle_unlock_handle (handle);
969 mono_w32handle_timedwait_signal_naked (mono_cond_t *cond, mono_mutex_t *mutex, guint32 timeout, gboolean poll, gboolean *alerted)
974 res = mono_os_cond_timedwait (cond, mutex, timeout);
976 /* This is needed when waiting for process handles */
979 * pthread_cond_(timed)wait() can return 0 even if the condition was not
980 * signalled. This happens at least on Darwin. We surface this, i.e., we
981 * get spurious wake-ups.
983 * http://pubs.opengroup.org/onlinepubs/007908775/xsh/pthread_cond_wait.html
985 res = mono_os_cond_timedwait (cond, mutex, timeout);
988 /* Real timeout is less than 100ms time */
989 res = mono_os_cond_timedwait (cond, mutex, timeout);
991 res = mono_os_cond_timedwait (cond, mutex, 100);
993 /* Mask the fake timeout, this will cause
994 * another poll if the cond was not really signaled
1006 signal_global (gpointer unused)
1008 /* If we reach here, then interrupt token is set to the flag value, which
1009 * means that the target thread is either
1010 * - before the first CAS in timedwait, which means it won't enter the wait.
1011 * - it is after the first CAS, so it is already waiting, or it will enter
1012 * the wait, and it will be interrupted by the broadcast. */
1013 mono_os_mutex_lock (&global_signal_mutex);
1014 mono_os_cond_broadcast (&global_signal_cond);
1015 mono_os_mutex_unlock (&global_signal_mutex);
1019 mono_w32handle_timedwait_signal (guint32 timeout, gboolean poll, gboolean *alerted)
1023 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: waiting for global", __func__);
1029 mono_thread_info_install_interrupt (signal_global, NULL, alerted);
1034 res = mono_w32handle_timedwait_signal_naked (&global_signal_cond, &global_signal_mutex, timeout, poll, alerted);
1037 mono_thread_info_uninstall_interrupt (alerted);
1043 signal_handle_and_unref (gpointer handle)
1045 MonoW32HandleBase *handle_data;
1047 mono_mutex_t *mutex;
1049 if (!mono_w32handle_lookup_data (handle, &handle_data))
1050 g_error ("cannot signal unknown handle %p", handle);
1052 /* If we reach here, then interrupt token is set to the flag value, which
1053 * means that the target thread is either
1054 * - before the first CAS in timedwait, which means it won't enter the wait.
1055 * - it is after the first CAS, so it is already waiting, or it will enter
1056 * the wait, and it will be interrupted by the broadcast. */
1057 cond = &handle_data->signal_cond;
1058 mutex = &handle_data->signal_mutex;
1060 mono_os_mutex_lock (mutex);
1061 mono_os_cond_broadcast (cond);
1062 mono_os_mutex_unlock (mutex);
1064 mono_w32handle_unref (handle);
1068 mono_w32handle_timedwait_signal_handle (gpointer handle, guint32 timeout, gboolean poll, gboolean *alerted)
1070 MonoW32HandleBase *handle_data;
1073 if (!mono_w32handle_lookup_data (handle, &handle_data))
1074 g_error ("cannot wait on unknown handle %p", handle);
1076 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: waiting for %p (type %s)", __func__, handle,
1077 mono_w32handle_ops_typename (mono_w32handle_get_type (handle)));
1083 mono_thread_info_install_interrupt (signal_handle_and_unref, handle, alerted);
1086 mono_w32handle_ref (handle);
1089 res = mono_w32handle_timedwait_signal_naked (&handle_data->signal_cond, &handle_data->signal_mutex, timeout, poll, alerted);
1092 mono_thread_info_uninstall_interrupt (alerted);
1094 /* if it is alerted, then the handle is unref in the interrupt callback */
1095 mono_w32handle_unref (handle);
1103 dump_callback (gpointer handle, gpointer handle_specific, gpointer user_data)
1105 MonoW32HandleBase *handle_data;
1107 if (!mono_w32handle_lookup_data (handle, &handle_data))
1108 g_error ("cannot dump unknown handle %p", handle);
1110 g_print ("%p [%7s] signalled: %5s ref: %3d ",
1111 handle, mono_w32handle_ops_typename (handle_data->type), handle_data->signalled ? "true" : "false", handle_data->ref);
1112 mono_w32handle_ops_details (handle_data->type, handle_data->specific);
1118 void mono_w32handle_dump (void)
1120 mono_w32handle_foreach (dump_callback, NULL);
1124 own_if_signalled (gpointer handle, gboolean *abandoned)
1126 if (!mono_w32handle_issignalled (handle))
1130 mono_w32handle_ops_own (handle, abandoned);
1135 own_if_owned( gpointer handle, gboolean *abandoned)
1137 if (!mono_w32handle_ops_isowned (handle))
1141 mono_w32handle_ops_own (handle, abandoned);
1145 MonoW32HandleWaitRet
1146 mono_w32handle_wait_one (gpointer handle, guint32 timeout, gboolean alertable)
1148 MonoW32HandleWaitRet ret;
1151 gboolean abandoned = FALSE;
1155 if (mono_w32handle_test_capabilities (handle, MONO_W32HANDLE_CAP_SPECIAL_WAIT)) {
1156 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p has special wait",
1159 return mono_w32handle_ops_specialwait (handle, timeout, alertable ? &alerted : NULL);
1162 if (!mono_w32handle_test_capabilities (handle, MONO_W32HANDLE_CAP_WAIT)) {
1163 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p can't be waited for",
1166 return MONO_W32HANDLE_WAIT_RET_FAILED;
1169 mono_w32handle_lock_handle (handle);
1171 if (mono_w32handle_test_capabilities (handle, MONO_W32HANDLE_CAP_OWN)) {
1172 if (own_if_owned (handle, &abandoned)) {
1173 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p already owned",
1176 ret = abandoned ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0;
1181 if (timeout != MONO_INFINITE_WAIT)
1182 start = mono_msec_ticks ();
1187 if (own_if_signalled (handle, &abandoned)) {
1188 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p signalled",
1191 ret = abandoned ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0;
1195 mono_w32handle_ops_prewait (handle);
1197 if (timeout == MONO_INFINITE_WAIT) {
1198 waited = mono_w32handle_timedwait_signal_handle (handle, MONO_INFINITE_WAIT, FALSE, alertable ? &alerted : NULL);
1202 elapsed = mono_msec_ticks () - start;
1203 if (elapsed > timeout) {
1204 ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT;
1208 waited = mono_w32handle_timedwait_signal_handle (handle, timeout - elapsed, FALSE, alertable ? &alerted : NULL);
1212 ret = MONO_W32HANDLE_WAIT_RET_ALERTED;
1217 ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT;
1223 mono_w32handle_unlock_handle (handle);
1228 MonoW32HandleWaitRet
1229 mono_w32handle_wait_multiple (gpointer *handles, gsize nhandles, gboolean waitall, guint32 timeout, gboolean alertable)
1231 MonoW32HandleWaitRet ret;
1232 gboolean alerted, poll;
1235 gpointer handles_sorted [MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
1236 gboolean abandoned [MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS] = {0};
1239 return MONO_W32HANDLE_WAIT_RET_FAILED;
1242 return mono_w32handle_wait_one (handles [0], timeout, alertable);
1246 if (nhandles > MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
1247 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: too many handles: %zd",
1248 __func__, nhandles);
1250 return MONO_W32HANDLE_WAIT_RET_FAILED;
1253 for (i = 0; i < nhandles; ++i) {
1254 if (!mono_w32handle_test_capabilities (handles[i], MONO_W32HANDLE_CAP_WAIT)
1255 && !mono_w32handle_test_capabilities (handles[i], MONO_W32HANDLE_CAP_SPECIAL_WAIT))
1257 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p can't be waited for",
1258 __func__, handles [i]);
1260 return MONO_W32HANDLE_WAIT_RET_FAILED;
1263 handles_sorted [i] = handles [i];
1266 qsort (handles_sorted, nhandles, sizeof (gpointer), g_direct_equal);
1267 for (i = 1; i < nhandles; ++i) {
1268 if (handles_sorted [i - 1] == handles_sorted [i]) {
1269 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p is duplicated",
1270 __func__, handles_sorted [i]);
1272 return MONO_W32HANDLE_WAIT_RET_FAILED;
1277 for (i = 0; i < nhandles; ++i) {
1278 if (mono_w32handle_get_type (handles [i]) == MONO_W32HANDLE_PROCESS) {
1279 /* Can't wait for a process handle + another handle without polling */
1284 if (timeout != MONO_INFINITE_WAIT)
1285 start = mono_msec_ticks ();
1287 for (i = 0; i < nhandles; ++i) {
1288 /* Add a reference, as we need to ensure the handle wont
1289 * disappear from under us while we're waiting in the loop
1290 * (not lock, as we don't want exclusive access here) */
1291 mono_w32handle_ref (handles [i]);
1295 gsize count, lowest;
1302 mono_w32handle_lock_handles (handles, nhandles);
1304 for (i = 0; i < nhandles; i++) {
1305 if ((mono_w32handle_test_capabilities (handles [i], MONO_W32HANDLE_CAP_OWN) && mono_w32handle_ops_isowned (handles [i]))
1306 || mono_w32handle_issignalled (handles [i]))
1315 signalled = (waitall && count == nhandles) || (!waitall && count > 0);
1318 for (i = 0; i < nhandles; i++)
1319 own_if_signalled (handles [i], &abandoned [i]);
1322 mono_w32handle_unlock_handles (handles, nhandles);
1325 ret = MONO_W32HANDLE_WAIT_RET_SUCCESS_0 + lowest;
1326 for (i = lowest; i < nhandles; i++) {
1327 if (abandoned [i]) {
1328 ret = MONO_W32HANDLE_WAIT_RET_ABANDONED_0 + lowest;
1335 for (i = 0; i < nhandles; i++) {
1336 mono_w32handle_ops_prewait (handles[i]);
1338 if (mono_w32handle_test_capabilities (handles [i], MONO_W32HANDLE_CAP_SPECIAL_WAIT)
1339 && !mono_w32handle_issignalled (handles [i]))
1341 mono_w32handle_ops_specialwait (handles [i], 0, alertable ? &alerted : NULL);
1345 mono_w32handle_lock_signal_mutex ();
1349 for (i = 0; i < nhandles; ++i) {
1350 if (!mono_w32handle_issignalled (handles [i])) {
1357 for (i = 0; i < nhandles; ++i) {
1358 if (mono_w32handle_issignalled (handles [i])) {
1368 if (timeout == MONO_INFINITE_WAIT) {
1369 waited = mono_w32handle_timedwait_signal (MONO_INFINITE_WAIT, poll, alertable ? &alerted : NULL);
1373 elapsed = mono_msec_ticks () - start;
1374 if (elapsed > timeout) {
1375 ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT;
1377 mono_w32handle_unlock_signal_mutex ();
1382 waited = mono_w32handle_timedwait_signal (timeout - elapsed, poll, alertable ? &alerted : NULL);
1386 mono_w32handle_unlock_signal_mutex ();
1389 ret = MONO_W32HANDLE_WAIT_RET_ALERTED;
1394 ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT;
1400 for (i = 0; i < nhandles; i++) {
1401 /* Unref everything we reffed above */
1402 mono_w32handle_unref (handles [i]);
1408 MonoW32HandleWaitRet
1409 mono_w32handle_signal_and_wait (gpointer signal_handle, gpointer wait_handle, guint32 timeout, gboolean alertable)
1411 MonoW32HandleWaitRet ret;
1414 gboolean abandoned = FALSE;
1415 gpointer handles [2];
1419 if (!mono_w32handle_test_capabilities (signal_handle, MONO_W32HANDLE_CAP_SIGNAL))
1420 return MONO_W32HANDLE_WAIT_RET_FAILED;
1421 if (!mono_w32handle_test_capabilities (wait_handle, MONO_W32HANDLE_CAP_WAIT))
1422 return MONO_W32HANDLE_WAIT_RET_FAILED;
1424 if (mono_w32handle_test_capabilities (wait_handle, MONO_W32HANDLE_CAP_SPECIAL_WAIT)) {
1425 g_warning ("%s: handle %p has special wait, implement me!!", __func__, wait_handle);
1426 return MONO_W32HANDLE_WAIT_RET_FAILED;
1429 handles [0] = wait_handle;
1430 handles [1] = signal_handle;
1432 mono_w32handle_lock_handles (handles, 2);
1434 mono_w32handle_ops_signal (signal_handle);
1436 mono_w32handle_unlock_handle (signal_handle);
1438 if (mono_w32handle_test_capabilities (wait_handle, MONO_W32HANDLE_CAP_OWN)) {
1439 if (own_if_owned (wait_handle, &abandoned)) {
1440 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p already owned",
1441 __func__, wait_handle);
1443 ret = abandoned ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0;
1448 if (timeout != MONO_INFINITE_WAIT)
1449 start = mono_msec_ticks ();
1454 if (own_if_signalled (wait_handle, &abandoned)) {
1455 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p signalled",
1456 __func__, wait_handle);
1458 ret = abandoned ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0;
1462 mono_w32handle_ops_prewait (wait_handle);
1464 if (timeout == MONO_INFINITE_WAIT) {
1465 waited = mono_w32handle_timedwait_signal_handle (wait_handle, MONO_INFINITE_WAIT, FALSE, alertable ? &alerted : NULL);
1469 elapsed = mono_msec_ticks () - start;
1470 if (elapsed > timeout) {
1471 ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT;
1475 waited = mono_w32handle_timedwait_signal_handle (wait_handle, timeout - elapsed, FALSE, alertable ? &alerted : NULL);
1479 ret = MONO_W32HANDLE_WAIT_RET_ALERTED;
1484 ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT;
1490 mono_w32handle_unlock_handle (wait_handle);