Merge pull request #5714 from alexischr/update_bockbuild
[mono.git] / mono / metadata / monitor.c
index b9a305121641975286467b84392ceba8856a4111..d3b51abfc80247f536fdb2410f28edf528411200 100644 (file)
@@ -1,5 +1,6 @@
-/*
- * monitor.c:  Monitor locking functions
+/**
+ * \file
+ * Monitor locking functions
  *
  * Author:
  *     Dick Porter (dick@ximian.com)
@@ -18,7 +19,6 @@
 #include <mono/metadata/threads-types.h>
 #include <mono/metadata/exception.h>
 #include <mono/metadata/threads.h>
-#include <mono/io-layer/io-layer.h>
 #include <mono/metadata/object-internals.h>
 #include <mono/metadata/class-internals.h>
 #include <mono/metadata/gc-internals.h>
 #include <mono/metadata/debug-helpers.h>
 #include <mono/metadata/tabledefs.h>
 #include <mono/metadata/marshal.h>
+#include <mono/metadata/w32event.h>
 #include <mono/utils/mono-threads.h>
 #include <mono/metadata/profiler-private.h>
 #include <mono/utils/mono-time.h>
 #include <mono/utils/atomic.h>
+#include <mono/utils/w32api.h>
+#include <mono/utils/mono-os-wait.h>
 
 /*
  * Pull the list of opcodes
@@ -306,10 +309,9 @@ monitor_is_on_freelist (MonoThreadsSync *mon)
 
 /**
  * mono_locks_dump:
- * @include_untaken:
- *
+ * \param include_untaken Whether to list unheld inflated locks.
  * Print a report on stdout of the managed locks currently held by
- * threads. If @include_untaken is specified, list also inflated locks
+ * threads. If \p include_untaken is specified, list also inflated locks
  * which are unheld.
  * This is supposed to be used in debuggers like gdb.
  */
@@ -357,7 +359,8 @@ mon_finalize (MonoThreadsSync *mon)
        LOCK_DEBUG (g_message ("%s: Finalizing sync %p", __func__, mon));
 
        if (mon->entry_sem != NULL) {
-               CloseHandle (mon->entry_sem);
+               mono_coop_sem_destroy (mon->entry_sem);
+               g_free (mon->entry_sem);
                mon->entry_sem = NULL;
        }
        /* If this isn't empty then something is seriously broken - it
@@ -371,7 +374,7 @@ mon_finalize (MonoThreadsSync *mon)
        mon->data = monitor_freelist;
        monitor_freelist = mon;
 #ifndef DISABLE_PERFCOUNTERS
-       mono_perfcounters->gc_sync_blocks--;
+       InterlockedDecrement (&mono_perfcounters->gc_sync_blocks);
 #endif
 }
 
@@ -394,7 +397,7 @@ mon_new (gsize id)
                                                /* Orphaned events left by aborted threads */
                                                while (new_->wait_list) {
                                                        LOCK_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": (%d): Closing orphaned event %d", mono_thread_info_get_small_id (), new_->wait_list->data));
-                                                       CloseHandle (new_->wait_list->data);
+                                                       mono_w32event_close (new_->wait_list->data);
                                                        new_->wait_list = g_slist_remove (new_->wait_list, new_->wait_list->data);
                                                }
                                        }
@@ -443,7 +446,7 @@ mon_new (gsize id)
        new_->data = NULL;
        
 #ifndef DISABLE_PERFCOUNTERS
-       mono_perfcounters->gc_sync_blocks++;
+       InterlockedIncrement (&mono_perfcounters->gc_sync_blocks);
 #endif
        return new_;
 }
@@ -629,18 +632,19 @@ mono_object_hash (MonoObject* obj)
 #endif
 }
 
