[w32handle] Fix deadlock on SignalAndWait (#4973)
[mono.git] / mono / metadata / w32handle.c
index 6e2a7659ab210c11287023801acbb12cfdd8fdcd..f6862a9a7dba737452b39cb840286b84d52883c1 100644 (file)
@@ -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)
  */
 
 #include <config.h>
-
-#if !defined(HOST_WIN32)
-
 #include <glib.h>
-#include <pthread.h>
-#include <errno.h>
-#include <unistd.h>
-#ifdef HAVE_SIGNAL_H
-#include <signal.h>
-#endif
-#include <string.h>
-#include <sys/types.h>
-#ifdef HAVE_SYS_SOCKET_H
-#  include <sys/socket.h>
-#endif
-#ifdef HAVE_SYS_UN_H
-#  include <sys/un.h>
-#endif
-#ifdef HAVE_SYS_MMAN_H
-#  include <sys/mman.h>
-#endif
-#ifdef HAVE_DIRENT_H
-#  include <dirent.h>
-#endif
-#include <sys/stat.h>
-#ifdef HAVE_SYS_RESOURCE_H
-#  include <sys/resource.h>
-#endif
 
 #include "w32handle.h"
 
 
 #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;
@@ -141,6 +113,15 @@ mono_w32handle_get_type (gpointer handle)
        return handle_data->type;
 }
 
+static const gchar*
+mono_w32handle_ops_typename (MonoW32HandleType type);
+
+const gchar*
+mono_w32handle_get_typename (MonoW32HandleType type)
+{
+       return mono_w32handle_ops_typename (type);
+}
+
 void
 mono_w32handle_set_signal_state (gpointer handle, gboolean state, gboolean broadcast)
 {
@@ -197,7 +178,7 @@ mono_w32handle_issignalled (gpointer handle)
        return handle_data->signalled;
 }
 
-static int
+static void
 mono_w32handle_lock_signal_mutex (void)
 {
 #ifdef DEBUG
@@ -205,11 +186,9 @@ mono_w32handle_lock_signal_mutex (void)
 #endif
 
        mono_os_mutex_lock (&global_signal_mutex);
-
-       return 0;
 }
 
-static int
+static void
 mono_w32handle_unlock_signal_mutex (void)
 {
 #ifdef DEBUG
@@ -217,79 +196,60 @@ mono_w32handle_unlock_signal_mutex (void)
 #endif
 
        mono_os_mutex_unlock (&global_signal_mutex);
-
-       return 0;
 }
 
-int
+void
 mono_w32handle_lock_handle (gpointer handle)
 {
        MonoW32HandleBase *handle_data;
 
-#ifdef DEBUG
-       g_message ("%s: locking handle %p", __func__, handle);
-#endif
-
-       if (!mono_w32handle_lookup_data (handle, &handle_data)) {
-               return(0);
-       }
+       if (!mono_w32handle_lookup_data (handle, &handle_data))
+               g_error ("%s: failed to lookup handle %p", __func__, handle);
 
        mono_w32handle_ref (handle);
 
        mono_os_mutex_lock (&handle_data->signal_mutex);
 
-       return 0;
+       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: lock handle %p", __func__, handle);
 }
 
-int
+gboolean
 mono_w32handle_trylock_handle (gpointer handle)
 {
        MonoW32HandleBase *handle_data;
-       int ret;
+       gboolean locked;
 
-#ifdef DEBUG
-       g_message ("%s: locking handle %p", __func__, handle);
-#endif
+       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: trylock handle %p", __func__, handle);
 
-       if (!mono_w32handle_lookup_data (handle, &handle_data)) {
-               return(0);
-       }
+       if (!mono_w32handle_lookup_data (handle, &handle_data))
+               g_error ("%s: failed to lookup handle %p", __func__, handle);
 
        mono_w32handle_ref (handle);
 
-       ret = mono_os_mutex_trylock (&handle_data->signal_mutex);
-       if (ret != 0) {
+       locked = mono_os_mutex_trylock (&handle_data->signal_mutex) == 0;
+       if (!locked)
                mono_w32handle_unref (handle);
-       }
 
-       return(ret);
+       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: trylock handle %p, locked: %s", __func__, handle, locked ? "true" : "false");
+
+       return locked;
 }
 
