-/*
- * w32handle.c: Generic and internal operations on handles
+/**
+ * \file
+ * Generic and internal operations on handles
*
* Author:
* Dick Porter (dick@ximian.com)
#undef DEBUG_REFS
-#define SLOT_MAX (1024 * 16)
+#define SLOT_MAX (1024 * 32)
/* must be a power of 2 */
#define HANDLE_PER_SLOT (256)
MonoW32HandleType type;
guint ref;
gboolean signalled;
+ gboolean in_use;
mono_mutex_t signal_mutex;
mono_cond_t signal_cond;
gpointer specific;
#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.
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)
{
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)
{
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)
{
mono_w32handle_unref (handle);
}
-/*
- * wapi_init:
- *
- * Initialize the io-layer.
- */
void
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);
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]);
}
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
* 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];
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++;
}
}
- 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
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++) {
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;
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
}
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;
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);
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);
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
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)
{
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;
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);
}
MonoW32HandleType type;
if (!mono_w32handle_lookup_data (handle, &handle_data)) {
- return(WAIT_FAILED);
+ return MONO_W32HANDLE_WAIT_RET_FAILED;
}
type = handle_data->type;
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;
}
}
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))
*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);
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);
}
}
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");
}
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;
}
MonoW32HandleWaitRet ret;
gboolean alerted;
gint64 start;
- guint32 statuscode = 0;
+ gboolean abandoned = FALSE;
alerted = FALSE;
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 != 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;
}
}
done:
+ mono_w32handle_set_in_use (handle, FALSE);
+
mono_w32handle_unlock_handle (handle);
return ret;
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;
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);
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;
}
MonoW32HandleWaitRet ret;
gint64 start;
gboolean alerted;
- guint32 statuscode = 0;
+ gboolean abandoned = FALSE;
gpointer handles [2];
alerted = FALSE;
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;
}
}
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;
}