X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fw32handle.c;h=654b215538d800de195db57afeca5ccaaa9176e9;hb=HEAD;hp=ef3b24838e1729459f9da4c99ddc7a834ce51aa7;hpb=9d5ff689fcb4f4b3a99328c1cb345ef5955a1d46;p=mono.git diff --git a/mono/metadata/w32handle.c b/mono/metadata/w32handle.c index ef3b24838e1..654b215538d 100644 --- a/mono/metadata/w32handle.c +++ b/mono/metadata/w32handle.c @@ -1,5 +1,6 @@ -/* - * w32handle.c: Generic and internal operations on handles +/** + * \file + * Generic and internal operations on handles * * Author: * Dick Porter (dick@ximian.com) @@ -24,17 +25,16 @@ #undef DEBUG_REFS -#define SLOT_MAX (1024 * 16) +#define SLOT_MAX (1024 * 32) /* must be a power of 2 */ #define HANDLE_PER_SLOT (256) -#define INFINITE 0xFFFFFFFF - typedef struct { MonoW32HandleType type; guint ref; gboolean signalled; + gboolean in_use; mono_mutex_t signal_mutex; mono_cond_t signal_cond; gpointer specific; @@ -51,10 +51,7 @@ static MonoW32HandleOps *handle_ops [MONO_W32HANDLE_COUNT]; #define SLOT_OFFSET(x) (x % HANDLE_PER_SLOT) static MonoW32HandleBase *private_handles [SLOT_MAX]; -static guint32 private_handles_count = 0; -static guint32 private_handles_slots_count = 0; - -guint32 mono_w32handle_fd_reserve; +static guint32 private_handles_size = 0; /* * This is an internal handle which is used for handling waiting for multiple handles. @@ -68,20 +65,6 @@ static mono_mutex_t scan_mutex; static gboolean shutting_down = FALSE; -static gboolean -type_is_fd (MonoW32HandleType type) -{ - switch (type) { - case MONO_W32HANDLE_FILE: - case MONO_W32HANDLE_CONSOLE: - case MONO_W32HANDLE_SOCKET: - case MONO_W32HANDLE_PIPE: - return TRUE; - default: - return FALSE; - } -} - static gboolean mono_w32handle_lookup_data (gpointer handle, MonoW32HandleBase **handle_data) { @@ -179,6 +162,17 @@ mono_w32handle_issignalled (gpointer handle) return handle_data->signalled; } +static void +mono_w32handle_set_in_use (gpointer handle, gboolean in_use) +{ + MonoW32HandleBase *handle_data; + + if (!mono_w32handle_lookup_data (handle, &handle_data)) + g_assert_not_reached (); + + handle_data->in_use = in_use; +} + static void mono_w32handle_lock_signal_mutex (void) { @@ -199,6 +193,12 @@ mono_w32handle_unlock_signal_mutex (void) mono_os_mutex_unlock (&global_signal_mutex); } +static void +mono_w32handle_ref (gpointer handle); + +static void +mono_w32handle_unref (gpointer handle); + void mono_w32handle_lock_handle (gpointer handle) { @@ -251,11 +251,6 @@ mono_w32handle_unlock_handle (gpointer handle) mono_w32handle_unref (handle); } -/* - * wapi_init: - * - * Initialize the io-layer. - */ void mono_w32handle_init (void) { @@ -267,19 +262,6 @@ mono_w32handle_init (void) g_assert ((sizeof (handle_ops) / sizeof (handle_ops[0])) == MONO_W32HANDLE_COUNT); - /* This is needed by the code in mono_w32handle_new_internal */ - mono_w32handle_fd_reserve = (eg_getdtablesize () + (HANDLE_PER_SLOT - 1)) & ~(HANDLE_PER_SLOT - 1); - - do { - /* - * The entries in private_handles reserved for fds are allocated lazily to - * save memory. - */ - - private_handles_count += HANDLE_PER_SLOT; - private_handles_slots_count ++; - } while(mono_w32handle_fd_reserve > private_handles_count); - mono_os_mutex_init (&scan_mutex); mono_os_cond_init (&global_signal_cond); @@ -291,29 +273,11 @@ mono_w32handle_init (void) void mono_w32handle_cleanup (void) { - int i, j, k; + int i; g_assert (!shutting_down); shutting_down = TRUE; - /* Every shared handle we were using ought really to be closed - * by now, but to make sure just blow them all away. The - * exiting finalizer thread in particular races us to the - * program exit and doesn't always win, so it can be left - * cluttering up the shared file. Anything else left over is - * really a bug. - */ - for(i = SLOT_INDEX (0); private_handles[i] != NULL; i++) { - for(j = SLOT_OFFSET (0); j < HANDLE_PER_SLOT; j++) { - MonoW32HandleBase *handle_data = &private_handles[i][j]; - gpointer handle = GINT_TO_POINTER (i*HANDLE_PER_SLOT+j); - - for(k = handle_data->ref; k > 0; k--) { - mono_w32handle_unref (handle); - } - } - } - for (i = 0; i < SLOT_MAX; ++i) g_free (private_handles [i]); } @@ -321,22 +285,6 @@ mono_w32handle_cleanup (void) static gsize mono_w32handle_ops_typesize (MonoW32HandleType type); -static void mono_w32handle_init_handle (MonoW32HandleBase *handle, - MonoW32HandleType type, gpointer handle_specific) -{ - g_assert (handle->ref == 0); - - handle->type = type; - handle->signalled = FALSE; - handle->ref = 1; - - mono_os_cond_init (&handle->signal_cond); - mono_os_mutex_init (&handle->signal_mutex); - - if (handle_specific) - handle->specific = g_memdup (handle_specific, mono_w32handle_ops_typesize (type)); -} - /* * mono_w32handle_new_internal: * @type: Init handle to this type @@ -358,15 +306,16 @@ static guint32 mono_w32handle_new_internal (MonoW32HandleType type, * descriptors */ - if (last < mono_w32handle_fd_reserve) { - last = mono_w32handle_fd_reserve; + if (last == 0) { + /* We need to go from 1 since a handle of value 0 can be considered invalid in managed code */ + last = 1; } else { retry = TRUE; } again: count = last; - for(i = SLOT_INDEX (count); i < private_handles_slots_count; i++) { + for(i = SLOT_INDEX (count); i < private_handles_size; i++) { if (private_handles [i]) { for (k = SLOT_OFFSET (count); k < HANDLE_PER_SLOT; k++) { MonoW32HandleBase *handle = &private_handles [i][k]; @@ -374,7 +323,18 @@ again: if(handle->type == MONO_W32HANDLE_UNUSED) { last = count + 1; - mono_w32handle_init_handle (handle, type, handle_specific); + g_assert (handle->ref == 0); + + handle->type = type; + handle->signalled = FALSE; + handle->ref = 1; + + mono_os_cond_init (&handle->signal_cond); + mono_os_mutex_init (&handle->signal_mutex); + + if (handle_specific) + handle->specific = g_memdup (handle_specific, mono_w32handle_ops_typesize (type)); + return (count); } count++; @@ -382,106 +342,91 @@ again: } } - if(retry && last > mono_w32handle_fd_reserve) { + if (retry) { /* Try again from the beginning */ - last = mono_w32handle_fd_reserve; + last = 1; + retry = FALSE; goto again; } /* Will need to expand the array. The caller will sort it out */ - return(0); + return G_MAXUINT32; } gpointer mono_w32handle_new (MonoW32HandleType type, gpointer handle_specific) { - guint32 handle_idx = 0; + guint32 handle_idx; gpointer handle; g_assert (!shutting_down); - g_assert(!type_is_fd(type)); - mono_os_mutex_lock (&scan_mutex); - while ((handle_idx = mono_w32handle_new_internal (type, handle_specific)) == 0) { + while ((handle_idx = mono_w32handle_new_internal (type, handle_specific)) == G_MAXUINT32) { /* Try and expand the array, and have another go */ - int idx = SLOT_INDEX (private_handles_count); - if (idx >= SLOT_MAX) { - break; - } + if (private_handles_size >= SLOT_MAX) { + mono_os_mutex_unlock (&scan_mutex); - private_handles [idx] = g_new0 (MonoW32HandleBase, HANDLE_PER_SLOT); + /* We ran out of slots */ + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: failed to create %s handle", __func__, mono_w32handle_ops_typename (type)); + return INVALID_HANDLE_VALUE; + } - private_handles_count += HANDLE_PER_SLOT; - private_handles_slots_count ++; + private_handles [private_handles_size ++] = g_new0 (MonoW32HandleBase, HANDLE_PER_SLOT); } mono_os_mutex_unlock (&scan_mutex); - if (handle_idx == 0) { - /* We ran out of slots */ - handle = INVALID_HANDLE_VALUE; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: failed to create %s handle", __func__, mono_w32handle_ops_typename (type)); - goto done; - } - - /* Make sure we left the space for fd mappings */ - g_assert (handle_idx >= mono_w32handle_fd_reserve); - handle = GUINT_TO_POINTER (handle_idx); mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: create %s handle %p", __func__, mono_w32handle_ops_typename (type), handle); -done: return(handle); } -gpointer mono_w32handle_new_fd (MonoW32HandleType type, int fd, - gpointer handle_specific) -{ - MonoW32HandleBase *handle_data; - int fd_index, fd_offset; - - g_assert (!shutting_down); - - g_assert(type_is_fd(type)); - - if (fd >= mono_w32handle_fd_reserve) { - 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)); +static gboolean +mono_w32handle_ref_core (gpointer handle, MonoW32HandleBase *handle_data); - return(GUINT_TO_POINTER (INVALID_HANDLE_VALUE)); - } +static gboolean +mono_w32handle_unref_core (gpointer handle, MonoW32HandleBase *handle_data); - fd_index = SLOT_INDEX (fd); - fd_offset = SLOT_OFFSET (fd); +static void +w32handle_destroy (gpointer handle); - /* Initialize the array entries on demand */ - if (!private_handles [fd_index]) { - mono_os_mutex_lock (&scan_mutex); +gpointer +mono_w32handle_duplicate (gpointer handle) +{ + MonoW32HandleBase *handle_data; - if (!private_handles [fd_index]) - private_handles [fd_index] = g_new0 (MonoW32HandleBase, HANDLE_PER_SLOT); + if (handle == INVALID_HANDLE_VALUE) + return handle; + if (!mono_w32handle_lookup_data (handle, &handle_data)) + return INVALID_HANDLE_VALUE; - mono_os_mutex_unlock (&scan_mutex); - } + if (!mono_w32handle_ref_core (handle, handle_data)) + g_error ("%s: failed to ref handle %p", __func__, handle); - handle_data = &private_handles [fd_index][fd_offset]; + return handle; +} - if (handle_data->type != MONO_W32HANDLE_UNUSED) { - 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)); - /* FIXME: clean up this handle? We can't do anything - * with the fd, cos thats the new one - */ - return(GUINT_TO_POINTER (INVALID_HANDLE_VALUE)); - } +gboolean +mono_w32handle_close (gpointer handle) +{ + MonoW32HandleBase *handle_data; + gboolean destroy; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: create %s handle %p", __func__, mono_w32handle_ops_typename (type), GUINT_TO_POINTER(fd)); + if (handle == INVALID_HANDLE_VALUE) + return FALSE; + if (!mono_w32handle_lookup_data (handle, &handle_data)) + return FALSE; - mono_w32handle_init_handle (handle_data, type, handle_specific); + destroy = mono_w32handle_unref_core (handle, handle_data); + if (destroy) + w32handle_destroy (handle); - return(GUINT_TO_POINTER(fd)); + return TRUE; } gboolean @@ -505,20 +450,17 @@ mono_w32handle_lookup (gpointer handle, MonoW32HandleType type, return(TRUE); } -static gboolean -mono_w32handle_ref_core (gpointer handle, MonoW32HandleBase *handle_data); - -static gboolean -mono_w32handle_unref_core (gpointer handle, MonoW32HandleBase *handle_data, guint minimum); - void mono_w32handle_foreach (gboolean (*on_each)(gpointer handle, gpointer data, gpointer user_data), gpointer user_data) { + GPtrArray *handles_to_destroy; guint32 i, k; + handles_to_destroy = NULL; + mono_os_mutex_lock (&scan_mutex); - for (i = SLOT_INDEX (0); i < private_handles_slots_count; i++) { + for (i = SLOT_INDEX (0); i < private_handles_size; i++) { if (!private_handles [i]) continue; for (k = SLOT_OFFSET (0); k < HANDLE_PER_SLOT; k++) { @@ -541,10 +483,18 @@ mono_w32handle_foreach (gboolean (*on_each)(gpointer handle, gpointer data, gpoi finished = on_each (handle, handle_data->specific, user_data); - /* we do not want to have to destroy the handle here, - * as it would means the ref/unref are unbalanced */ - destroy = mono_w32handle_unref_core (handle, handle_data, 2); - g_assert (!destroy); + /* we might have to destroy the handle here, as + * it could have been unrefed in another thread */ + destroy = mono_w32handle_unref_core (handle, handle_data); + if (destroy) { + /* we do not destroy it while holding the scan_mutex + * lock, because w32handle_destroy also needs to take + * the lock, and it calls user code which might lead + * to a deadlock */ + if (!handles_to_destroy) + handles_to_destroy = g_ptr_array_sized_new (4); + g_ptr_array_add (handles_to_destroy, handle); + } if (finished) goto done; @@ -553,6 +503,13 @@ mono_w32handle_foreach (gboolean (*on_each)(gpointer handle, gpointer data, gpoi done: mono_os_mutex_unlock (&scan_mutex); + + if (handles_to_destroy) { + for (i = 0; i < handles_to_destroy->len; ++i) + w32handle_destroy (handles_to_destroy->pdata [i]); + + g_ptr_array_free (handles_to_destroy, TRUE); + } } static gboolean @@ -575,7 +532,7 @@ mono_w32handle_ref_core (gpointer handle, MonoW32HandleBase *handle_data) } static gboolean -mono_w32handle_unref_core (gpointer handle, MonoW32HandleBase *handle_data, guint minimum) +mono_w32handle_unref_core (gpointer handle, MonoW32HandleBase *handle_data) { MonoW32HandleType type; guint old, new; @@ -584,8 +541,8 @@ mono_w32handle_unref_core (gpointer handle, MonoW32HandleBase *handle_data, guin do { old = handle_data->ref; - if (!(old >= minimum)) - g_error ("%s: handle %p has ref %d, it should be >= %d", __func__, handle, old, minimum); + if (!(old >= 1)) + g_error ("%s: handle %p has ref %d, it should be >= 1", __func__, handle, old); new = old - 1; } while (InterlockedCompareExchange ((gint32*) &handle_data->ref, new, old) != old); @@ -599,14 +556,13 @@ mono_w32handle_unref_core (gpointer handle, MonoW32HandleBase *handle_data, guin return new == 0; } -void mono_w32handle_ref (gpointer handle) +static void +mono_w32handle_ref (gpointer handle) { MonoW32HandleBase *handle_data; - if (!mono_w32handle_lookup_data (handle, &handle_data)) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: failed to ref handle %p, unknown handle", __func__, handle); - return; - } + if (!mono_w32handle_lookup_data (handle, &handle_data)) + g_error ("%s: failed to ref handle %p, unknown handle", __func__, handle); if (!mono_w32handle_ref_core (handle, handle_data)) g_error ("%s: failed to ref handle %p", __func__, handle); @@ -614,62 +570,62 @@ void mono_w32handle_ref (gpointer handle) static void (*_wapi_handle_ops_get_close_func (MonoW32HandleType type))(gpointer, gpointer); -/* The handle must not be locked on entry to this function */ -void -mono_w32handle_unref (gpointer handle) +static void +w32handle_destroy (gpointer handle) { + /* Need to copy the handle info, reset the slot in the + * array, and _only then_ call the close function to + * avoid race conditions (eg file descriptors being + * closed, and another file being opened getting the + * same fd racing the memset()) + */ MonoW32HandleBase *handle_data; - gboolean destroy; + MonoW32HandleType type; + gpointer handle_specific; + void (*close_func)(gpointer, gpointer); - if (!mono_w32handle_lookup_data (handle, &handle_data)) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: failed to unref handle %p, unknown handle", - __func__, handle); - return; - } + if (!mono_w32handle_lookup_data (handle, &handle_data)) + g_error ("%s: unknown handle %p", __func__, handle); - destroy = mono_w32handle_unref_core (handle, handle_data, 1); + g_assert (!handle_data->in_use); - if (destroy) { - /* Need to copy the handle info, reset the slot in the - * array, and _only then_ call the close function to - * avoid race conditions (eg file descriptors being - * closed, and another file being opened getting the - * same fd racing the memset()) - */ - MonoW32HandleType type; - gpointer handle_specific; - void (*close_func)(gpointer, gpointer); + type = handle_data->type; + handle_specific = handle_data->specific; - type = handle_data->type; - handle_specific = handle_data->specific; + mono_os_mutex_lock (&scan_mutex); - mono_os_mutex_lock (&scan_mutex); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: destroy %s handle %p", __func__, mono_w32handle_ops_typename (type), handle); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: destroy %s handle %p", __func__, mono_w32handle_ops_typename (type), handle); + mono_os_mutex_destroy (&handle_data->signal_mutex); + mono_os_cond_destroy (&handle_data->signal_cond); - mono_os_mutex_destroy (&handle_data->signal_mutex); - mono_os_cond_destroy (&handle_data->signal_cond); + memset (handle_data, 0, sizeof (MonoW32HandleBase)); - memset (handle_data, 0, sizeof (MonoW32HandleBase)); + mono_os_mutex_unlock (&scan_mutex); - mono_os_mutex_unlock (&scan_mutex); + close_func = _wapi_handle_ops_get_close_func (type); + if (close_func != NULL) { + close_func (handle, handle_specific); + } - close_func = _wapi_handle_ops_get_close_func (type); - if (close_func != NULL) { - close_func (handle, handle_specific); - } + memset (handle_specific, 0, mono_w32handle_ops_typesize (type)); - g_free (handle_specific); - } + g_free (handle_specific); } +/* The handle must not be locked on entry to this function */ static void -mono_w32handle_ops_close (gpointer handle, gpointer data); - -void -mono_w32handle_force_close (gpointer handle, gpointer data) +mono_w32handle_unref (gpointer handle) { - mono_w32handle_ops_close (handle, data); + MonoW32HandleBase *handle_data; + gboolean destroy; + + if (!mono_w32handle_lookup_data (handle, &handle_data)) + g_error ("%s: failed to unref handle %p, unknown handle", __func__, handle); + + destroy = mono_w32handle_unref_core (handle, handle_data); + if (destroy) + w32handle_destroy (handle); } void @@ -712,24 +668,6 @@ static void (*_wapi_handle_ops_get_close_func (MonoW32HandleType type))(gpointer return (NULL); } -static void -mono_w32handle_ops_close (gpointer handle, gpointer data) -{ - MonoW32HandleBase *handle_data; - MonoW32HandleType type; - - if (!mono_w32handle_lookup_data (handle, &handle_data)) { - return; - } - - type = handle_data->type; - - if (handle_ops[type] != NULL && - handle_ops[type]->close != NULL) { - handle_ops[type]->close (handle, data); - } -} - static void mono_w32handle_ops_details (MonoW32HandleType type, gpointer data) { @@ -768,12 +706,12 @@ mono_w32handle_ops_signal (gpointer handle) type = handle_data->type; if (handle_ops[type] != NULL && handle_ops[type]->signal != NULL) { - handle_ops[type]->signal (handle); + handle_ops[type]->signal (handle, handle_data->specific); } } static gboolean -mono_w32handle_ops_own (gpointer handle, guint32 *statuscode) +mono_w32handle_ops_own (gpointer handle, gboolean *abandoned) { MonoW32HandleBase *handle_data; MonoW32HandleType type; @@ -785,7 +723,7 @@ mono_w32handle_ops_own (gpointer handle, guint32 *statuscode) type = handle_data->type; if (handle_ops[type] != NULL && handle_ops[type]->own_handle != NULL) { - return(handle_ops[type]->own_handle (handle, statuscode)); + return(handle_ops[type]->own_handle (handle, abandoned)); } else { return(FALSE); } @@ -817,7 +755,7 @@ mono_w32handle_ops_specialwait (gpointer handle, guint32 timeout, gboolean *aler MonoW32HandleType type; if (!mono_w32handle_lookup_data (handle, &handle_data)) { - return(WAIT_FAILED); + return MONO_W32HANDLE_WAIT_RET_FAILED; } type = handle_data->type; @@ -826,7 +764,7 @@ mono_w32handle_ops_specialwait (gpointer handle, guint32 timeout, gboolean *aler handle_ops[type]->special_wait != NULL) { return(handle_ops[type]->special_wait (handle, timeout, alerted)); } else { - return(WAIT_FAILED); + return MONO_W32HANDLE_WAIT_RET_FAILED; } } @@ -879,7 +817,7 @@ again: if (!mono_w32handle_trylock_handle (handle)) { /* Bummer */ - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: attempt failed for %p: %s", __func__, + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: attempt failed for %p.", __func__, handle); while (i--) { @@ -1020,13 +958,14 @@ signal_handle_and_unref (gpointer handle) mono_os_cond_broadcast (cond); mono_os_mutex_unlock (mutex); - mono_w32handle_unref (handle); + mono_w32handle_close (handle); } static int mono_w32handle_timedwait_signal_handle (gpointer handle, guint32 timeout, gboolean poll, gboolean *alerted) { MonoW32HandleBase *handle_data; + gpointer handle_duplicate; int res; if (!mono_w32handle_lookup_data (handle, &handle_data)) @@ -1039,10 +978,11 @@ mono_w32handle_timedwait_signal_handle (gpointer handle, guint32 timeout, gboole *alerted = FALSE; if (alerted) { - mono_thread_info_install_interrupt (signal_handle_and_unref, handle, alerted); - if (*alerted) + mono_thread_info_install_interrupt (signal_handle_and_unref, handle_duplicate = mono_w32handle_duplicate (handle), alerted); + if (*alerted) { + mono_w32handle_close (handle_duplicate); return 0; - mono_w32handle_ref (handle); + } } res = mono_w32handle_timedwait_signal_naked (&handle_data->signal_cond, &handle_data->signal_mutex, timeout, poll, alerted); @@ -1050,8 +990,8 @@ mono_w32handle_timedwait_signal_handle (gpointer handle, guint32 timeout, gboole if (alerted) { mono_thread_info_uninstall_interrupt (alerted); if (!*alerted) { - /* if it is alerted, then the handle is unref in the interrupt callback */ - mono_w32handle_unref (handle); + /* if it is alerted, then the handle_duplicate is closed in the interrupt callback */ + mono_w32handle_close (handle_duplicate); } } @@ -1067,7 +1007,7 @@ dump_callback (gpointer handle, gpointer handle_specific, gpointer user_data) g_error ("cannot dump unknown handle %p", handle); g_print ("%p [%7s] signalled: %5s ref: %3d ", - handle, mono_w32handle_ops_typename (handle_data->type), handle_data->signalled ? "true" : "false", handle_data->ref); + handle, mono_w32handle_ops_typename (handle_data->type), handle_data->signalled ? "true" : "false", handle_data->ref - 1 /* foreach increase ref by 1 */); mono_w32handle_ops_details (handle_data->type, handle_data->specific); g_print ("\n"); @@ -1080,24 +1020,24 @@ void mono_w32handle_dump (void) } static gboolean -own_if_signalled (gpointer handle, guint32 *statuscode) +own_if_signalled (gpointer handle, gboolean *abandoned) { if (!mono_w32handle_issignalled (handle)) return FALSE; - *statuscode = WAIT_OBJECT_0; - mono_w32handle_ops_own (handle, statuscode); + *abandoned = FALSE; + mono_w32handle_ops_own (handle, abandoned); return TRUE; } static gboolean -own_if_owned( gpointer handle, guint32 *statuscode) +own_if_owned( gpointer handle, gboolean *abandoned) { if (!mono_w32handle_ops_isowned (handle)) return FALSE; - *statuscode = WAIT_OBJECT_0; - mono_w32handle_ops_own (handle, statuscode); + *abandoned = FALSE; + mono_w32handle_ops_own (handle, abandoned); return TRUE; } @@ -1107,7 +1047,7 @@ mono_w32handle_wait_one (gpointer handle, guint32 timeout, gboolean alertable) MonoW32HandleWaitRet ret; gboolean alerted; gint64 start; - guint32 statuscode = 0; + gboolean abandoned = FALSE; alerted = FALSE; @@ -1128,33 +1068,35 @@ mono_w32handle_wait_one (gpointer handle, guint32 timeout, gboolean alertable) mono_w32handle_lock_handle (handle); if (mono_w32handle_test_capabilities (handle, MONO_W32HANDLE_CAP_OWN)) { - if (own_if_owned (handle, &statuscode)) { + if (own_if_owned (handle, &abandoned)) { mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p already owned", __func__, handle); - ret = statuscode == WAIT_ABANDONED_0 ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0; + ret = abandoned ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0; goto done; } } - if (timeout != INFINITE) + if (timeout != MONO_INFINITE_WAIT) start = mono_msec_ticks (); + mono_w32handle_set_in_use (handle, TRUE); + for (;;) { gint waited; - if (own_if_signalled (handle, &statuscode)) { + if (own_if_signalled (handle, &abandoned)) { mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p signalled", __func__, handle); - ret = statuscode == WAIT_ABANDONED_0 ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0; + ret = abandoned ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0; goto done; } mono_w32handle_ops_prewait (handle); - if (timeout == INFINITE) { - waited = mono_w32handle_timedwait_signal_handle (handle, INFINITE, FALSE, alertable ? &alerted : NULL); + if (timeout == MONO_INFINITE_WAIT) { + waited = mono_w32handle_timedwait_signal_handle (handle, MONO_INFINITE_WAIT, FALSE, alertable ? &alerted : NULL); } else { gint64 elapsed; @@ -1179,6 +1121,8 @@ mono_w32handle_wait_one (gpointer handle, guint32 timeout, gboolean alertable) } done: + mono_w32handle_set_in_use (handle, FALSE); + mono_w32handle_unlock_handle (handle); return ret; @@ -1192,7 +1136,7 @@ mono_w32handle_wait_multiple (gpointer *handles, gsize nhandles, gboolean waital gint i; gint64 start; gpointer handles_sorted [MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS]; - guint32 statuscodes [MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS] = {0}; + gboolean abandoned [MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS] = {0}; if (nhandles == 0) return MONO_W32HANDLE_WAIT_RET_FAILED; @@ -1240,7 +1184,7 @@ mono_w32handle_wait_multiple (gpointer *handles, gsize nhandles, gboolean waital } } - if (timeout != INFINITE) + if (timeout != MONO_INFINITE_WAIT) start = mono_msec_ticks (); for (i = 0; i < nhandles; ++i) { @@ -1274,8 +1218,13 @@ mono_w32handle_wait_multiple (gpointer *handles, gsize nhandles, gboolean waital signalled = (waitall && count == nhandles) || (!waitall && count > 0); if (signalled) { - for (i = 0; i < nhandles; i++) - own_if_signalled (handles [i], &statuscodes [i]); + for (i = 0; i < nhandles; i++) { + if (own_if_signalled (handles [i], &abandoned [i]) && !waitall) { + /* if we are calling WaitHandle.WaitAny, .NET only owns the first one; it matters for Mutex which + * throw AbandonedMutexException in case we owned it but didn't release it */ + break; + } + } } mono_w32handle_unlock_handles (handles, nhandles); @@ -1283,7 +1232,7 @@ mono_w32handle_wait_multiple (gpointer *handles, gsize nhandles, gboolean waital if (signalled) { ret = MONO_W32HANDLE_WAIT_RET_SUCCESS_0 + lowest; for (i = lowest; i < nhandles; i++) { - if (statuscodes [i] == WAIT_ABANDONED_0) { + if (abandoned [i]) { ret = MONO_W32HANDLE_WAIT_RET_ABANDONED_0 + lowest; break; } @@ -1324,8 +1273,8 @@ mono_w32handle_wait_multiple (gpointer *handles, gsize nhandles, gboolean waital waited = 0; if (!signalled) { - if (timeout == INFINITE) { - waited = mono_w32handle_timedwait_signal (INFINITE, poll, alertable ? &alerted : NULL); + if (timeout == MONO_INFINITE_WAIT) { + waited = mono_w32handle_timedwait_signal (MONO_INFINITE_WAIT, poll, alertable ? &alerted : NULL); } else { gint64 elapsed; @@ -1370,7 +1319,7 @@ mono_w32handle_signal_and_wait (gpointer signal_handle, gpointer wait_handle, gu MonoW32HandleWaitRet ret; gint64 start; gboolean alerted; - guint32 statuscode = 0; + gboolean abandoned = FALSE; gpointer handles [2]; alerted = FALSE; @@ -1395,33 +1344,33 @@ mono_w32handle_signal_and_wait (gpointer signal_handle, gpointer wait_handle, gu mono_w32handle_unlock_handle (signal_handle); if (mono_w32handle_test_capabilities (wait_handle, MONO_W32HANDLE_CAP_OWN)) { - if (own_if_owned (wait_handle, &statuscode)) { + if (own_if_owned (wait_handle, &abandoned)) { mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p already owned", __func__, wait_handle); - ret = statuscode == WAIT_ABANDONED_0 ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0; + ret = abandoned ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0; goto done; } } - if (timeout != INFINITE) + if (timeout != MONO_INFINITE_WAIT) start = mono_msec_ticks (); for (;;) { gint waited; - if (own_if_signalled (wait_handle, &statuscode)) { + if (own_if_signalled (wait_handle, &abandoned)) { mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p signalled", __func__, wait_handle); - ret = statuscode == WAIT_ABANDONED_0 ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0; + ret = abandoned ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0; goto done; } mono_w32handle_ops_prewait (wait_handle); - if (timeout == INFINITE) { - waited = mono_w32handle_timedwait_signal_handle (wait_handle, INFINITE, FALSE, alertable ? &alerted : NULL); + if (timeout == MONO_INFINITE_WAIT) { + waited = mono_w32handle_timedwait_signal_handle (wait_handle, MONO_INFINITE_WAIT, FALSE, alertable ? &alerted : NULL); } else { gint64 elapsed;