-int
+void
 mono_w32handle_unlock_handle (gpointer handle)
 {
        MonoW32HandleBase *handle_data;
 
-#ifdef DEBUG
-       g_message ("%s: unlocking handle %p", __func__, handle);
-#endif
+       if (!mono_w32handle_lookup_data (handle, &handle_data))
+               g_error ("%s: failed to lookup handle %p", __func__, handle);
 
-       if (!mono_w32handle_lookup_data (handle, &handle_data)) {
-               return(0);
-       }
+       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: unlock handle %p", __func__, handle);
 
        mono_os_mutex_unlock (&handle_data->signal_mutex);
 
        mono_w32handle_unref (handle);
-
-       return 0;
 }
 
-/*
- * wapi_init:
- *
- *   Initialize the io-layer.
- */
 void
 mono_w32handle_init (void)
 {
@@ -352,6 +312,9 @@ mono_w32handle_cleanup (void)
                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)
 {
@@ -515,6 +478,24 @@ gpointer mono_w32handle_new_fd (MonoW32HandleType type, int fd,
        return(GUINT_TO_POINTER(fd));
 }
 
+gboolean
+mono_w32handle_close (gpointer handle)
+{
+       if (handle == INVALID_HANDLE_VALUE)
+               return FALSE;
+       if (handle == (gpointer) 0 && mono_w32handle_get_type (handle) != MONO_W32HANDLE_CONSOLE) {
+               /* Problem: because we map file descriptors to the
+                * same-numbered handle we can't tell the difference
+                * between a bogus handle and the handle to stdin.
+                * Assume that it's the console handle if that handle
+                * exists... */
+               return FALSE;
+       }
+
+       mono_w32handle_unref (handle);
+       return TRUE;
+}
+
 gboolean
 mono_w32handle_lookup (gpointer handle, MonoW32HandleType type,
                              gpointer *handle_specific)
@@ -540,13 +521,19 @@ static gboolean
 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);
+
+static void
+w32handle_destroy (gpointer handle);
 
 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++) {
@@ -572,10 +559,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;
@@ -584,57 +579,13 @@ mono_w32handle_foreach (gboolean (*on_each)(gpointer handle, gpointer data, gpoi
 
 done:
        mono_os_mutex_unlock (&scan_mutex);
-}
-
-typedef struct {
-       MonoW32HandleType type;
-       gboolean (*search_user_callback)(gpointer handle, gpointer data);
-       gpointer search_user_data;
-       gpointer handle;
-       gpointer handle_specific;
-} SearchData;
-
-static gboolean
-search_callback (gpointer handle, gpointer handle_specific, gpointer user_data)
-{
-       SearchData *search_data = (SearchData*) user_data;
-
-       if (search_data->type != mono_w32handle_get_type (handle))
-               return FALSE;
 
-       if (!search_data->search_user_callback (handle, search_data->search_user_data))
-               return FALSE;
-
-       mono_w32handle_ref (handle);
-       search_data->handle = handle;
-       search_data->handle_specific = handle_specific;
-       return TRUE;
-}
+       if (handles_to_destroy) {
+               for (i = 0; i < handles_to_destroy->len; ++i)
+                       w32handle_destroy (handles_to_destroy->pdata [i]);
 
-/* This might list some shared handles twice if they are already
- * opened by this process, and the check function returns FALSE the
- * first time.  Shared handles that are created during the search are
- * unreffed if the check function returns FALSE, so callers must not
- * rely on the handle persisting (unless the check function returns
- * TRUE)
- * The caller owns the returned handle.
- */
-gpointer mono_w32handle_search (MonoW32HandleType type,
-                             gboolean (*check)(gpointer test, gpointer user),
-                             gpointer user_data,
-                             gpointer *handle_specific,
-                             gboolean search_shared)
-{
-       SearchData search_data;
-
-       memset (&search_data, 0, sizeof (search_data));
-       search_data.type = type;
-       search_data.search_user_callback = check;
-       search_data.search_user_data = user_data;
-       mono_w32handle_foreach (search_callback, &search_data);
-       if (handle_specific)
-               *handle_specific = search_data.handle_specific;
-       return search_data.handle;
+               g_ptr_array_free (handles_to_destroy, TRUE);
+       }
 }
 
 static gboolean
@@ -657,7 +608,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;
@@ -666,8 +617,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);
@@ -696,6 +647,45 @@ void mono_w32handle_ref (gpointer handle)
 
 static void (*_wapi_handle_ops_get_close_func (MonoW32HandleType type))(gpointer, gpointer);
 
+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;
+       MonoW32HandleType type;
+       gpointer handle_specific;
+       void (*close_func)(gpointer, gpointer);
+
+       if (!mono_w32handle_lookup_data (handle, &handle_data))
+               g_error ("%s: unknown handle %p", __func__, handle);
+
+       type = handle_data->type;
+       handle_specific = handle_data->specific;
+
+       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_os_mutex_destroy (&handle_data->signal_mutex);
+       mono_os_cond_destroy (&handle_data->signal_cond);
+
+       memset (handle_data, 0, sizeof (MonoW32HandleBase));
+
+       mono_os_mutex_unlock (&scan_mutex);
+
+       close_func = _wapi_handle_ops_get_close_func (type);
+       if (close_func != NULL) {
+               close_func (handle, handle_specific);
+       }
+
+       g_free (handle_specific);
+}
+
 /* The handle must not be locked on entry to this function */
 void
 mono_w32handle_unref (gpointer handle)