-static void
+static gboolean
 mono_monitor_ensure_owned (LockWord lw, guint32 id)
 {
        if (lock_word_is_flat (lw)) {
                if (lock_word_get_owner (lw) == id)
-                       return;
+                       return TRUE;
        } else if (lock_word_is_inflated (lw)) {
                if (mon_status_get_owner (lock_word_get_inflated_lock (lw)->status) == id)
-                       return;
+                       return TRUE;
        }
 
        mono_set_pending_exception (mono_get_exception_synchronization_lock ("Object synchronization method was called from an unsynchronized block of code."));
+       return FALSE;
 }
 
 /*
@@ -679,7 +683,7 @@ mono_monitor_exit_inflated (MonoObject *obj)
                        tmp_status = InterlockedCompareExchange ((gint32*)&mon->status, new_status, old_status);
                        if (tmp_status == old_status) {
                                if (have_waiters)
-                                       ReleaseSemaphore (mon->entry_sem, 1, NULL);
+                                       mono_coop_sem_post (mon->entry_sem);
                                break;
                        }
                        old_status = tmp_status;
@@ -745,8 +749,8 @@ mono_monitor_try_enter_inflated (MonoObject *obj, guint32 ms, gboolean allow_int
        HANDLE sem;
        gint64 then = 0, now, delta;
        guint32 waitms;
-       guint32 ret;
        guint32 new_status, old_status, tmp_status;
+       MonoSemTimedwaitRet wait_ret;
        MonoInternalThread *thread;
        gboolean interrupted = FALSE;
 
@@ -789,7 +793,7 @@ retry:
 
        /* The object must be locked by someone else... */
 #ifndef DISABLE_PERFCOUNTERS
-       mono_perfcounters->thread_contentions++;
+       InterlockedIncrement (&mono_perfcounters->thread_contentions);
 #endif
 
        /* If ms is 0 we don't block, but just fail straight away */
@@ -798,7 +802,7 @@ retry:
                return 0;
        }
 
-       mono_profiler_monitor_event (obj, MONO_PROFILER_MONITOR_CONTENTION);
+       MONO_PROFILER_RAISE (monitor_contention, (obj));
 
        /* The slow path begins here. */
 retry_contended:
@@ -821,7 +825,7 @@ retry_contended:
                if (G_LIKELY (tmp_status == old_status)) {
                        /* Success */
                        g_assert (mon->nest == 1);
-                       mono_profiler_monitor_event (obj, MONO_PROFILER_MONITOR_DONE);
+                       MONO_PROFILER_RAISE (monitor_acquired, (obj));
                        return 1;
                }
        }
@@ -829,7 +833,7 @@ retry_contended:
        /* If the object is currently locked by this thread... */
        if (mon_status_get_owner (old_status) == id) {
                mon->nest++;
-               mono_profiler_monitor_event (obj, MONO_PROFILER_MONITOR_DONE);
+               MONO_PROFILER_RAISE (monitor_acquired, (obj));
                return 1;
        }
 
@@ -838,11 +842,12 @@ retry_contended:
         */
        if (mon->entry_sem == NULL) {
                /* Create the semaphore */
-               sem = CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
-               g_assert (sem != NULL);
+               sem = g_new0 (MonoCoopSem, 1);
+               mono_coop_sem_init (sem, 0);
                if (InterlockedCompareExchangePointer ((gpointer*)&mon->entry_sem, sem, NULL) != NULL) {
                        /* Someone else just put a handle here */
-                       CloseHandle (sem);
+                       mono_coop_sem_destroy (sem);
+                       g_free (sem);
                }
        }
 
@@ -864,41 +869,58 @@ retry_contended:
                }
        }
 
