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;
38 mono_mutex_t signal_mutex;
39 mono_cond_t signal_cond;
43 static MonoW32HandleCapability handle_caps [MONO_W32HANDLE_COUNT];
44 static MonoW32HandleOps *handle_ops [MONO_W32HANDLE_COUNT];
47 * We can hold SLOT_MAX * HANDLE_PER_SLOT handles.
48 * If 4M handles are not enough... Oh, well... we will crash.
50 #define SLOT_INDEX(x) (x / HANDLE_PER_SLOT)
51 #define SLOT_OFFSET(x) (x % HANDLE_PER_SLOT)
53 static MonoW32HandleBase *private_handles [SLOT_MAX];
54 static guint32 private_handles_count = 0;
55 static guint32 private_handles_slots_count = 0;
57 guint32 mono_w32handle_fd_reserve;
60 * This is an internal handle which is used for handling waiting for multiple handles.
61 * Threads which wait for multiple handles wait on this one handle, and when a handle
62 * is signalled, this handle is signalled too.
64 static mono_mutex_t global_signal_mutex;
65 static mono_cond_t global_signal_cond;
67 static mono_mutex_t scan_mutex;
69 static gboolean shutting_down = FALSE;
72 type_is_fd (MonoW32HandleType type)
75 case MONO_W32HANDLE_FILE:
76 case MONO_W32HANDLE_CONSOLE:
77 case MONO_W32HANDLE_SOCKET:
78 case MONO_W32HANDLE_PIPE:
86 mono_w32handle_lookup_data (gpointer handle, MonoW32HandleBase **handle_data)
90 g_assert (handle_data);
92 index = SLOT_INDEX ((gsize) handle);
93 if (index >= SLOT_MAX)
95 if (!private_handles [index])
98 offset = SLOT_OFFSET ((gsize) handle);
99 if (private_handles [index][offset].type == MONO_W32HANDLE_UNUSED)
102 *handle_data = &private_handles [index][offset];
107 mono_w32handle_get_type (gpointer handle)
109 MonoW32HandleBase *handle_data;
111 if (!mono_w32handle_lookup_data (handle, &handle_data))
112 return MONO_W32HANDLE_UNUSED; /* An impossible type */
114 return handle_data->type;
118 mono_w32handle_ops_typename (MonoW32HandleType type);
121 mono_w32handle_get_typename (MonoW32HandleType type)
123 return mono_w32handle_ops_typename (type);
127 mono_w32handle_set_signal_state (gpointer handle, gboolean state, gboolean broadcast)
129 MonoW32HandleBase *handle_data;
131 if (!mono_w32handle_lookup_data (handle, &handle_data)) {
136 g_message ("%s: setting state of %p to %s (broadcast %s)", __func__,
137 handle, state?"TRUE":"FALSE", broadcast?"TRUE":"FALSE");
141 /* Tell everyone blocking on a single handle */
143 /* The condition the global signal cond is waiting on is the signalling of
144 * _any_ handle. So lock it before setting the signalled state.
146 mono_os_mutex_lock (&global_signal_mutex);
148 /* This function _must_ be called with
149 * handle->signal_mutex locked
151 handle_data->signalled=state;
153 if (broadcast == TRUE) {
154 mono_os_cond_broadcast (&handle_data->signal_cond);
156 mono_os_cond_signal (&handle_data->signal_cond);
159 /* Tell everyone blocking on multiple handles that something
162 mono_os_cond_broadcast (&global_signal_cond);
164 mono_os_mutex_unlock (&global_signal_mutex);
166 handle_data->signalled=state;
171 mono_w32handle_issignalled (gpointer handle)
173 MonoW32HandleBase *handle_data;
175 if (!mono_w32handle_lookup_data (handle, &handle_data)) {
179 return handle_data->signalled;
183 mono_w32handle_set_in_use (gpointer handle, gboolean in_use)
185 MonoW32HandleBase *handle_data;
187 if (!mono_w32handle_lookup_data (handle, &handle_data))
188 g_assert_not_reached ();
190 handle_data->in_use = in_use;
194 mono_w32handle_lock_signal_mutex (void)
197 g_message ("%s: lock global signal mutex", __func__);
200 mono_os_mutex_lock (&global_signal_mutex);
204 mono_w32handle_unlock_signal_mutex (void)
207 g_message ("%s: unlock global signal mutex", __func__);
210 mono_os_mutex_unlock (&global_signal_mutex);
214 mono_w32handle_lock_handle (gpointer handle)
216 MonoW32HandleBase *handle_data;
218 if (!mono_w32handle_lookup_data (handle, &handle_data))
219 g_error ("%s: failed to lookup handle %p", __func__, handle);
221 mono_w32handle_ref (handle);
223 mono_os_mutex_lock (&handle_data->signal_mutex);
225 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: lock handle %p", __func__, handle);
229 mono_w32handle_trylock_handle (gpointer handle)
231 MonoW32HandleBase *handle_data;
234 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: trylock handle %p", __func__, handle);
236 if (!mono_w32handle_lookup_data (handle, &handle_data))
237 g_error ("%s: failed to lookup handle %p", __func__, handle);
239 mono_w32handle_ref (handle);
241 locked = mono_os_mutex_trylock (&handle_data->signal_mutex) == 0;
243 mono_w32handle_unref (handle);
245 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: trylock handle %p, locked: %s", __func__, handle, locked ? "true" : "false");
251 mono_w32handle_unlock_handle (gpointer handle)
253 MonoW32HandleBase *handle_data;
255 if (!mono_w32handle_lookup_data (handle, &handle_data))
256 g_error ("%s: failed to lookup handle %p", __func__, handle);
258 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: unlock handle %p", __func__, handle);
260 mono_os_mutex_unlock (&handle_data->signal_mutex);
262 mono_w32handle_unref (handle);
266 mono_w32handle_init (void)
268 static gboolean initialized = FALSE;
273 g_assert ((sizeof (handle_ops) / sizeof (handle_ops[0]))
274 == MONO_W32HANDLE_COUNT);
276 /* This is needed by the code in mono_w32handle_new_internal */
277 mono_w32handle_fd_reserve = (eg_getdtablesize () + (HANDLE_PER_SLOT - 1)) & ~(HANDLE_PER_SLOT - 1);
281 * The entries in private_handles reserved for fds are allocated lazily to
285 private_handles_count += HANDLE_PER_SLOT;
286 private_handles_slots_count ++;
287 } while(mono_w32handle_fd_reserve > private_handles_count);
289 mono_os_mutex_init (&scan_mutex);
291 mono_os_cond_init (&global_signal_cond);
292 mono_os_mutex_init (&global_signal_mutex);
298 mono_w32handle_cleanup (void)
302 g_assert (!shutting_down);
303 shutting_down = TRUE;
305 /* Every shared handle we were using ought really to be closed
306 * by now, but to make sure just blow them all away. The
307 * exiting finalizer thread in particular races us to the
308 * program exit and doesn't always win, so it can be left
309 * cluttering up the shared file. Anything else left over is
312 for(i = SLOT_INDEX (0); private_handles[i] != NULL; i++) {
313 for(j = SLOT_OFFSET (0); j < HANDLE_PER_SLOT; j++) {
314 MonoW32HandleBase *handle_data = &private_handles[i][j];
315 gpointer handle = GINT_TO_POINTER (i*HANDLE_PER_SLOT+j);
317 for(k = handle_data->ref; k > 0; k--) {
318 mono_w32handle_unref (handle);
323 for (i = 0; i < SLOT_MAX; ++i)
324 g_free (private_handles [i]);
328 mono_w32handle_ops_typesize (MonoW32HandleType type);
330 static void mono_w32handle_init_handle (MonoW32HandleBase *handle,
331 MonoW32HandleType type, gpointer handle_specific)
333 g_assert (handle->ref == 0);
336 handle->signalled = FALSE;
339 mono_os_cond_init (&handle->signal_cond);
340 mono_os_mutex_init (&handle->signal_mutex);
343 handle->specific = g_memdup (handle_specific, mono_w32handle_ops_typesize (type));
347 * mono_w32handle_new_internal:
348 * @type: Init handle to this type
350 * Search for a free handle and initialize it. Return the handle on
351 * success and 0 on failure. This is only called from
352 * mono_w32handle_new, and scan_mutex must be held.
354 static guint32 mono_w32handle_new_internal (MonoW32HandleType type,
355 gpointer handle_specific)
358 static guint32 last = 0;
359 gboolean retry = FALSE;
361 /* A linear scan should be fast enough. Start from the last
362 * allocation, assuming that handles are allocated more often
363 * than they're freed. Leave the space reserved for file
367 if (last < mono_w32handle_fd_reserve) {
368 last = mono_w32handle_fd_reserve;
375 for(i = SLOT_INDEX (count); i < private_handles_slots_count; i++) {
376 if (private_handles [i]) {
377 for (k = SLOT_OFFSET (count); k < HANDLE_PER_SLOT; k++) {
378 MonoW32HandleBase *handle = &private_handles [i][k];
380 if(handle->type == MONO_W32HANDLE_UNUSED) {
383 mono_w32handle_init_handle (handle, type, handle_specific);
391 if(retry && last > mono_w32handle_fd_reserve) {
392 /* Try again from the beginning */
393 last = mono_w32handle_fd_reserve;
397 /* Will need to expand the array. The caller will sort it out */
403 mono_w32handle_new (MonoW32HandleType type, gpointer handle_specific)
405 guint32 handle_idx = 0;
408 g_assert (!shutting_down);
410 g_assert(!type_is_fd(type));
412 mono_os_mutex_lock (&scan_mutex);
414 while ((handle_idx = mono_w32handle_new_internal (type, handle_specific)) == 0) {
415 /* Try and expand the array, and have another go */
416 int idx = SLOT_INDEX (private_handles_count);
417 if (idx >= SLOT_MAX) {
421 private_handles [idx] = g_new0 (MonoW32HandleBase, HANDLE_PER_SLOT);
423 private_handles_count += HANDLE_PER_SLOT;
424 private_handles_slots_count ++;
427 mono_os_mutex_unlock (&scan_mutex);
429 if (handle_idx == 0) {
430 /* We ran out of slots */
431 handle = INVALID_HANDLE_VALUE;
432 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: failed to create %s handle", __func__, mono_w32handle_ops_typename (type));
436 /* Make sure we left the space for fd mappings */
437 g_assert (handle_idx >= mono_w32handle_fd_reserve);
439 handle = GUINT_TO_POINTER (handle_idx);
441 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: create %s handle %p", __func__, mono_w32handle_ops_typename (type), handle);
447 gpointer mono_w32handle_new_fd (MonoW32HandleType type, int fd,
448 gpointer handle_specific)
450 MonoW32HandleBase *handle_data;
451 int fd_index, fd_offset;
453 g_assert (!shutting_down);
455 g_assert(type_is_fd(type));
457 if (fd >= mono_w32handle_fd_reserve) {
458 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));
460 return(GUINT_TO_POINTER (INVALID_HANDLE_VALUE));
463 fd_index = SLOT_INDEX (fd);
464 fd_offset = SLOT_OFFSET (fd);
466 /* Initialize the array entries on demand */
467 if (!private_handles [fd_index]) {
468 mono_os_mutex_lock (&scan_mutex);
470 if (!private_handles [fd_index])
471 private_handles [fd_index] = g_new0 (MonoW32HandleBase, HANDLE_PER_SLOT);
473 mono_os_mutex_unlock (&scan_mutex);
476 handle_data = &private_handles [fd_index][fd_offset];
478 if (handle_data->type != MONO_W32HANDLE_UNUSED) {
479 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));
480 /* FIXME: clean up this handle? We can't do anything
481 * with the fd, cos thats the new one
483 return(GUINT_TO_POINTER (INVALID_HANDLE_VALUE));
486 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: create %s handle %p", __func__, mono_w32handle_ops_typename (type), GUINT_TO_POINTER(fd));
488 mono_w32handle_init_handle (handle_data, type, handle_specific);
490 return(GUINT_TO_POINTER(fd));
494 mono_w32handle_close (gpointer handle)
496 if (handle == INVALID_HANDLE_VALUE)
498 if (handle == (gpointer) 0 && mono_w32handle_get_type (handle) != MONO_W32HANDLE_CONSOLE) {
499 /* Problem: because we map file descriptors to the
500 * same-numbered handle we can't tell the difference
501 * between a bogus handle and the handle to stdin.
502 * Assume that it's the console handle if that handle
507 mono_w32handle_unref (handle);
512 mono_w32handle_lookup (gpointer handle, MonoW32HandleType type,
513 gpointer *handle_specific)
515 MonoW32HandleBase *handle_data;
517 g_assert (handle_specific);
519 if (!mono_w32handle_lookup_data (handle, &handle_data)) {
523 if (handle_data->type != type) {
527 *handle_specific = handle_data->specific;
533 mono_w32handle_ref_core (gpointer handle, MonoW32HandleBase *handle_data);
536 mono_w32handle_unref_core (gpointer handle, MonoW32HandleBase *handle_data);
539 w32handle_destroy (gpointer handle);
542 mono_w32handle_foreach (gboolean (*on_each)(gpointer handle, gpointer data, gpointer user_data), gpointer user_data)
544 GPtrArray *handles_to_destroy;
547 handles_to_destroy = NULL;
549 mono_os_mutex_lock (&scan_mutex);
551 for (i = SLOT_INDEX (0); i < private_handles_slots_count; i++) {
552 if (!private_handles [i])
554 for (k = SLOT_OFFSET (0); k < HANDLE_PER_SLOT; k++) {
555 MonoW32HandleBase *handle_data = NULL;
557 gboolean destroy, finished;
559 handle_data = &private_handles [i][k];
560 if (handle_data->type == MONO_W32HANDLE_UNUSED)
563 handle = GUINT_TO_POINTER (i * HANDLE_PER_SLOT + k);
565 if (!mono_w32handle_ref_core (handle, handle_data)) {
566 /* we are racing with mono_w32handle_unref:
567 * the handle ref has been decremented, but it
568 * hasn't yet been destroyed. */
572 finished = on_each (handle, handle_data->specific, user_data);
574 /* we might have to destroy the handle here, as
575 * it could have been unrefed in another thread */
576 destroy = mono_w32handle_unref_core (handle, handle_data);
578 /* we do not destroy it while holding the scan_mutex
579 * lock, because w32handle_destroy also needs to take
580 * the lock, and it calls user code which might lead
582 if (!handles_to_destroy)
583 handles_to_destroy = g_ptr_array_sized_new (4);
584 g_ptr_array_add (handles_to_destroy, handle);
593 mono_os_mutex_unlock (&scan_mutex);
595 if (handles_to_destroy) {
596 for (i = 0; i < handles_to_destroy->len; ++i)
597 w32handle_destroy (handles_to_destroy->pdata [i]);
599 g_ptr_array_free (handles_to_destroy, TRUE);
604 mono_w32handle_ref_core (gpointer handle, MonoW32HandleBase *handle_data)
609 old = handle_data->ref;
614 } while (InterlockedCompareExchange ((gint32*) &handle_data->ref, new, old) != old);
616 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: ref %s handle %p, ref: %d -> %d",
617 __func__, mono_w32handle_ops_typename (handle_data->type), handle, old, new);
623 mono_w32handle_unref_core (gpointer handle, MonoW32HandleBase *handle_data)
625 MonoW32HandleType type;
628 type = handle_data->type;
631 old = handle_data->ref;
633 g_error ("%s: handle %p has ref %d, it should be >= 1", __func__, handle, old);
636 } while (InterlockedCompareExchange ((gint32*) &handle_data->ref, new, old) != old);
638 /* handle_data might contain invalid data from now on, if
639 * another thread is unref'ing this handle at the same time */
641 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: unref %s handle %p, ref: %d -> %d destroy: %s",
642 __func__, mono_w32handle_ops_typename (type), handle, old, new, new == 0 ? "true" : "false");
647 void mono_w32handle_ref (gpointer handle)
649 MonoW32HandleBase *handle_data;
651 if (!mono_w32handle_lookup_data (handle, &handle_data)) {
652 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: failed to ref handle %p, unknown handle", __func__, handle);
656 if (!mono_w32handle_ref_core (handle, handle_data))
657 g_error ("%s: failed to ref handle %p", __func__, handle);
660 static void (*_wapi_handle_ops_get_close_func (MonoW32HandleType type))(gpointer, gpointer);
663 w32handle_destroy (gpointer handle)
665 /* Need to copy the handle info, reset the slot in the
666 * array, and _only then_ call the close function to
667 * avoid race conditions (eg file descriptors being
668 * closed, and another file being opened getting the
669 * same fd racing the memset())
671 MonoW32HandleBase *handle_data;
672 MonoW32HandleType type;
673 gpointer handle_specific;
674 void (*close_func)(gpointer, gpointer);
676 if (!mono_w32handle_lookup_data (handle, &handle_data))
677 g_error ("%s: unknown handle %p", __func__, handle);
679 g_assert (!handle_data->in_use);
681 type = handle_data->type;
682 handle_specific = handle_data->specific;
684 mono_os_mutex_lock (&scan_mutex);
686 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: destroy %s handle %p", __func__, mono_w32handle_ops_typename (type), handle);
688 mono_os_mutex_destroy (&handle_data->signal_mutex);
689 mono_os_cond_destroy (&handle_data->signal_cond);
691 memset (handle_data, 0, sizeof (MonoW32HandleBase));
693 mono_os_mutex_unlock (&scan_mutex);
695 close_func = _wapi_handle_ops_get_close_func (type);
696 if (close_func != NULL) {
697 close_func (handle, handle_specific);
700 memset (handle_specific, 0, mono_w32handle_ops_typesize (type));
702 g_free (handle_specific);
705 /* The handle must not be locked on entry to this function */
707 mono_w32handle_unref (gpointer handle)
709 MonoW32HandleBase *handle_data;
712 if (!mono_w32handle_lookup_data (handle, &handle_data)) {
713 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: failed to unref handle %p, unknown handle",
718 destroy = mono_w32handle_unref_core (handle, handle_data);
720 w32handle_destroy (handle);
724 mono_w32handle_ops_close (gpointer handle, gpointer data);
727 mono_w32handle_force_close (gpointer handle, gpointer data)
729 mono_w32handle_ops_close (handle, data);
733 mono_w32handle_register_ops (MonoW32HandleType type, MonoW32HandleOps *ops)
735 handle_ops [type] = ops;
738 void mono_w32handle_register_capabilities (MonoW32HandleType type,
739 MonoW32HandleCapability caps)
741 handle_caps[type] = caps;
744 gboolean mono_w32handle_test_capabilities (gpointer handle,
745 MonoW32HandleCapability caps)
747 MonoW32HandleBase *handle_data;
748 MonoW32HandleType type;
750 if (!mono_w32handle_lookup_data (handle, &handle_data)) {
754 type = handle_data->type;
756 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: testing 0x%x against 0x%x (%d)", __func__,
757 handle_caps[type], caps, handle_caps[type] & caps);
759 return((handle_caps[type] & caps) != 0);
762 static void (*_wapi_handle_ops_get_close_func (MonoW32HandleType type))(gpointer, gpointer)
764 if (handle_ops[type] != NULL &&
765 handle_ops[type]->close != NULL) {
766 return (handle_ops[type]->close);
773 mono_w32handle_ops_close (gpointer handle, gpointer data)
775 MonoW32HandleBase *handle_data;
776 MonoW32HandleType type;
778 if (!mono_w32handle_lookup_data (handle, &handle_data)) {
782 type = handle_data->type;
784 if (handle_ops[type] != NULL &&
785 handle_ops[type]->close != NULL) {
786 handle_ops[type]->close (handle, data);
791 mono_w32handle_ops_details (MonoW32HandleType type, gpointer data)
793 if (handle_ops[type] != NULL &&
794 handle_ops[type]->details != NULL) {
795 handle_ops[type]->details (data);
800 mono_w32handle_ops_typename (MonoW32HandleType type)
802 g_assert (handle_ops [type]);
803 g_assert (handle_ops [type]->typename);
804 return handle_ops [type]->typename ();
808 mono_w32handle_ops_typesize (MonoW32HandleType type)
810 g_assert (handle_ops [type]);
811 g_assert (handle_ops [type]->typesize);
812 return handle_ops [type]->typesize ();
816 mono_w32handle_ops_signal (gpointer handle)
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]->signal != NULL) {
828 handle_ops[type]->signal (handle, handle_data->specific);
833 mono_w32handle_ops_own (gpointer handle, gboolean *abandoned)
835 MonoW32HandleBase *handle_data;
836 MonoW32HandleType type;
838 if (!mono_w32handle_lookup_data (handle, &handle_data)) {
842 type = handle_data->type;
844 if (handle_ops[type] != NULL && handle_ops[type]->own_handle != NULL) {
845 return(handle_ops[type]->own_handle (handle, abandoned));
852 mono_w32handle_ops_isowned (gpointer handle)
854 MonoW32HandleBase *handle_data;
855 MonoW32HandleType type;
857 if (!mono_w32handle_lookup_data (handle, &handle_data)) {
861 type = handle_data->type;
863 if (handle_ops[type] != NULL && handle_ops[type]->is_owned != NULL) {
864 return(handle_ops[type]->is_owned (handle));
870 static MonoW32HandleWaitRet
871 mono_w32handle_ops_specialwait (gpointer handle, guint32 timeout, gboolean *alerted)
873 MonoW32HandleBase *handle_data;
874 MonoW32HandleType type;
876 if (!mono_w32handle_lookup_data (handle, &handle_data)) {
877 return MONO_W32HANDLE_WAIT_RET_FAILED;
880 type = handle_data->type;
882 if (handle_ops[type] != NULL &&
883 handle_ops[type]->special_wait != NULL) {
884 return(handle_ops[type]->special_wait (handle, timeout, alerted));
886 return MONO_W32HANDLE_WAIT_RET_FAILED;
891 mono_w32handle_ops_prewait (gpointer handle)
893 MonoW32HandleBase *handle_data;
894 MonoW32HandleType type;
896 if (!mono_w32handle_lookup_data (handle, &handle_data)) {
900 type = handle_data->type;
902 if (handle_ops[type] != NULL &&
903 handle_ops[type]->prewait != NULL) {
904 handle_ops[type]->prewait (handle);
914 struct timespec sleepytime;
916 g_assert (ms < 1000);
918 sleepytime.tv_sec = 0;
919 sleepytime.tv_nsec = ms * 1000000;
920 nanosleep (&sleepytime, NULL);
921 #endif /* HOST_WIN32 */
925 mono_w32handle_lock_handles (gpointer *handles, gsize numhandles)
929 /* Lock all the handles, with backoff */
931 for(i=0; i<numhandles; i++) {
932 gpointer handle = handles[i];
934 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: attempting to lock %p", __func__, handle);
936 if (!mono_w32handle_trylock_handle (handle)) {
939 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: attempt failed for %p.", __func__,
945 mono_w32handle_unlock_handle (handle);
948 /* If iter ever reaches 100 the nanosleep will
949 * return EINVAL immediately, but we have a
950 * design flaw if that happens.
954 g_warning ("%s: iteration overflow!",
959 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: Backing off for %d ms", __func__,
967 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: Locked all handles", __func__);
971 mono_w32handle_unlock_handles (gpointer *handles, gsize numhandles)
975 for(i=0; i<numhandles; i++) {
976 gpointer handle = handles[i];
978 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: unlocking handle %p", __func__, handle);
980 mono_w32handle_unlock_handle (handle);
985 mono_w32handle_timedwait_signal_naked (mono_cond_t *cond, mono_mutex_t *mutex, guint32 timeout, gboolean poll, gboolean *alerted)
990 res = mono_os_cond_timedwait (cond, mutex, timeout);
992 /* This is needed when waiting for process handles */
995 * pthread_cond_(timed)wait() can return 0 even if the condition was not
996 * signalled. This happens at least on Darwin. We surface this, i.e., we
997 * get spurious wake-ups.
999 * http://pubs.opengroup.org/onlinepubs/007908775/xsh/pthread_cond_wait.html
1001 res = mono_os_cond_timedwait (cond, mutex, timeout);
1003 if (timeout < 100) {
1004 /* Real timeout is less than 100ms time */
1005 res = mono_os_cond_timedwait (cond, mutex, timeout);
1007 res = mono_os_cond_timedwait (cond, mutex, 100);
1009 /* Mask the fake timeout, this will cause
1010 * another poll if the cond was not really signaled
1022 signal_global (gpointer unused)
1024 /* If we reach here, then interrupt token is set to the flag value, which
1025 * means that the target thread is either
1026 * - before the first CAS in timedwait, which means it won't enter the wait.
1027 * - it is after the first CAS, so it is already waiting, or it will enter
1028 * the wait, and it will be interrupted by the broadcast. */
1029 mono_os_mutex_lock (&global_signal_mutex);
1030 mono_os_cond_broadcast (&global_signal_cond);
1031 mono_os_mutex_unlock (&global_signal_mutex);
1035 mono_w32handle_timedwait_signal (guint32 timeout, gboolean poll, gboolean *alerted)
1039 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: waiting for global", __func__);
1045 mono_thread_info_install_interrupt (signal_global, NULL, alerted);
1050 res = mono_w32handle_timedwait_signal_naked (&global_signal_cond, &global_signal_mutex, timeout, poll, alerted);
1053 mono_thread_info_uninstall_interrupt (alerted);
1059 signal_handle_and_unref (gpointer handle)
1061 MonoW32HandleBase *handle_data;
1063 mono_mutex_t *mutex;
1065 if (!mono_w32handle_lookup_data (handle, &handle_data))
1066 g_error ("cannot signal unknown handle %p", handle);
1068 /* If we reach here, then interrupt token is set to the flag value, which
1069 * means that the target thread is either
1070 * - before the first CAS in timedwait, which means it won't enter the wait.
1071 * - it is after the first CAS, so it is already waiting, or it will enter
1072 * the wait, and it will be interrupted by the broadcast. */
1073 cond = &handle_data->signal_cond;
1074 mutex = &handle_data->signal_mutex;
1076 mono_os_mutex_lock (mutex);
1077 mono_os_cond_broadcast (cond);
1078 mono_os_mutex_unlock (mutex);
1080 mono_w32handle_unref (handle);
1084 mono_w32handle_timedwait_signal_handle (gpointer handle, guint32 timeout, gboolean poll, gboolean *alerted)
1086 MonoW32HandleBase *handle_data;
1089 if (!mono_w32handle_lookup_data (handle, &handle_data))
1090 g_error ("cannot wait on unknown handle %p", handle);
1092 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: waiting for %p (type %s)", __func__, handle,
1093 mono_w32handle_ops_typename (mono_w32handle_get_type (handle)));
1099 mono_thread_info_install_interrupt (signal_handle_and_unref, handle, alerted);
1102 mono_w32handle_ref (handle);
1105 res = mono_w32handle_timedwait_signal_naked (&handle_data->signal_cond, &handle_data->signal_mutex, timeout, poll, alerted);
1108 mono_thread_info_uninstall_interrupt (alerted);
1110 /* if it is alerted, then the handle is unref in the interrupt callback */
1111 mono_w32handle_unref (handle);
1119 dump_callback (gpointer handle, gpointer handle_specific, gpointer user_data)
1121 MonoW32HandleBase *handle_data;
1123 if (!mono_w32handle_lookup_data (handle, &handle_data))
1124 g_error ("cannot dump unknown handle %p", handle);
1126 g_print ("%p [%7s] signalled: %5s ref: %3d ",
1127 handle, mono_w32handle_ops_typename (handle_data->type), handle_data->signalled ? "true" : "false", handle_data->ref);
1128 mono_w32handle_ops_details (handle_data->type, handle_data->specific);
1134 void mono_w32handle_dump (void)
1136 mono_w32handle_foreach (dump_callback, NULL);
1140 own_if_signalled (gpointer handle, gboolean *abandoned)
1142 if (!mono_w32handle_issignalled (handle))
1146 mono_w32handle_ops_own (handle, abandoned);
1151 own_if_owned( gpointer handle, gboolean *abandoned)
1153 if (!mono_w32handle_ops_isowned (handle))
1157 mono_w32handle_ops_own (handle, abandoned);
1161 MonoW32HandleWaitRet
1162 mono_w32handle_wait_one (gpointer handle, guint32 timeout, gboolean alertable)
1164 MonoW32HandleWaitRet ret;
1167 gboolean abandoned = FALSE;
1171 if (mono_w32handle_test_capabilities (handle, MONO_W32HANDLE_CAP_SPECIAL_WAIT)) {
1172 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p has special wait",
1175 return mono_w32handle_ops_specialwait (handle, timeout, alertable ? &alerted : NULL);
1178 if (!mono_w32handle_test_capabilities (handle, MONO_W32HANDLE_CAP_WAIT)) {
1179 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p can't be waited for",
1182 return MONO_W32HANDLE_WAIT_RET_FAILED;
1185 mono_w32handle_lock_handle (handle);
1187 if (mono_w32handle_test_capabilities (handle, MONO_W32HANDLE_CAP_OWN)) {
1188 if (own_if_owned (handle, &abandoned)) {
1189 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p already owned",
1192 ret = abandoned ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0;
1197 if (timeout != MONO_INFINITE_WAIT)
1198 start = mono_msec_ticks ();
1200 mono_w32handle_set_in_use (handle, TRUE);
1205 if (own_if_signalled (handle, &abandoned)) {
1206 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p signalled",
1209 ret = abandoned ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0;
1213 mono_w32handle_ops_prewait (handle);
1215 if (timeout == MONO_INFINITE_WAIT) {
1216 waited = mono_w32handle_timedwait_signal_handle (handle, MONO_INFINITE_WAIT, FALSE, alertable ? &alerted : NULL);
1220 elapsed = mono_msec_ticks () - start;
1221 if (elapsed > timeout) {
1222 ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT;
1226 waited = mono_w32handle_timedwait_signal_handle (handle, timeout - elapsed, FALSE, alertable ? &alerted : NULL);
1230 ret = MONO_W32HANDLE_WAIT_RET_ALERTED;
1235 ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT;
1241 mono_w32handle_set_in_use (handle, FALSE);
1243 mono_w32handle_unlock_handle (handle);
1248 MonoW32HandleWaitRet
1249 mono_w32handle_wait_multiple (gpointer *handles, gsize nhandles, gboolean waitall, guint32 timeout, gboolean alertable)
1251 MonoW32HandleWaitRet ret;
1252 gboolean alerted, poll;
1255 gpointer handles_sorted [MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
1256 gboolean abandoned [MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS] = {0};
1259 return MONO_W32HANDLE_WAIT_RET_FAILED;
1262 return mono_w32handle_wait_one (handles [0], timeout, alertable);
1266 if (nhandles > MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
1267 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: too many handles: %zd",
1268 __func__, nhandles);
1270 return MONO_W32HANDLE_WAIT_RET_FAILED;
1273 for (i = 0; i < nhandles; ++i) {
1274 if (!mono_w32handle_test_capabilities (handles[i], MONO_W32HANDLE_CAP_WAIT)
1275 && !mono_w32handle_test_capabilities (handles[i], MONO_W32HANDLE_CAP_SPECIAL_WAIT))
1277 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p can't be waited for",
1278 __func__, handles [i]);
1280 return MONO_W32HANDLE_WAIT_RET_FAILED;
1283 handles_sorted [i] = handles [i];
1286 qsort (handles_sorted, nhandles, sizeof (gpointer), g_direct_equal);
1287 for (i = 1; i < nhandles; ++i) {
1288 if (handles_sorted [i - 1] == handles_sorted [i]) {
1289 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p is duplicated",
1290 __func__, handles_sorted [i]);
1292 return MONO_W32HANDLE_WAIT_RET_FAILED;
1297 for (i = 0; i < nhandles; ++i) {
1298 if (mono_w32handle_get_type (handles [i]) == MONO_W32HANDLE_PROCESS) {
1299 /* Can't wait for a process handle + another handle without polling */
1304 if (timeout != MONO_INFINITE_WAIT)
1305 start = mono_msec_ticks ();
1307 for (i = 0; i < nhandles; ++i) {
1308 /* Add a reference, as we need to ensure the handle wont
1309 * disappear from under us while we're waiting in the loop
1310 * (not lock, as we don't want exclusive access here) */
1311 mono_w32handle_ref (handles [i]);
1315 gsize count, lowest;
1322 mono_w32handle_lock_handles (handles, nhandles);
1324 for (i = 0; i < nhandles; i++) {
1325 if ((mono_w32handle_test_capabilities (handles [i], MONO_W32HANDLE_CAP_OWN) && mono_w32handle_ops_isowned (handles [i]))
1326 || mono_w32handle_issignalled (handles [i]))
1335 signalled = (waitall && count == nhandles) || (!waitall && count > 0);
1338 for (i = 0; i < nhandles; i++)
1339 own_if_signalled (handles [i], &abandoned [i]);
1342 mono_w32handle_unlock_handles (handles, nhandles);
1345 ret = MONO_W32HANDLE_WAIT_RET_SUCCESS_0 + lowest;
1346 for (i = lowest; i < nhandles; i++) {
1347 if (abandoned [i]) {
1348 ret = MONO_W32HANDLE_WAIT_RET_ABANDONED_0 + lowest;
1355 for (i = 0; i < nhandles; i++) {
1356 mono_w32handle_ops_prewait (handles[i]);
1358 if (mono_w32handle_test_capabilities (handles [i], MONO_W32HANDLE_CAP_SPECIAL_WAIT)
1359 && !mono_w32handle_issignalled (handles [i]))
1361 mono_w32handle_ops_specialwait (handles [i], 0, alertable ? &alerted : NULL);
1365 mono_w32handle_lock_signal_mutex ();
1369 for (i = 0; i < nhandles; ++i) {
1370 if (!mono_w32handle_issignalled (handles [i])) {
1377 for (i = 0; i < nhandles; ++i) {
1378 if (mono_w32handle_issignalled (handles [i])) {
1388 if (timeout == MONO_INFINITE_WAIT) {
1389 waited = mono_w32handle_timedwait_signal (MONO_INFINITE_WAIT, poll, alertable ? &alerted : NULL);
1393 elapsed = mono_msec_ticks () - start;
1394 if (elapsed > timeout) {
1395 ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT;
1397 mono_w32handle_unlock_signal_mutex ();
1402 waited = mono_w32handle_timedwait_signal (timeout - elapsed, poll, alertable ? &alerted : NULL);
1406 mono_w32handle_unlock_signal_mutex ();
1409 ret = MONO_W32HANDLE_WAIT_RET_ALERTED;
1414 ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT;
1420 for (i = 0; i < nhandles; i++) {
1421 /* Unref everything we reffed above */
1422 mono_w32handle_unref (handles [i]);
1428 MonoW32HandleWaitRet
1429 mono_w32handle_signal_and_wait (gpointer signal_handle, gpointer wait_handle, guint32 timeout, gboolean alertable)
1431 MonoW32HandleWaitRet ret;
1434 gboolean abandoned = FALSE;
1435 gpointer handles [2];
1439 if (!mono_w32handle_test_capabilities (signal_handle, MONO_W32HANDLE_CAP_SIGNAL))
1440 return MONO_W32HANDLE_WAIT_RET_FAILED;
1441 if (!mono_w32handle_test_capabilities (wait_handle, MONO_W32HANDLE_CAP_WAIT))
1442 return MONO_W32HANDLE_WAIT_RET_FAILED;
1444 if (mono_w32handle_test_capabilities (wait_handle, MONO_W32HANDLE_CAP_SPECIAL_WAIT)) {
1445 g_warning ("%s: handle %p has special wait, implement me!!", __func__, wait_handle);
1446 return MONO_W32HANDLE_WAIT_RET_FAILED;
1449 handles [0] = wait_handle;
1450 handles [1] = signal_handle;
1452 mono_w32handle_lock_handles (handles, 2);
1454 mono_w32handle_ops_signal (signal_handle);
1456 mono_w32handle_unlock_handle (signal_handle);
1458 if (mono_w32handle_test_capabilities (wait_handle, MONO_W32HANDLE_CAP_OWN)) {
1459 if (own_if_owned (wait_handle, &abandoned)) {
1460 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p already owned",
1461 __func__, wait_handle);
1463 ret = abandoned ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0;
1468 if (timeout != MONO_INFINITE_WAIT)
1469 start = mono_msec_ticks ();
1474 if (own_if_signalled (wait_handle, &abandoned)) {
1475 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p signalled",
1476 __func__, wait_handle);
1478 ret = abandoned ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0;
1482 mono_w32handle_ops_prewait (wait_handle);
1484 if (timeout == MONO_INFINITE_WAIT) {
1485 waited = mono_w32handle_timedwait_signal_handle (wait_handle, MONO_INFINITE_WAIT, FALSE, alertable ? &alerted : NULL);
1489 elapsed = mono_msec_ticks () - start;
1490 if (elapsed > timeout) {
1491 ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT;
1495 waited = mono_w32handle_timedwait_signal_handle (wait_handle, timeout - elapsed, FALSE, alertable ? &alerted : NULL);
1499 ret = MONO_W32HANDLE_WAIT_RET_ALERTED;
1504 ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT;
1510 mono_w32handle_unlock_handle (wait_handle);