2 * w32handle.c: Generic and internal operations on handles
5 * Dick Porter (dick@ximian.com)
6 * Ludovic Henry (luhenry@microsoft.com)
8 * (C) 2002-2011 Novell, Inc.
9 * Copyright 2011 Xamarin Inc
10 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
16 #include "w32handle.h"
18 #include "utils/atomic.h"
19 #include "utils/mono-logger-internals.h"
20 #include "utils/mono-os-mutex.h"
21 #include "utils/mono-proclib.h"
22 #include "utils/mono-threads.h"
23 #include "utils/mono-time.h"
27 #define SLOT_MAX (1024 * 16)
29 /* must be a power of 2 */
30 #define HANDLE_PER_SLOT (256)
33 MonoW32HandleType type;
36 mono_mutex_t signal_mutex;
37 mono_cond_t signal_cond;
41 static MonoW32HandleCapability handle_caps [MONO_W32HANDLE_COUNT];
42 static MonoW32HandleOps *handle_ops [MONO_W32HANDLE_COUNT];
45 * We can hold SLOT_MAX * HANDLE_PER_SLOT handles.
46 * If 4M handles are not enough... Oh, well... we will crash.
48 #define SLOT_INDEX(x) (x / HANDLE_PER_SLOT)
49 #define SLOT_OFFSET(x) (x % HANDLE_PER_SLOT)
51 static MonoW32HandleBase *private_handles [SLOT_MAX];
52 static guint32 private_handles_count = 0;
53 static guint32 private_handles_slots_count = 0;
55 guint32 mono_w32handle_fd_reserve;
58 * This is an internal handle which is used for handling waiting for multiple handles.
59 * Threads which wait for multiple handles wait on this one handle, and when a handle
60 * is signalled, this handle is signalled too.
62 static mono_mutex_t global_signal_mutex;
63 static mono_cond_t global_signal_cond;
65 static mono_mutex_t scan_mutex;
67 static gboolean shutting_down = FALSE;
70 type_is_fd (MonoW32HandleType type)
73 case MONO_W32HANDLE_FILE:
74 case MONO_W32HANDLE_CONSOLE:
75 case MONO_W32HANDLE_SOCKET:
76 case MONO_W32HANDLE_PIPE:
84 mono_w32handle_lookup_data (gpointer handle, MonoW32HandleBase **handle_data)
88 g_assert (handle_data);
90 index = SLOT_INDEX ((gsize) handle);
91 if (index >= SLOT_MAX)
93 if (!private_handles [index])
96 offset = SLOT_OFFSET ((gsize) handle);
97 if (private_handles [index][offset].type == MONO_W32HANDLE_UNUSED)
100 *handle_data = &private_handles [index][offset];
105 mono_w32handle_get_type (gpointer handle)
107 MonoW32HandleBase *handle_data;
109 if (!mono_w32handle_lookup_data (handle, &handle_data))
110 return MONO_W32HANDLE_UNUSED; /* An impossible type */
112 return handle_data->type;
116 mono_w32handle_ops_typename (MonoW32HandleType type);
119 mono_w32handle_get_typename (MonoW32HandleType type)
121 return mono_w32handle_ops_typename (type);
125 mono_w32handle_set_signal_state (gpointer handle, gboolean state, gboolean broadcast)
127 MonoW32HandleBase *handle_data;
129 if (!mono_w32handle_lookup_data (handle, &handle_data)) {
134 g_message ("%s: setting state of %p to %s (broadcast %s)", __func__,
135 handle, state?"TRUE":"FALSE", broadcast?"TRUE":"FALSE");
139 /* Tell everyone blocking on a single handle */
141 /* The condition the global signal cond is waiting on is the signalling of
142 * _any_ handle. So lock it before setting the signalled state.
144 mono_os_mutex_lock (&global_signal_mutex);
146 /* This function _must_ be called with
147 * handle->signal_mutex locked
149 handle_data->signalled=state;
151 if (broadcast == TRUE) {
152 mono_os_cond_broadcast (&handle_data->signal_cond);
154 mono_os_cond_signal (&handle_data->signal_cond);
157 /* Tell everyone blocking on multiple handles that something
160 mono_os_cond_broadcast (&global_signal_cond);
162 mono_os_mutex_unlock (&global_signal_mutex);
164 handle_data->signalled=state;
169 mono_w32handle_issignalled (gpointer handle)
171 MonoW32HandleBase *handle_data;
173 if (!mono_w32handle_lookup_data (handle, &handle_data)) {
177 return handle_data->signalled;
181 mono_w32handle_lock_signal_mutex (void)
184 g_message ("%s: lock global signal mutex", __func__);
187 mono_os_mutex_lock (&global_signal_mutex);
191 mono_w32handle_unlock_signal_mutex (void)
194 g_message ("%s: unlock global signal mutex", __func__);
197 mono_os_mutex_unlock (&global_signal_mutex);
201 mono_w32handle_lock_handle (gpointer handle)
203 MonoW32HandleBase *handle_data;
205 if (!mono_w32handle_lookup_data (handle, &handle_data))
206 g_error ("%s: failed to lookup handle %p", __func__, handle);
208 mono_w32handle_ref (handle);
210 mono_os_mutex_lock (&handle_data->signal_mutex);
212 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: lock handle %p", __func__, handle);
216 mono_w32handle_trylock_handle (gpointer handle)
218 MonoW32HandleBase *handle_data;
221 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: trylock handle %p", __func__, handle);
223 if (!mono_w32handle_lookup_data (handle, &handle_data))
224 g_error ("%s: failed to lookup handle %p", __func__, handle);
226 mono_w32handle_ref (handle);
228 locked = mono_os_mutex_trylock (&handle_data->signal_mutex) == 0;
230 mono_w32handle_unref (handle);
232 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: trylock handle %p, locked: %s", __func__, handle, locked ? "true" : "false");
238 mono_w32handle_unlock_handle (gpointer handle)
240 MonoW32HandleBase *handle_data;
242 if (!mono_w32handle_lookup_data (handle, &handle_data))
243 g_error ("%s: failed to lookup handle %p", __func__, handle);
245 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: unlock handle %p", __func__, handle);
247 mono_os_mutex_unlock (&handle_data->signal_mutex);
249 mono_w32handle_unref (handle);
253 mono_w32handle_init (void)
255 static gboolean initialized = FALSE;
260 g_assert ((sizeof (handle_ops) / sizeof (handle_ops[0]))
261 == MONO_W32HANDLE_COUNT);
263 /* This is needed by the code in mono_w32handle_new_internal */
264 mono_w32handle_fd_reserve = (eg_getdtablesize () + (HANDLE_PER_SLOT - 1)) & ~(HANDLE_PER_SLOT - 1);
268 * The entries in private_handles reserved for fds are allocated lazily to
272 private_handles_count += HANDLE_PER_SLOT;
273 private_handles_slots_count ++;
274 } while(mono_w32handle_fd_reserve > private_handles_count);
276 mono_os_mutex_init (&scan_mutex);
278 mono_os_cond_init (&global_signal_cond);
279 mono_os_mutex_init (&global_signal_mutex);
285 mono_w32handle_cleanup (void)
289 g_assert (!shutting_down);
290 shutting_down = TRUE;
292 /* Every shared handle we were using ought really to be closed
293 * by now, but to make sure just blow them all away. The
294 * exiting finalizer thread in particular races us to the
295 * program exit and doesn't always win, so it can be left
296 * cluttering up the shared file. Anything else left over is
299 for(i = SLOT_INDEX (0); private_handles[i] != NULL; i++) {
300 for(j = SLOT_OFFSET (0); j < HANDLE_PER_SLOT; j++) {
301 MonoW32HandleBase *handle_data = &private_handles[i][j];
302 gpointer handle = GINT_TO_POINTER (i*HANDLE_PER_SLOT+j);
304 for(k = handle_data->ref; k > 0; k--) {
305 mono_w32handle_unref (handle);
310 for (i = 0; i < SLOT_MAX; ++i)
311 g_free (private_handles [i]);
315 mono_w32handle_ops_typesize (MonoW32HandleType type);
317 static void mono_w32handle_init_handle (MonoW32HandleBase *handle,
318 MonoW32HandleType type, gpointer handle_specific)
320 g_assert (handle->ref == 0);
323 handle->signalled = FALSE;
326 mono_os_cond_init (&handle->signal_cond);
327 mono_os_mutex_init (&handle->signal_mutex);
330 handle->specific = g_memdup (handle_specific, mono_w32handle_ops_typesize (type));
334 * mono_w32handle_new_internal:
335 * @type: Init handle to this type
337 * Search for a free handle and initialize it. Return the handle on
338 * success and 0 on failure. This is only called from
339 * mono_w32handle_new, and scan_mutex must be held.
341 static guint32 mono_w32handle_new_internal (MonoW32HandleType type,
342 gpointer handle_specific)
345 static guint32 last = 0;
346 gboolean retry = FALSE;
348 /* A linear scan should be fast enough. Start from the last
349 * allocation, assuming that handles are allocated more often
350 * than they're freed. Leave the space reserved for file
354 if (last < mono_w32handle_fd_reserve) {
355 last = mono_w32handle_fd_reserve;
362 for(i = SLOT_INDEX (count); i < private_handles_slots_count; i++) {
363 if (private_handles [i]) {
364 for (k = SLOT_OFFSET (count); k < HANDLE_PER_SLOT; k++) {
365 MonoW32HandleBase *handle = &private_handles [i][k];
367 if(handle->type == MONO_W32HANDLE_UNUSED) {
370 mono_w32handle_init_handle (handle, type, handle_specific);
378 if(retry && last > mono_w32handle_fd_reserve) {
379 /* Try again from the beginning */
380 last = mono_w32handle_fd_reserve;
384 /* Will need to expand the array. The caller will sort it out */
390 mono_w32handle_new (MonoW32HandleType type, gpointer handle_specific)
392 guint32 handle_idx = 0;
395 g_assert (!shutting_down);
397 g_assert(!type_is_fd(type));
399 mono_os_mutex_lock (&scan_mutex);
401 while ((handle_idx = mono_w32handle_new_internal (type, handle_specific)) == 0) {
402 /* Try and expand the array, and have another go */
403 int idx = SLOT_INDEX (private_handles_count);
404 if (idx >= SLOT_MAX) {
408 private_handles [idx] = g_new0 (MonoW32HandleBase, HANDLE_PER_SLOT);
410 private_handles_count += HANDLE_PER_SLOT;
411 private_handles_slots_count ++;
414 mono_os_mutex_unlock (&scan_mutex);
416 if (handle_idx == 0) {
417 /* We ran out of slots */
418 handle = INVALID_HANDLE_VALUE;
419 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: failed to create %s handle", __func__, mono_w32handle_ops_typename (type));
423 /* Make sure we left the space for fd mappings */
424 g_assert (handle_idx >= mono_w32handle_fd_reserve);
426 handle = GUINT_TO_POINTER (handle_idx);
428 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: create %s handle %p", __func__, mono_w32handle_ops_typename (type), handle);
434 gpointer mono_w32handle_new_fd (MonoW32HandleType type, int fd,
435 gpointer handle_specific)
437 MonoW32HandleBase *handle_data;
438 int fd_index, fd_offset;
440 g_assert (!shutting_down);
442 g_assert(type_is_fd(type));
444 if (fd >= mono_w32handle_fd_reserve) {
445 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));
447 return(GUINT_TO_POINTER (INVALID_HANDLE_VALUE));
450 fd_index = SLOT_INDEX (fd);
451 fd_offset = SLOT_OFFSET (fd);
453 /* Initialize the array entries on demand */
454 if (!private_handles [fd_index]) {
455 mono_os_mutex_lock (&scan_mutex);
457 if (!private_handles [fd_index])
458 private_handles [fd_index] = g_new0 (MonoW32HandleBase, HANDLE_PER_SLOT);
460 mono_os_mutex_unlock (&scan_mutex);
463 handle_data = &private_handles [fd_index][fd_offset];
465 if (handle_data->type != MONO_W32HANDLE_UNUSED) {
466 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));
467 /* FIXME: clean up this handle? We can't do anything
468 * with the fd, cos thats the new one
470 return(GUINT_TO_POINTER (INVALID_HANDLE_VALUE));
473 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: create %s handle %p", __func__, mono_w32handle_ops_typename (type), GUINT_TO_POINTER(fd));
475 mono_w32handle_init_handle (handle_data, type, handle_specific);
477 return(GUINT_TO_POINTER(fd));
481 mono_w32handle_close (gpointer handle)
483 if (handle == INVALID_HANDLE_VALUE)
485 if (handle == (gpointer) 0 && mono_w32handle_get_type (handle) != MONO_W32HANDLE_CONSOLE) {
486 /* Problem: because we map file descriptors to the
487 * same-numbered handle we can't tell the difference
488 * between a bogus handle and the handle to stdin.
489 * Assume that it's the console handle if that handle
494 mono_w32handle_unref (handle);
499 mono_w32handle_lookup (gpointer handle, MonoW32HandleType type,
500 gpointer *handle_specific)
502 MonoW32HandleBase *handle_data;
504 g_assert (handle_specific);
506 if (!mono_w32handle_lookup_data (handle, &handle_data)) {
510 if (handle_data->type != type) {
514 *handle_specific = handle_data->specific;
520 mono_w32handle_ref_core (gpointer handle, MonoW32HandleBase *handle_data);
523 mono_w32handle_unref_core (gpointer handle, MonoW32HandleBase *handle_data);
526 w32handle_destroy (gpointer handle);
529 mono_w32handle_foreach (gboolean (*on_each)(gpointer handle, gpointer data, gpointer user_data), gpointer user_data)
531 GPtrArray *handles_to_destroy;
534 handles_to_destroy = NULL;
536 mono_os_mutex_lock (&scan_mutex);
538 for (i = SLOT_INDEX (0); i < private_handles_slots_count; i++) {
539 if (!private_handles [i])
541 for (k = SLOT_OFFSET (0); k < HANDLE_PER_SLOT; k++) {
542 MonoW32HandleBase *handle_data = NULL;
544 gboolean destroy, finished;
546 handle_data = &private_handles [i][k];
547 if (handle_data->type == MONO_W32HANDLE_UNUSED)
550 handle = GUINT_TO_POINTER (i * HANDLE_PER_SLOT + k);
552 if (!mono_w32handle_ref_core (handle, handle_data)) {
553 /* we are racing with mono_w32handle_unref:
554 * the handle ref has been decremented, but it
555 * hasn't yet been destroyed. */
559 finished = on_each (handle, handle_data->specific, user_data);
561 /* we might have to destroy the handle here, as
562 * it could have been unrefed in another thread */
563 destroy = mono_w32handle_unref_core (handle, handle_data);
565 /* we do not destroy it while holding the scan_mutex
566 * lock, because w32handle_destroy also needs to take
567 * the lock, and it calls user code which might lead
569 if (!handles_to_destroy)
570 handles_to_destroy = g_ptr_array_sized_new (4);
571 g_ptr_array_add (handles_to_destroy, handle);
580 mono_os_mutex_unlock (&scan_mutex);
582 if (handles_to_destroy) {
583 for (i = 0; i < handles_to_destroy->len; ++i)
584 w32handle_destroy (handles_to_destroy->pdata [i]);
586 g_ptr_array_free (handles_to_destroy, TRUE);
591 mono_w32handle_ref_core (gpointer handle, MonoW32HandleBase *handle_data)
596 old = handle_data->ref;
601 } while (InterlockedCompareExchange ((gint32*) &handle_data->ref, new, old) != old);
603 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: ref %s handle %p, ref: %d -> %d",
604 __func__, mono_w32handle_ops_typename (handle_data->type), handle, old, new);
610 mono_w32handle_unref_core (gpointer handle, MonoW32HandleBase *handle_data)
612 MonoW32HandleType type;
615 type = handle_data->type;
618 old = handle_data->ref;
620 g_error ("%s: handle %p has ref %d, it should be >= 1", __func__, handle, old);
623 } while (InterlockedCompareExchange ((gint32*) &handle_data->ref, new, old) != old);
625 /* handle_data might contain invalid data from now on, if
626 * another thread is unref'ing this handle at the same time */
628 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: unref %s handle %p, ref: %d -> %d destroy: %s",
629 __func__, mono_w32handle_ops_typename (type), handle, old, new, new == 0 ? "true" : "false");
634 void mono_w32handle_ref (gpointer handle)
636 MonoW32HandleBase *handle_data;
638 if (!mono_w32handle_lookup_data (handle, &handle_data)) {
639 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: failed to ref handle %p, unknown handle", __func__, handle);
643 if (!mono_w32handle_ref_core (handle, handle_data))
644 g_error ("%s: failed to ref handle %p", __func__, handle);
647 static void (*_wapi_handle_ops_get_close_func (MonoW32HandleType type))(gpointer, gpointer);
650 w32handle_destroy (gpointer handle)
652 /* Need to copy the handle info, reset the slot in the
653 * array, and _only then_ call the close function to
654 * avoid race conditions (eg file descriptors being
655 * closed, and another file being opened getting the
656 * same fd racing the memset())
658 MonoW32HandleBase *handle_data;
659 MonoW32HandleType type;
660 gpointer handle_specific;
661 void (*close_func)(gpointer, gpointer);
663 if (!mono_w32handle_lookup_data (handle, &handle_data))
664 g_error ("%s: unknown handle %p", __func__, handle);
666 type = handle_data->type;
667 handle_specific = handle_data->specific;
669 mono_os_mutex_lock (&scan_mutex);
671 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: destroy %s handle %p", __func__, mono_w32handle_ops_typename (type), handle);
673 mono_os_mutex_destroy (&handle_data->signal_mutex);
674 mono_os_cond_destroy (&handle_data->signal_cond);
676 memset (handle_data, 0, sizeof (MonoW32HandleBase));
678 mono_os_mutex_unlock (&scan_mutex);
680 close_func = _wapi_handle_ops_get_close_func (type);
681 if (close_func != NULL) {
682 close_func (handle, handle_specific);
685 g_free (handle_specific);
688 /* The handle must not be locked on entry to this function */
690 mono_w32handle_unref (gpointer handle)
692 MonoW32HandleBase *handle_data;
695 if (!mono_w32handle_lookup_data (handle, &handle_data)) {
696 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: failed to unref handle %p, unknown handle",
701 destroy = mono_w32handle_unref_core (handle, handle_data);
703 w32handle_destroy (handle);
707 mono_w32handle_ops_close (gpointer handle, gpointer data);
710 mono_w32handle_force_close (gpointer handle, gpointer data)
712 mono_w32handle_ops_close (handle, data);
716 mono_w32handle_register_ops (MonoW32HandleType type, MonoW32HandleOps *ops)
718 handle_ops [type] = ops;
721 void mono_w32handle_register_capabilities (MonoW32HandleType type,
722 MonoW32HandleCapability caps)
724 handle_caps[type] = caps;
727 gboolean mono_w32handle_test_capabilities (gpointer handle,
728 MonoW32HandleCapability caps)
730 MonoW32HandleBase *handle_data;
731 MonoW32HandleType type;
733 if (!mono_w32handle_lookup_data (handle, &handle_data)) {
737 type = handle_data->type;
739 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: testing 0x%x against 0x%x (%d)", __func__,
740 handle_caps[type], caps, handle_caps[type] & caps);
742 return((handle_caps[type] & caps) != 0);
745 static void (*_wapi_handle_ops_get_close_func (MonoW32HandleType type))(gpointer, gpointer)
747 if (handle_ops[type] != NULL &&
748 handle_ops[type]->close != NULL) {
749 return (handle_ops[type]->close);
756 mono_w32handle_ops_close (gpointer handle, gpointer data)
758 MonoW32HandleBase *handle_data;
759 MonoW32HandleType type;
761 if (!mono_w32handle_lookup_data (handle, &handle_data)) {
765 type = handle_data->type;
767 if (handle_ops[type] != NULL &&
768 handle_ops[type]->close != NULL) {
769 handle_ops[type]->close (handle, data);
774 mono_w32handle_ops_details (MonoW32HandleType type, gpointer data)
776 if (handle_ops[type] != NULL &&
777 handle_ops[type]->details != NULL) {
778 handle_ops[type]->details (data);
783 mono_w32handle_ops_typename (MonoW32HandleType type)
785 g_assert (handle_ops [type]);
786 g_assert (handle_ops [type]->typename);
787 return handle_ops [type]->typename ();
791 mono_w32handle_ops_typesize (MonoW32HandleType type)
793 g_assert (handle_ops [type]);
794 g_assert (handle_ops [type]->typesize);
795 return handle_ops [type]->typesize ();
799 mono_w32handle_ops_signal (gpointer handle)
801 MonoW32HandleBase *handle_data;
802 MonoW32HandleType type;
804 if (!mono_w32handle_lookup_data (handle, &handle_data)) {
808 type = handle_data->type;
810 if (handle_ops[type] != NULL && handle_ops[type]->signal != NULL) {
811 handle_ops[type]->signal (handle);
816 mono_w32handle_ops_own (gpointer handle, gboolean *abandoned)
818 MonoW32HandleBase *handle_data;
819 MonoW32HandleType type;
821 if (!mono_w32handle_lookup_data (handle, &handle_data)) {
825 type = handle_data->type;
827 if (handle_ops[type] != NULL && handle_ops[type]->own_handle != NULL) {
828 return(handle_ops[type]->own_handle (handle, abandoned));
835 mono_w32handle_ops_isowned (gpointer handle)
837 MonoW32HandleBase *handle_data;
838 MonoW32HandleType type;
840 if (!mono_w32handle_lookup_data (handle, &handle_data)) {
844 type = handle_data->type;
846 if (handle_ops[type] != NULL && handle_ops[type]->is_owned != NULL) {
847 return(handle_ops[type]->is_owned (handle));
853 static MonoW32HandleWaitRet
854 mono_w32handle_ops_specialwait (gpointer handle, guint32 timeout, gboolean *alerted)
856 MonoW32HandleBase *handle_data;
857 MonoW32HandleType type;
859 if (!mono_w32handle_lookup_data (handle, &handle_data)) {
860 return MONO_W32HANDLE_WAIT_RET_FAILED;
863 type = handle_data->type;
865 if (handle_ops[type] != NULL &&
866 handle_ops[type]->special_wait != NULL) {
867 return(handle_ops[type]->special_wait (handle, timeout, alerted));
869 return MONO_W32HANDLE_WAIT_RET_FAILED;
874 mono_w32handle_ops_prewait (gpointer handle)
876 MonoW32HandleBase *handle_data;
877 MonoW32HandleType type;
879 if (!mono_w32handle_lookup_data (handle, &handle_data)) {
883 type = handle_data->type;
885 if (handle_ops[type] != NULL &&
886 handle_ops[type]->prewait != NULL) {
887 handle_ops[type]->prewait (handle);
897 struct timespec sleepytime;
899 g_assert (ms < 1000);
901 sleepytime.tv_sec = 0;
902 sleepytime.tv_nsec = ms * 1000000;
903 nanosleep (&sleepytime, NULL);
904 #endif /* HOST_WIN32 */
908 mono_w32handle_lock_handles (gpointer *handles, gsize numhandles)
912 /* Lock all the handles, with backoff */
914 for(i=0; i<numhandles; i++) {
915 gpointer handle = handles[i];
917 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: attempting to lock %p", __func__, handle);
919 if (!mono_w32handle_trylock_handle (handle)) {
922 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: attempt failed for %p.", __func__,
928 mono_w32handle_unlock_handle (handle);
931 /* If iter ever reaches 100 the nanosleep will
932 * return EINVAL immediately, but we have a
933 * design flaw if that happens.
937 g_warning ("%s: iteration overflow!",
942 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: Backing off for %d ms", __func__,
950 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: Locked all handles", __func__);
954 mono_w32handle_unlock_handles (gpointer *handles, gsize numhandles)
958 for(i=0; i<numhandles; i++) {
959 gpointer handle = handles[i];
961 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: unlocking handle %p", __func__, handle);
963 mono_w32handle_unlock_handle (handle);
968 mono_w32handle_timedwait_signal_naked (mono_cond_t *cond, mono_mutex_t *mutex, guint32 timeout, gboolean poll, gboolean *alerted)
973 res = mono_os_cond_timedwait (cond, mutex, timeout);
975 /* This is needed when waiting for process handles */
978 * pthread_cond_(timed)wait() can return 0 even if the condition was not
979 * signalled. This happens at least on Darwin. We surface this, i.e., we
980 * get spurious wake-ups.
982 * http://pubs.opengroup.org/onlinepubs/007908775/xsh/pthread_cond_wait.html
984 res = mono_os_cond_timedwait (cond, mutex, timeout);
987 /* Real timeout is less than 100ms time */
988 res = mono_os_cond_timedwait (cond, mutex, timeout);
990 res = mono_os_cond_timedwait (cond, mutex, 100);
992 /* Mask the fake timeout, this will cause
993 * another poll if the cond was not really signaled
1005 signal_global (gpointer unused)
1007 /* If we reach here, then interrupt token is set to the flag value, which
1008 * means that the target thread is either
1009 * - before the first CAS in timedwait, which means it won't enter the wait.
1010 * - it is after the first CAS, so it is already waiting, or it will enter
1011 * the wait, and it will be interrupted by the broadcast. */
1012 mono_os_mutex_lock (&global_signal_mutex);
1013 mono_os_cond_broadcast (&global_signal_cond);
1014 mono_os_mutex_unlock (&global_signal_mutex);
1018 mono_w32handle_timedwait_signal (guint32 timeout, gboolean poll, gboolean *alerted)
1022 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: waiting for global", __func__);
1028 mono_thread_info_install_interrupt (signal_global, NULL, alerted);
1033 res = mono_w32handle_timedwait_signal_naked (&global_signal_cond, &global_signal_mutex, timeout, poll, alerted);
1036 mono_thread_info_uninstall_interrupt (alerted);
1042 signal_handle_and_unref (gpointer handle)
1044 MonoW32HandleBase *handle_data;
1046 mono_mutex_t *mutex;
1048 if (!mono_w32handle_lookup_data (handle, &handle_data))
1049 g_error ("cannot signal unknown handle %p", handle);
1051 /* If we reach here, then interrupt token is set to the flag value, which
1052 * means that the target thread is either
1053 * - before the first CAS in timedwait, which means it won't enter the wait.
1054 * - it is after the first CAS, so it is already waiting, or it will enter
1055 * the wait, and it will be interrupted by the broadcast. */
1056 cond = &handle_data->signal_cond;
1057 mutex = &handle_data->signal_mutex;
1059 mono_os_mutex_lock (mutex);
1060 mono_os_cond_broadcast (cond);
1061 mono_os_mutex_unlock (mutex);
1063 mono_w32handle_unref (handle);
1067 mono_w32handle_timedwait_signal_handle (gpointer handle, guint32 timeout, gboolean poll, gboolean *alerted)
1069 MonoW32HandleBase *handle_data;
1072 if (!mono_w32handle_lookup_data (handle, &handle_data))
1073 g_error ("cannot wait on unknown handle %p", handle);
1075 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: waiting for %p (type %s)", __func__, handle,
1076 mono_w32handle_ops_typename (mono_w32handle_get_type (handle)));
1082 mono_thread_info_install_interrupt (signal_handle_and_unref, handle, alerted);
1085 mono_w32handle_ref (handle);
1088 res = mono_w32handle_timedwait_signal_naked (&handle_data->signal_cond, &handle_data->signal_mutex, timeout, poll, alerted);
1091 mono_thread_info_uninstall_interrupt (alerted);
1093 /* if it is alerted, then the handle is unref in the interrupt callback */
1094 mono_w32handle_unref (handle);
1102 dump_callback (gpointer handle, gpointer handle_specific, gpointer user_data)
1104 MonoW32HandleBase *handle_data;
1106 if (!mono_w32handle_lookup_data (handle, &handle_data))
1107 g_error ("cannot dump unknown handle %p", handle);
1109 g_print ("%p [%7s] signalled: %5s ref: %3d ",
1110 handle, mono_w32handle_ops_typename (handle_data->type), handle_data->signalled ? "true" : "false", handle_data->ref);
1111 mono_w32handle_ops_details (handle_data->type, handle_data->specific);
1117 void mono_w32handle_dump (void)
1119 mono_w32handle_foreach (dump_callback, NULL);
1123 own_if_signalled (gpointer handle, gboolean *abandoned)
1125 if (!mono_w32handle_issignalled (handle))
1129 mono_w32handle_ops_own (handle, abandoned);
1134 own_if_owned( gpointer handle, gboolean *abandoned)
1136 if (!mono_w32handle_ops_isowned (handle))
1140 mono_w32handle_ops_own (handle, abandoned);
1144 MonoW32HandleWaitRet
1145 mono_w32handle_wait_one (gpointer handle, guint32 timeout, gboolean alertable)
1147 MonoW32HandleWaitRet ret;
1150 gboolean abandoned = FALSE;
1154 if (mono_w32handle_test_capabilities (handle, MONO_W32HANDLE_CAP_SPECIAL_WAIT)) {
1155 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p has special wait",
1158 return mono_w32handle_ops_specialwait (handle, timeout, alertable ? &alerted : NULL);
1161 if (!mono_w32handle_test_capabilities (handle, MONO_W32HANDLE_CAP_WAIT)) {
1162 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p can't be waited for",
1165 return MONO_W32HANDLE_WAIT_RET_FAILED;
1168 mono_w32handle_lock_handle (handle);
1170 if (mono_w32handle_test_capabilities (handle, MONO_W32HANDLE_CAP_OWN)) {
1171 if (own_if_owned (handle, &abandoned)) {
1172 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p already owned",
1175 ret = abandoned ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0;
1180 if (timeout != MONO_INFINITE_WAIT)
1181 start = mono_msec_ticks ();
1186 if (own_if_signalled (handle, &abandoned)) {
1187 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p signalled",
1190 ret = abandoned ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0;
1194 mono_w32handle_ops_prewait (handle);
1196 if (timeout == MONO_INFINITE_WAIT) {
1197 waited = mono_w32handle_timedwait_signal_handle (handle, MONO_INFINITE_WAIT, FALSE, alertable ? &alerted : NULL);
1201 elapsed = mono_msec_ticks () - start;
1202 if (elapsed > timeout) {
1203 ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT;
1207 waited = mono_w32handle_timedwait_signal_handle (handle, timeout - elapsed, FALSE, alertable ? &alerted : NULL);
1211 ret = MONO_W32HANDLE_WAIT_RET_ALERTED;
1216 ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT;
1222 mono_w32handle_unlock_handle (handle);
1227 MonoW32HandleWaitRet
1228 mono_w32handle_wait_multiple (gpointer *handles, gsize nhandles, gboolean waitall, guint32 timeout, gboolean alertable)
1230 MonoW32HandleWaitRet ret;
1231 gboolean alerted, poll;
1234 gpointer handles_sorted [MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
1235 gboolean abandoned [MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS] = {0};
1238 return MONO_W32HANDLE_WAIT_RET_FAILED;
1241 return mono_w32handle_wait_one (handles [0], timeout, alertable);
1245 if (nhandles > MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
1246 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: too many handles: %zd",
1247 __func__, nhandles);
1249 return MONO_W32HANDLE_WAIT_RET_FAILED;
1252 for (i = 0; i < nhandles; ++i) {
1253 if (!mono_w32handle_test_capabilities (handles[i], MONO_W32HANDLE_CAP_WAIT)
1254 && !mono_w32handle_test_capabilities (handles[i], MONO_W32HANDLE_CAP_SPECIAL_WAIT))
1256 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p can't be waited for",
1257 __func__, handles [i]);
1259 return MONO_W32HANDLE_WAIT_RET_FAILED;
1262 handles_sorted [i] = handles [i];
1265 qsort (handles_sorted, nhandles, sizeof (gpointer), g_direct_equal);
1266 for (i = 1; i < nhandles; ++i) {
1267 if (handles_sorted [i - 1] == handles_sorted [i]) {
1268 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p is duplicated",
1269 __func__, handles_sorted [i]);
1271 return MONO_W32HANDLE_WAIT_RET_FAILED;
1276 for (i = 0; i < nhandles; ++i) {
1277 if (mono_w32handle_get_type (handles [i]) == MONO_W32HANDLE_PROCESS) {
1278 /* Can't wait for a process handle + another handle without polling */
1283 if (timeout != MONO_INFINITE_WAIT)
1284 start = mono_msec_ticks ();
1286 for (i = 0; i < nhandles; ++i) {
1287 /* Add a reference, as we need to ensure the handle wont
1288 * disappear from under us while we're waiting in the loop
1289 * (not lock, as we don't want exclusive access here) */
1290 mono_w32handle_ref (handles [i]);
1294 gsize count, lowest;
1301 mono_w32handle_lock_handles (handles, nhandles);
1303 for (i = 0; i < nhandles; i++) {
1304 if ((mono_w32handle_test_capabilities (handles [i], MONO_W32HANDLE_CAP_OWN) && mono_w32handle_ops_isowned (handles [i]))
1305 || mono_w32handle_issignalled (handles [i]))
1314 signalled = (waitall && count == nhandles) || (!waitall && count > 0);
1317 for (i = 0; i < nhandles; i++)
1318 own_if_signalled (handles [i], &abandoned [i]);
1321 mono_w32handle_unlock_handles (handles, nhandles);
1324 ret = MONO_W32HANDLE_WAIT_RET_SUCCESS_0 + lowest;
1325 for (i = lowest; i < nhandles; i++) {
1326 if (abandoned [i]) {
1327 ret = MONO_W32HANDLE_WAIT_RET_ABANDONED_0 + lowest;
1334 for (i = 0; i < nhandles; i++) {
1335 mono_w32handle_ops_prewait (handles[i]);
1337 if (mono_w32handle_test_capabilities (handles [i], MONO_W32HANDLE_CAP_SPECIAL_WAIT)
1338 && !mono_w32handle_issignalled (handles [i]))
1340 mono_w32handle_ops_specialwait (handles [i], 0, alertable ? &alerted : NULL);
1344 mono_w32handle_lock_signal_mutex ();
1348 for (i = 0; i < nhandles; ++i) {
1349 if (!mono_w32handle_issignalled (handles [i])) {
1356 for (i = 0; i < nhandles; ++i) {
1357 if (mono_w32handle_issignalled (handles [i])) {
1367 if (timeout == MONO_INFINITE_WAIT) {
1368 waited = mono_w32handle_timedwait_signal (MONO_INFINITE_WAIT, poll, alertable ? &alerted : NULL);
1372 elapsed = mono_msec_ticks () - start;
1373 if (elapsed > timeout) {
1374 ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT;
1376 mono_w32handle_unlock_signal_mutex ();
1381 waited = mono_w32handle_timedwait_signal (timeout - elapsed, poll, alertable ? &alerted : NULL);
1385 mono_w32handle_unlock_signal_mutex ();
1388 ret = MONO_W32HANDLE_WAIT_RET_ALERTED;
1393 ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT;
1399 for (i = 0; i < nhandles; i++) {
1400 /* Unref everything we reffed above */
1401 mono_w32handle_unref (handles [i]);
1407 MonoW32HandleWaitRet
1408 mono_w32handle_signal_and_wait (gpointer signal_handle, gpointer wait_handle, guint32 timeout, gboolean alertable)
1410 MonoW32HandleWaitRet ret;
1413 gboolean abandoned = FALSE;
1414 gpointer handles [2];
1418 if (!mono_w32handle_test_capabilities (signal_handle, MONO_W32HANDLE_CAP_SIGNAL))
1419 return MONO_W32HANDLE_WAIT_RET_FAILED;
1420 if (!mono_w32handle_test_capabilities (wait_handle, MONO_W32HANDLE_CAP_WAIT))
1421 return MONO_W32HANDLE_WAIT_RET_FAILED;
1423 if (mono_w32handle_test_capabilities (wait_handle, MONO_W32HANDLE_CAP_SPECIAL_WAIT)) {
1424 g_warning ("%s: handle %p has special wait, implement me!!", __func__, wait_handle);
1425 return MONO_W32HANDLE_WAIT_RET_FAILED;
1428 handles [0] = wait_handle;
1429 handles [1] = signal_handle;
1431 mono_w32handle_lock_handles (handles, 2);
1433 mono_w32handle_ops_signal (signal_handle);
1435 mono_w32handle_unlock_handle (signal_handle);
1437 if (mono_w32handle_test_capabilities (wait_handle, MONO_W32HANDLE_CAP_OWN)) {
1438 if (own_if_owned (wait_handle, &abandoned)) {
1439 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p already owned",
1440 __func__, wait_handle);
1442 ret = abandoned ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0;
1447 if (timeout != MONO_INFINITE_WAIT)
1448 start = mono_msec_ticks ();
1453 if (own_if_signalled (wait_handle, &abandoned)) {
1454 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p signalled",
1455 __func__, wait_handle);
1457 ret = abandoned ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0;
1461 mono_w32handle_ops_prewait (wait_handle);
1463 if (timeout == MONO_INFINITE_WAIT) {
1464 waited = mono_w32handle_timedwait_signal_handle (wait_handle, MONO_INFINITE_WAIT, FALSE, alertable ? &alerted : NULL);
1468 elapsed = mono_msec_ticks () - start;
1469 if (elapsed > timeout) {
1470 ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT;
1474 waited = mono_w32handle_timedwait_signal_handle (wait_handle, timeout - elapsed, FALSE, alertable ? &alerted : NULL);
1478 ret = MONO_W32HANDLE_WAIT_RET_ALERTED;
1483 ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT;
1489 mono_w32handle_unlock_handle (wait_handle);