-       if (ms != INFINITE) {
+       if (ms != MONO_INFINITE_WAIT) {
                then = mono_msec_ticks ();
        }
        waitms = ms;
        
 #ifndef DISABLE_PERFCOUNTERS
-       mono_perfcounters->thread_queue_len++;
-       mono_perfcounters->thread_queue_max++;
+       InterlockedIncrement (&mono_perfcounters->thread_queue_len);
+       InterlockedIncrement (&mono_perfcounters->thread_queue_max);
 #endif
        thread = mono_thread_internal_current ();
 
-       mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
+       /*
+        * If we allow interruption, we check the test state for an abort request before going into sleep.
+        * This is a workaround to the fact that Thread.Abort does non-sticky interruption of semaphores.
+        *
+        * Semaphores don't support the sticky interruption with mono_thread_info_install_interrupt.
+        *
+        * A better fix would be to switch to wait with something that allows sticky interrupts together
+        * with wrapping it with abort_protected_block_count for the non-alertable cases.
+        * And somehow make this whole dance atomic and not crazy expensive. Good luck.
+        *
+        */
+       if (allow_interruption) {
+               if (!mono_thread_test_and_set_state (thread, ThreadState_AbortRequested, ThreadState_WaitSleepJoin)) {
+                       wait_ret = MONO_SEM_TIMEDWAIT_RET_ALERTED;
+                       goto done_waiting;
+               }
+       } else {
+               mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
+       }
 
        /*
-        * We pass TRUE instead of allow_interruption since we have to check for the
+        * We pass ALERTABLE instead of allow_interruption since we have to check for the
         * StopRequested case below.
         */
-       MONO_ENTER_GC_SAFE;
-       ret = WaitForSingleObjectEx (mon->entry_sem, waitms, TRUE);
-       MONO_EXIT_GC_SAFE;
+       wait_ret = mono_coop_sem_timedwait (mon->entry_sem, waitms, MONO_SEM_FLAGS_ALERTABLE);
 
        mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
-       
+
+done_waiting:
 #ifndef DISABLE_PERFCOUNTERS
-       mono_perfcounters->thread_queue_len--;
+       InterlockedDecrement (&mono_perfcounters->thread_queue_len);
 #endif
 
-       if (ret == WAIT_IO_COMPLETION && !allow_interruption) {
+       if (wait_ret == MONO_SEM_TIMEDWAIT_RET_ALERTED && !allow_interruption) {
                interrupted = TRUE;
                /* 
                 * We have to obey a stop/suspend request even if 
                 * allow_interruption is FALSE to avoid hangs at shutdown.
                 */
-               if (!mono_thread_test_state (mono_thread_internal_current (), (MonoThreadState)(ThreadState_StopRequested | ThreadState_SuspendRequested | ThreadState_AbortRequested))) {
-                       if (ms != INFINITE) {
+               if (!mono_thread_test_state (mono_thread_internal_current (), ThreadState_SuspendRequested | ThreadState_AbortRequested)) {
+                       if (ms != MONO_INFINITE_WAIT) {
                                now = mono_msec_ticks ();
 
                                /* it should not overflow before ~30k years */
@@ -914,23 +936,23 @@ retry_contended:
                        /* retry from the top */
                        goto retry_contended;
                }
-       } else if (ret == WAIT_OBJECT_0) {
+       } else if (wait_ret == MONO_SEM_TIMEDWAIT_RET_SUCCESS) {
                interrupted = FALSE;
                /* retry from the top */
                goto retry_contended;
-       } else if (ret == WAIT_TIMEOUT) {
+       } else if (wait_ret == MONO_SEM_TIMEDWAIT_RET_TIMEDOUT) {
                /* we're done */
        }
 
        /* Timed out or interrupted */
        mon_decrement_entry_count (mon);
 
-       mono_profiler_monitor_event (obj, MONO_PROFILER_MONITOR_FAIL);
+       MONO_PROFILER_RAISE (monitor_failed, (obj));
 
-       if (ret == WAIT_IO_COMPLETION) {
+       if (wait_ret == MONO_SEM_TIMEDWAIT_RET_ALERTED) {
                LOCK_DEBUG (g_message ("%s: (%d) interrupted waiting, returning -1", __func__, id));
                return -1;
-       } else if (ret == WAIT_TIMEOUT) {
+       } else if (wait_ret == MONO_SEM_TIMEDWAIT_RET_TIMEDOUT) {
                LOCK_DEBUG (g_message ("%s: (%d) timed out waiting, returning FALSE", __func__, id));
                return 0;
        } else {
@@ -951,11 +973,6 @@ mono_monitor_try_enter_internal (MonoObject *obj, guint32 ms, gboolean allow_int
 
        LOCK_DEBUG (g_message("%s: (%d) Trying to lock object %p (%d ms)", __func__, id, obj, ms));
 
-       if (G_UNLIKELY (!obj)) {
-               mono_set_pending_exception (mono_get_exception_argument_null ("obj"));
-               return FALSE;
-       }
-
        lw.sync = obj->synchronisation;
 
        if (G_LIKELY (lock_word_is_free (lw))) {
@@ -998,24 +1015,78 @@ mono_monitor_try_enter_internal (MonoObject *obj, guint32 ms, gboolean allow_int
        return -1;
 }
 
-gboolean 
+/* This is an icall */
+MonoBoolean
+mono_monitor_enter_internal (MonoObject *obj)
+{
+       gint32 res;
+       gboolean allow_interruption = TRUE;
+       if (G_UNLIKELY (!obj)) {
+               mono_set_pending_exception (mono_get_exception_argument_null ("obj"));
+               return FALSE;
+       }
+
+       /*
+        * An inquisitive mind could ask what's the deal with this loop.
+        * It exists to deal with interrupting a monitor enter that happened within an abort-protected block, like a .cctor.
+        *
+        * The thread will be set with a pending abort and the wait might even be interrupted. Either way, once we call mono_thread_interruption_checkpoint,
+        * it will return NULL meaning we can't be aborted right now. Once that happens we switch to non-alertable.
+        */
+       do {
+               res = mono_monitor_try_enter_internal (obj, MONO_INFINITE_WAIT, allow_interruption);
+               /*This means we got interrupted during the wait and didn't got the monitor.*/
+               if (res == -1) {
+                       MonoException *exc = mono_thread_interruption_checkpoint ();
+                       if (exc) {
+                               mono_set_pending_exception (exc);
+                               return FALSE;
+                       } else {
+                               //we detected a pending interruption but it turned out to be a false positive, we ignore it from now on (this feels like a hack, right?, threads.c should give us less confusing directions)
+                               allow_interruption = FALSE;
+                       }
+               }
+       } while (res == -1);
+       return TRUE;
+}
+
+/**
+ * mono_monitor_enter:
+ */
+gboolean
 mono_monitor_enter (MonoObject *obj)
 {
-       return mono_monitor_try_enter_internal (obj, INFINITE, FALSE) == 1;
+       return mono_monitor_enter_internal (obj);
 }
 
-gboolean 
+/* Called from JITted code so we return guint32 instead of gboolean */
+guint32
 mono_monitor_enter_fast (MonoObject *obj)
 {
+       if (G_UNLIKELY (!obj)) {
+               /* don't set pending exn on the fast path, just return
+                * FALSE and let the slow path take care of it. */
+               return FALSE;
+       }
        return mono_monitor_try_enter_internal (obj, 0, FALSE) == 1;
 }
 
+/**
+ * mono_monitor_try_enter:
+ */
 gboolean
 mono_monitor_try_enter (MonoObject *obj, guint32 ms)
 {
+       if (G_UNLIKELY (!obj)) {
+               mono_set_pending_exception (mono_get_exception_argument_null ("obj"));
+               return FALSE;
+       }
        return mono_monitor_try_enter_internal (obj, ms, FALSE) == 1;
 }
 
+/**
+ * mono_monitor_exit:
+ */
 void
 mono_monitor_exit (MonoObject *obj)
 {
@@ -1030,7 +1101,8 @@ mono_monitor_exit (MonoObject *obj)
 
        lw.sync = obj->synchronisation;
 
-       mono_monitor_ensure_owned (lw, mono_thread_info_get_small_id ());
+       if (!mono_monitor_ensure_owned (lw, mono_thread_info_get_small_id ()))
+               return;
 
        if (G_UNLIKELY (lock_word_is_inflated (lw)))
                mono_monitor_exit_inflated (obj);
@@ -1072,17 +1144,25 @@ mono_monitor_threads_sync_members_offset (int *status_offset, int *nest_offset)
 }
 
 void
-ves_icall_System_Threading_Monitor_Monitor_try_enter_with_atomic_var (MonoObject *obj, guint32 ms, char *lockTaken)
+ves_icall_System_Threading_Monitor_Monitor_try_enter_with_atomic_var (MonoObject *obj, guint32 ms, MonoBoolean *lockTaken)
 {
        gint32 res;
+       gboolean allow_interruption = TRUE;
+       if (G_UNLIKELY (!obj)) {
+               mono_set_pending_exception (mono_get_exception_argument_null ("obj"));
+               return;
+       }
        do {
-               res = mono_monitor_try_enter_internal (obj, ms, TRUE);
+               res = mono_monitor_try_enter_internal (obj, ms, allow_interruption);
                /*This means we got interrupted during the wait and didn't got the monitor.*/
                if (res == -1) {
                        MonoException *exc = mono_thread_interruption_checkpoint ();
                        if (exc) {
                                mono_set_pending_exception (exc);
                                return;
+                       } else {
+                               //we detected a pending interruption but it turned out to be a false positive, we ignore it from now on (this feels like a hack, right?, threads.c should give us less confusing directions)
+                               allow_interruption = FALSE;
                        }
                }
        } while (res == -1);
@@ -1090,6 +1170,9 @@ ves_icall_System_Threading_Monitor_Monitor_try_enter_with_atomic_var (MonoObject
        *lockTaken = res == 1;
 }
 
+/**
+ * mono_monitor_enter_v4:
+ */
 void
 mono_monitor_enter_v4 (MonoObject *obj, char *lock_taken)
 {
@@ -1098,7 +1181,22 @@ mono_monitor_enter_v4 (MonoObject *obj, char *lock_taken)
                return;
        }
 
-       ves_icall_System_Threading_Monitor_Monitor_try_enter_with_atomic_var (obj, INFINITE, lock_taken);
+       MonoBoolean taken;
+
+       ves_icall_System_Threading_Monitor_Monitor_try_enter_with_atomic_var (obj, MONO_INFINITE_WAIT, &taken);
+       *lock_taken = taken;
+}
+
+/* Called from JITted code */
+void
+mono_monitor_enter_v4_internal (MonoObject *obj, MonoBoolean *lock_taken)
+{
+       if (*lock_taken == 1) {
+               mono_set_pending_exception (mono_get_exception_argument ("lockTaken", "lockTaken is already true"));
+               return;
+       }
+
+       ves_icall_System_Threading_Monitor_Monitor_try_enter_with_atomic_var (obj, MONO_INFINITE_WAIT, lock_taken);
 }
 
 /*
@@ -1107,9 +1205,10 @@ mono_monitor_enter_v4 (MonoObject *obj, char *lock_taken)
  *   Same as mono_monitor_enter_v4, but return immediately if the
  * monitor cannot be acquired.
  * Returns TRUE if the lock was acquired, FALSE otherwise.
+ * Called from JITted code so we return guint32 instead of gboolean.
  */
-gboolean
-mono_monitor_enter_v4_fast (MonoObject *obj, char *lock_taken)
+guint32
+mono_monitor_enter_v4_fast (MonoObject *obj, MonoBoolean *lock_taken)
 {
        if (*lock_taken == 1)
                return FALSE;
@@ -1120,7 +1219,7 @@ mono_monitor_enter_v4_fast (MonoObject *obj, char *lock_taken)
        return res == 1;
 }
 
-gboolean 
+MonoBoolean
 ves_icall_System_Threading_Monitor_Monitor_test_owner (MonoObject *obj)
 {
        LockWord lw;
@@ -1138,7 +1237,7 @@ ves_icall_System_Threading_Monitor_Monitor_test_owner (MonoObject *obj)
        return(FALSE);
 }
 
-gboolean 
+MonoBoolean
 ves_icall_System_Threading_Monitor_Monitor_test_synchronised (MonoObject *obj)
 {
        LockWord lw;
@@ -1173,7 +1272,8 @@ ves_icall_System_Threading_Monitor_Monitor_pulse (MonoObject *obj)
        id = mono_thread_info_get_small_id ();
        lw.sync = obj->synchronisation;
 
-       mono_monitor_ensure_owned (lw, id);
+       if (!mono_monitor_ensure_owned (lw, id))
+               return;
 
        if (!lock_word_is_inflated (lw)) {
                /* No threads waiting. A wait would have inflated the lock */
@@ -1187,7 +1287,7 @@ ves_icall_System_Threading_Monitor_Monitor_pulse (MonoObject *obj)
        if (mon->wait_list != NULL) {
                LOCK_DEBUG (g_message ("%s: (%d) signalling and dequeuing handle %p", __func__, mono_thread_info_get_small_id (), mon->wait_list->data));
        
-               SetEvent (mon->wait_list->data);
+               mono_w32event_set (mon->wait_list->data);
                mon->wait_list = g_slist_remove (mon->wait_list, mon->wait_list->data);
        }
 }
@@ -1204,7 +1304,8 @@ ves_icall_System_Threading_Monitor_Monitor_pulse_all (MonoObject *obj)
        id = mono_thread_info_get_small_id ();
        lw.sync = obj->synchronisation;
 
-       mono_monitor_ensure_owned (lw, id);
+       if (!mono_monitor_ensure_owned (lw, id))
+               return;
 
        if (!lock_word_is_inflated (lw)) {
                /* No threads waiting. A wait would have inflated the lock */
@@ -1218,19 +1319,19 @@ ves_icall_System_Threading_Monitor_Monitor_pulse_all (MonoObject *obj)
        while (mon->wait_list != NULL) {
                LOCK_DEBUG (g_message ("%s: (%d) signalling and dequeuing handle %p", __func__, mono_thread_info_get_small_id (), mon->wait_list->data));
        
-               SetEvent (mon->wait_list->data);
+               mono_w32event_set (mon->wait_list->data);
                mon->wait_list = g_slist_remove (mon->wait_list, mon->wait_list->data);
        }
 }
 
-gboolean
+MonoBoolean
 ves_icall_System_Threading_Monitor_Monitor_wait (MonoObject *obj, guint32 ms)
 {
        LockWord lw;
        MonoThreadsSync *mon;
        HANDLE event;
        guint32 nest;
-       guint32 ret;
+       MonoW32HandleWaitRet ret;
        gboolean success = FALSE;
        gint32 regain;
        MonoInternalThread *thread = mono_thread_internal_current ();
@@ -1240,7 +1341,8 @@ ves_icall_System_Threading_Monitor_Monitor_wait (MonoObject *obj, guint32 ms)
 
        lw.sync = obj->synchronisation;
 
-       mono_monitor_ensure_owned (lw, id);
+       if (!mono_monitor_ensure_owned (lw, id))
+               return FALSE;
 
        if (!lock_word_is_inflated (lw)) {
                mono_monitor_inflate_owned (obj, id);
@@ -1253,7 +1355,7 @@ ves_icall_System_Threading_Monitor_Monitor_wait (MonoObject *obj, guint32 ms)
        if (mono_thread_current_check_pending_interrupt ())
                return FALSE;
        
-       event = CreateEvent (NULL, FALSE, FALSE, NULL);
+       event = mono_w32event_create (FALSE, FALSE);
        if (event == NULL) {
                mono_set_pending_exception (mono_get_exception_synchronization_lock ("Failed to set up wait event"));
                return FALSE;
@@ -1263,7 +1365,7 @@ ves_icall_System_Threading_Monitor_Monitor_wait (MonoObject *obj, guint32 ms)
 
        /* This looks superfluous */
        if (mono_thread_current_check_pending_interrupt ()) {
-               CloseHandle (event);
+               mono_w32event_close (event);
                return FALSE;
        }
        
@@ -1285,7 +1387,11 @@ ves_icall_System_Threading_Monitor_Monitor_wait (MonoObject *obj, guint32 ms)
         * signalled before we wait, we still succeed.
         */
        MONO_ENTER_GC_SAFE;
-       ret = WaitForSingleObjectEx (event, ms, TRUE);
+#ifdef HOST_WIN32
+       ret = mono_w32handle_convert_wait_ret (mono_win32_wait_for_single_object_ex (event, ms, TRUE), 1);
+#else
+       ret = mono_w32handle_wait_one (event, ms, TRUE);
+#endif /* HOST_WIN32 */
        MONO_EXIT_GC_SAFE;
 
        /* Reset the thread state fairly early, so we don't have to worry
@@ -1295,7 +1401,7 @@ ves_icall_System_Threading_Monitor_Monitor_wait (MonoObject *obj, guint32 ms)
 
        /* Regain the lock with the previous nest count */
        do {
-               regain = mono_monitor_try_enter_inflated (obj, INFINITE, TRUE, id);
+               regain = mono_monitor_try_enter_inflated (obj, MONO_INFINITE_WAIT, TRUE, id);
                /* We must regain the lock before handling interruption requests */
        } while (regain == -1);
 
@@ -1305,12 +1411,16 @@ ves_icall_System_Threading_Monitor_Monitor_wait (MonoObject *obj, guint32 ms)
 
        LOCK_DEBUG (g_message ("%s: (%d) Regained %p lock %p", __func__, mono_thread_info_get_small_id (), obj, mon));
 
-       if (ret == WAIT_TIMEOUT) {
+       if (ret == MONO_W32HANDLE_WAIT_RET_TIMEOUT) {
                /* Poll the event again, just in case it was signalled
                 * while we were trying to regain the monitor lock
                 */
                MONO_ENTER_GC_SAFE;
-               ret = WaitForSingleObjectEx (event, 0, FALSE);
+#ifdef HOST_WIN32
+               ret = mono_w32handle_convert_wait_ret (mono_win32_wait_for_single_object_ex (event, 0, FALSE), 1);
+#else
+               ret = mono_w32handle_wait_one (event, 0, FALSE);
+#endif /* HOST_WIN32 */
                MONO_EXIT_GC_SAFE;
        }
 
@@ -1324,7 +1434,7 @@ ves_icall_System_Threading_Monitor_Monitor_wait (MonoObject *obj, guint32 ms)
         * thread.
         */
        
-       if (ret == WAIT_OBJECT_0) {
+       if (ret == MONO_W32HANDLE_WAIT_RET_SUCCESS_0) {
                LOCK_DEBUG (g_message ("%s: (%d) Success", __func__, mono_thread_info_get_small_id ()));
                success = TRUE;
        } else {
@@ -1334,7 +1444,7 @@ ves_icall_System_Threading_Monitor_Monitor_wait (MonoObject *obj, guint32 ms)
                 */
                mon->wait_list = g_slist_remove (mon->wait_list, event);
        }
-       CloseHandle (event);
+       mono_w32event_close (event);
        
        return success;
 }