@@ -709,40 +699,18 @@ mono_w32handle_unref (gpointer handle)
                return;
        }
 
-       destroy = mono_w32handle_unref_core (handle, handle_data, 1);
-
-       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;
-
-               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_os_mutex_destroy (&handle_data->signal_mutex);
-               mono_os_cond_destroy (&handle_data->signal_cond);
-
-               memset (handle_data, 0, sizeof (MonoW32HandleBase));
-
-               mono_os_mutex_unlock (&scan_mutex);
+       destroy = mono_w32handle_unref_core (handle, handle_data);
+       if (destroy)
+               w32handle_destroy (handle);
+}
 
-               close_func = _wapi_handle_ops_get_close_func (type);
-               if (close_func != NULL) {
-                       close_func (handle, handle_specific);
-               }
+static void
+mono_w32handle_ops_close (gpointer handle, gpointer data);
 
-               g_free (handle_specific);
-       }
+void
+mono_w32handle_force_close (gpointer handle, gpointer data)
+{
+       mono_w32handle_ops_close (handle, data);
 }
 
 void
@@ -785,7 +753,8 @@ static void (*_wapi_handle_ops_get_close_func (MonoW32HandleType type))(gpointer
        return (NULL);
 }
 
-void mono_w32handle_ops_close (gpointer handle, gpointer data)
+static void
+mono_w32handle_ops_close (gpointer handle, gpointer data)
 {
        MonoW32HandleBase *handle_data;
        MonoW32HandleType type;
@@ -802,7 +771,8 @@ void mono_w32handle_ops_close (gpointer handle, gpointer data)
        }
 }
 
-void mono_w32handle_ops_details (MonoW32HandleType type, gpointer data)
+static void
+mono_w32handle_ops_details (MonoW32HandleType type, gpointer data)
 {
        if (handle_ops[type] != NULL &&
            handle_ops[type]->details != NULL) {
@@ -810,21 +780,24 @@ void mono_w32handle_ops_details (MonoW32HandleType type, gpointer data)
        }
 }
 
-const gchar* mono_w32handle_ops_typename (MonoW32HandleType type)
+static const gchar*
+mono_w32handle_ops_typename (MonoW32HandleType type)
 {
        g_assert (handle_ops [type]);
        g_assert (handle_ops [type]->typename);
        return handle_ops [type]->typename ();
 }
 
-gsize mono_w32handle_ops_typesize (MonoW32HandleType type)
+static gsize
+mono_w32handle_ops_typesize (MonoW32HandleType type)
 {
        g_assert (handle_ops [type]);
        g_assert (handle_ops [type]->typesize);
        return handle_ops [type]->typesize ();
 }
 
-void mono_w32handle_ops_signal (gpointer handle)
+static void
+mono_w32handle_ops_signal (gpointer handle)
 {
        MonoW32HandleBase *handle_data;
        MonoW32HandleType type;
@@ -836,11 +809,12 @@ void 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);
        }
 }
 
-gboolean mono_w32handle_ops_own (gpointer handle, guint32 *statuscode)
+static gboolean
+mono_w32handle_ops_own (gpointer handle, gboolean *abandoned)
 {
        MonoW32HandleBase *handle_data;
        MonoW32HandleType type;
@@ -852,13 +826,14 @@ gboolean 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);
        }
 }
 
-gboolean mono_w32handle_ops_isowned (gpointer handle)
+static gboolean
+mono_w32handle_ops_isowned (gpointer handle)
 {
        MonoW32HandleBase *handle_data;
        MonoW32HandleType type;
@@ -876,13 +851,14 @@ gboolean mono_w32handle_ops_isowned (gpointer handle)
        }
 }
 
-guint32 mono_w32handle_ops_specialwait (gpointer handle, guint32 timeout, gboolean *alerted)
+static MonoW32HandleWaitRet
+mono_w32handle_ops_specialwait (gpointer handle, guint32 timeout, gboolean *alerted)
 {
        MonoW32HandleBase *handle_data;
        MonoW32HandleType type;
 
        if (!mono_w32handle_lookup_data (handle, &handle_data)) {
-               return(WAIT_FAILED);
+               return MONO_W32HANDLE_WAIT_RET_FAILED;
        }
 
        type = handle_data->type;
@@ -891,11 +867,12 @@ guint32 mono_w32handle_ops_specialwait (gpointer handle, guint32 timeout, gboole
            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;
        }
 }
 
-void mono_w32handle_ops_prewait (gpointer handle)
+static void
+mono_w32handle_ops_prewait (gpointer handle)
 {
        MonoW32HandleBase *handle_data;
        MonoW32HandleType type;
@@ -915,6 +892,9 @@ void mono_w32handle_ops_prewait (gpointer handle)
 static void
 spin (guint32 ms)
 {
+#ifdef HOST_WIN32
+       SleepEx (ms, TRUE);
+#else
        struct timespec sleepytime;
 
        g_assert (ms < 1000);
@@ -922,13 +902,13 @@ spin (guint32 ms)
        sleepytime.tv_sec = 0;
        sleepytime.tv_nsec = ms * 1000000;
        nanosleep (&sleepytime, NULL);
+#endif /* HOST_WIN32 */
 }
 
 static void
 mono_w32handle_lock_handles (gpointer *handles, gsize numhandles)
 {
        guint32 i, iter=0;
-       int thr_ret;
 
        /* Lock all the handles, with backoff */
 again:
@@ -937,19 +917,16 @@ again:
 
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: attempting to lock %p", __func__, handle);
 
-               thr_ret = mono_w32handle_trylock_handle (handle);
-
-               if (thr_ret != 0) {
+               if (!mono_w32handle_trylock_handle (handle)) {
                        /* Bummer */
 
-                       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: attempt failed for %p: %s", __func__,
-                                  handle, strerror (thr_ret));
+                       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: attempt failed for %p.", __func__,
+                                  handle);
 
                        while (i--) {
                                handle = handles[i];
 
-                               thr_ret = mono_w32handle_unlock_handle (handle);
-                               g_assert (thr_ret == 0);
+                               mono_w32handle_unlock_handle (handle);
                        }
 
                        /* If iter ever reaches 100 the nanosleep will
@@ -978,15 +955,13 @@ static void
 mono_w32handle_unlock_handles (gpointer *handles, gsize numhandles)
 {
        guint32 i;
-       int thr_ret;
 
        for(i=0; i<numhandles; i++) {
                gpointer handle = handles[i];
 
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: unlocking handle %p", __func__, handle);
 
-               thr_ret = mono_w32handle_unlock_handle (handle);
-               g_assert (thr_ret == 0);
+               mono_w32handle_unlock_handle (handle);
        }
 }
 
@@ -1146,24 +1121,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;
 }
 
@@ -1173,8 +1148,7 @@ mono_w32handle_wait_one (gpointer handle, guint32 timeout, gboolean alertable)
        MonoW32HandleWaitRet ret;
        gboolean alerted;
        gint64 start;
-       gint thr_ret;
-       guint32 statuscode = 0;
+       gboolean abandoned = FALSE;
 
        alerted = FALSE;
 
@@ -1182,30 +1156,7 @@ mono_w32handle_wait_one (gpointer handle, guint32 timeout, gboolean alertable)
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p has special wait",
                        __func__, handle);
 
-               switch (mono_w32handle_ops_specialwait (handle, timeout, alertable ? &alerted : NULL)) {
-               case WAIT_OBJECT_0:
-                       ret = MONO_W32HANDLE_WAIT_RET_SUCCESS_0;
-                       break;
-               case WAIT_ABANDONED_0:
-                       ret = MONO_W32HANDLE_WAIT_RET_ABANDONED_0;
-                       break;
-               case WAIT_IO_COMPLETION:
-                       ret = MONO_W32HANDLE_WAIT_RET_ALERTED;
-                       break;
-               case WAIT_TIMEOUT:
-                       ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT;
-                       break;
-               case WAIT_FAILED:
-                       ret = MONO_W32HANDLE_WAIT_RET_FAILED;
-                       break;
-               default:
-                       g_assert_not_reached ();
-               }
-
-               if (alerted)
-                       ret = MONO_W32HANDLE_WAIT_RET_ALERTED;
-
-               return ret;
+               return mono_w32handle_ops_specialwait (handle, timeout, alertable ? &alerted : NULL);
        }
 
        if (!mono_w32handle_test_capabilities (handle, MONO_W32HANDLE_CAP_WAIT)) {
@@ -1215,37 +1166,36 @@ mono_w32handle_wait_one (gpointer handle, guint32 timeout, gboolean alertable)
                return MONO_W32HANDLE_WAIT_RET_FAILED;
        }
 
-       thr_ret = mono_w32handle_lock_handle (handle);
-       g_assert (thr_ret == 0);
+       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 ();
 
        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;
 
@@ -1270,8 +1220,7 @@ mono_w32handle_wait_one (gpointer handle, guint32 timeout, gboolean alertable)
        }
 
 done:
-       thr_ret = mono_w32handle_unlock_handle (handle);
-       g_assert (thr_ret == 0);
+       mono_w32handle_unlock_handle (handle);
 
        return ret;
 }
@@ -1281,10 +1230,10 @@ mono_w32handle_wait_multiple (gpointer *handles, gsize nhandles, gboolean waital
 {
        MonoW32HandleWaitRet ret;
        gboolean alerted, poll;
-       gint i, thr_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;
@@ -1332,7 +1281,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) {
@@ -1367,7 +1316,7 @@ mono_w32handle_wait_multiple (gpointer *handles, gsize nhandles, gboolean waital
 
                if (signalled) {
                        for (i = 0; i < nhandles; i++)
-                               own_if_signalled (handles [i], &statuscodes [i]);
+                               own_if_signalled (handles [i], &abandoned [i]);
                }
 
                mono_w32handle_unlock_handles (handles, nhandles);
@@ -1375,7 +1324,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;
                                }
@@ -1393,8 +1342,7 @@ mono_w32handle_wait_multiple (gpointer *handles, gsize nhandles, gboolean waital
                        }
                }
 
-               thr_ret = mono_w32handle_lock_signal_mutex ();
-               g_assert (thr_ret == 0);
+               mono_w32handle_lock_signal_mutex ();
 
                if (waitall) {
                        signalled = TRUE;
@@ -1417,8 +1365,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;
 
@@ -1426,8 +1374,7 @@ mono_w32handle_wait_multiple (gpointer *handles, gsize nhandles, gboolean waital
                                if (elapsed > timeout) {
                                        ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT;
 
-                                       thr_ret = mono_w32handle_unlock_signal_mutex ();
-                                       g_assert (thr_ret == 0);
+                                       mono_w32handle_unlock_signal_mutex ();
 
                                        goto done;
                                }
@@ -1436,8 +1383,7 @@ mono_w32handle_wait_multiple (gpointer *handles, gsize nhandles, gboolean waital
                        }
                }
 
-               thr_ret = mono_w32handle_unlock_signal_mutex ();
-               g_assert (thr_ret == 0);
+               mono_w32handle_unlock_signal_mutex ();
 
                if (alerted) {
                        ret = MONO_W32HANDLE_WAIT_RET_ALERTED;
@@ -1465,8 +1411,8 @@ mono_w32handle_signal_and_wait (gpointer signal_handle, gpointer wait_handle, gu
        MonoW32HandleWaitRet ret;
        gint64 start;
        gboolean alerted;
-       gint thr_ret;
-       guint32 statuscode = 0;
+       gboolean abandoned = FALSE;
+       gpointer handles [2];
 
        alerted = FALSE;
 
@@ -1480,39 +1426,43 @@ mono_w32handle_signal_and_wait (gpointer signal_handle, gpointer wait_handle, gu
                return MONO_W32HANDLE_WAIT_RET_FAILED;
        }
 
-       thr_ret = mono_w32handle_lock_handle (wait_handle);
-       g_assert (thr_ret == 0);
+       handles [0] = wait_handle;
+       handles [1] = signal_handle;
+
+       mono_w32handle_lock_handles (handles, 2);
 
        mono_w32handle_ops_signal (signal_handle);
 
+       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;
 
@@ -1537,10 +1487,7 @@ mono_w32handle_signal_and_wait (gpointer signal_handle, gpointer wait_handle, gu
        }
 
 done:
-       thr_ret = mono_w32handle_unlock_handle (wait_handle);
-       g_assert (thr_ret == 0);
+       mono_w32handle_unlock_handle (wait_handle);
 
        return ret;
 }
-
-#endif /* !defined(HOST_WIN32) */