Fix sporadic hang in Mono.Debugger.Soft test suite on Windows.
authorlateralusX <lateralusx.github@gmail.com>
Wed, 23 Aug 2017 08:38:56 +0000 (10:38 +0200)
committerlateralusX <lateralusx.github@gmail.com>
Mon, 25 Sep 2017 13:41:32 +0000 (15:41 +0200)
Mono.Debugger.Soft has low frequency hangs in InspectThreadSuspenedOnWaitOne test.
This method launch the debuggee (dtest-app.exe), sets a breakpoint on a method just
doing an infinite OS wait, validate that the breakpoint gets hit and resumes debuggee.
After resume from breakpoint debuggee will hit the infinite OS wait and the debugger test
will suspend and shutdown the process.

In order for mono debugger to handle the shutdown request it will suspend all managed threads
using mono_thread_suspend_all_other_threads. This method uses a pooling schema until all threads
have reported that they are suspended. Since one of the threads are doing an infinite OS wait we
entered the land of APC (Asynchron Procedure Calls) used on Windows to alert waitable threads.

The reason for the hang is the fact that the OS won’t return from the wait until all queued APC’s
have been executed. Since the loop sending async suspend requests to the
threads mono_thread_suspend_all_other_threads can run faster (including suspending/resuming the
thread that need to consume APC’s in the process) then the dequeue and execute of the queued APC’s, the
wait won’t break, meaning that the thread won’t be able to set the mono suspend state causing the
mono_thread_suspend_all_other_threads to run forever. This is highly timing dependent and will only reproduce
sporadic, but I was able to isolate and do a solid repro locally while working on the fix.

The fix makes sure we don’t post a new suspend APC if there is already one in flight with a pending unhandled
interruption. This will make sure we won’t flood the APC queue on Windows preventing the thread from suspending.

14 files changed:
mono/metadata/gc.c
mono/metadata/monitor.c
mono/metadata/threadpool.c
mono/metadata/threads.c
mono/metadata/w32socket-win32.c
mono/utils/Makefile.am
mono/utils/mono-os-semaphore.h
mono/utils/mono-os-wait-win32.c [new file with mode: 0644]
mono/utils/mono-os-wait.h [new file with mode: 0644]
mono/utils/mono-threads-windows.c
mono/utils/mono-threads.h
mono/utils/os-event-win32.c
msvc/libmonoutils.vcxproj
msvc/libmonoutils.vcxproj.filters

index 80605dba2d0d7f4aff7090ebf2e60aefb53704a0..702857858eb25c4d50ca5485e92d32a91c37cd28 100644 (file)
@@ -45,6 +45,7 @@
 #include <mono/utils/hazard-pointer.h>
 #include <mono/utils/w32api.h>
 #include <mono/utils/unlocked.h>
+#include <mono/utils/mono-os-wait.h>
 
 #ifndef HOST_WIN32
 #include <pthread.h>
@@ -598,7 +599,7 @@ ves_icall_System_GC_WaitForPendingFinalizers (void)
        mono_gc_finalize_notify ();
        /* g_print ("Waiting for pending finalizers....\n"); */
        MONO_ENTER_GC_SAFE;
-       WaitForSingleObjectEx (pending_done_event, INFINITE, TRUE);
+       mono_win32_wait_for_single_object_ex (pending_done_event, INFINITE, TRUE);
        MONO_EXIT_GC_SAFE;
        /* g_print ("Done pending....\n"); */
 #else
index c371f0f3c476c0e6756c97460e5c37e9cd3e1bc5..d3b51abfc80247f536fdb2410f28edf528411200 100644 (file)
@@ -32,6 +32,7 @@
 #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
@@ -1387,7 +1388,7 @@ ves_icall_System_Threading_Monitor_Monitor_wait (MonoObject *obj, guint32 ms)
         */
        MONO_ENTER_GC_SAFE;
 #ifdef HOST_WIN32
-       ret = mono_w32handle_convert_wait_ret (WaitForSingleObjectEx (event, ms, TRUE), 1);
+       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 */
@@ -1416,7 +1417,7 @@ ves_icall_System_Threading_Monitor_Monitor_wait (MonoObject *obj, guint32 ms)
                 */
                MONO_ENTER_GC_SAFE;
 #ifdef HOST_WIN32
-               ret = mono_w32handle_convert_wait_ret (WaitForSingleObjectEx (event, 0, FALSE), 1);
+               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 */
index 1c8c1f401a8fb0a49c3f0cdb8b9f1abeeedeeda4..a1424beaebaea483723c7cda7050bed4182730f6 100644 (file)
@@ -46,6 +46,7 @@
 #include <mono/utils/mono-threads.h>
 #include <mono/utils/mono-time.h>
 #include <mono/utils/refcount.h>
+#include <mono/utils/mono-os-wait.h>
 
 typedef struct {
        MonoDomain *domain;
@@ -495,7 +496,7 @@ mono_threadpool_end_invoke (MonoAsyncResult *ares, MonoArray **out_args, MonoObj
                mono_monitor_exit ((MonoObject*) ares);
                MONO_ENTER_GC_SAFE;
 #ifdef HOST_WIN32
-               WaitForSingleObjectEx (wait_event, INFINITE, TRUE);
+               mono_win32_wait_for_single_object_ex (wait_event, INFINITE, TRUE);
 #else
                mono_w32handle_wait_one (wait_event, MONO_INFINITE_WAIT, TRUE);
 #endif
index 52dc0c0c23001fa962b2fe7e74dd8afe53a5de48..cc4705c813336a8dfb7d1936d43f1324267aba4c 100644 (file)
@@ -54,6 +54,7 @@
 #include <mono/metadata/abi-details.h>
 #include <mono/metadata/w32error.h>
 #include <mono/utils/w32api.h>
+#include <mono/utils/mono-os-wait.h>
 
 #ifdef HAVE_SIGNAL_H
 #include <signal.h>
@@ -1904,9 +1905,9 @@ ves_icall_System_Threading_WaitHandle_Wait_internal (gpointer *handles, gint32 n
                MONO_ENTER_GC_SAFE;
 #ifdef HOST_WIN32
                if (numhandles != 1)
-                       ret = mono_w32handle_convert_wait_ret (WaitForMultipleObjectsEx (numhandles, handles, waitall, timeoutLeft, TRUE), numhandles);
+                       ret = mono_w32handle_convert_wait_ret (mono_win32_wait_for_multiple_objects_ex(numhandles, handles, waitall, timeoutLeft, TRUE), numhandles);
                else
-                       ret = mono_w32handle_convert_wait_ret (WaitForSingleObjectEx (handles [0], timeoutLeft, TRUE), 1);
+                       ret = mono_w32handle_convert_wait_ret (mono_win32_wait_for_single_object_ex (handles [0], timeoutLeft, TRUE), 1);
 #else
                /* mono_w32handle_wait_multiple optimizes the case for numhandles == 1 */
                ret = mono_w32handle_wait_multiple (handles, numhandles, waitall, timeoutLeft, TRUE);
@@ -1956,7 +1957,7 @@ ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (gpointer toSignal,
        
        MONO_ENTER_GC_SAFE;
 #ifdef HOST_WIN32
-       ret = mono_w32handle_convert_wait_ret (SignalObjectAndWait (toSignal, toWait, ms, TRUE), 1);
+       ret = mono_w32handle_convert_wait_ret (mono_win32_signal_object_and_wait (toSignal, toWait, ms, TRUE), 1);
 #else
        ret = mono_w32handle_signal_and_wait (toSignal, toWait, ms, TRUE);
 #endif
@@ -4454,9 +4455,10 @@ mono_thread_execute_interruption (void)
        }
 
        /* this will consume pending APC calls */
-#ifdef HOST_WIN32
-       WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
+#ifdef USE_WINDOWS_BACKEND
+       mono_win32_wait_for_single_object_ex (GetCurrentThread (), 0, TRUE);
 #endif
+
        /* Clear the interrupted flag of the thread so it can wait again */
        mono_thread_info_clear_self_interrupt ();
 
@@ -4524,9 +4526,8 @@ mono_thread_request_interruption (gboolean running_managed)
 
                /* this will awake the thread if it is in WaitForSingleObject 
                   or similar */
-               /* Our implementation of this function ignores the func argument */
-#ifdef HOST_WIN32
-               QueueUserAPC ((PAPCFUNC)dummy_apc, thread->native_handle, (ULONG_PTR)NULL);
+#ifdef USE_WINDOWS_BACKEND
+               mono_win32_interrupt_wait (thread->thread_info, thread->native_handle, (DWORD)thread->tid);
 #else
                mono_thread_info_self_interrupt ();
 #endif
index 4f7cc8cdcf555f28ffbf37a6a7c6807192bdeaf6..076500687baeea45d32e1f247532c8a83b43e684 100644 (file)
@@ -23,6 +23,7 @@
 #include "w32socket-internals.h"
 
 #include "utils/w32api.h"
+#include "utils/mono-os-wait.h"
 
 #define LOGDEBUG(...)  
 
@@ -76,10 +77,10 @@ static gboolean alertable_socket_wait (SOCKET sock, int event_bit)
        WSAEVENT event = WSACreateEvent ();
        if (event != WSA_INVALID_EVENT) {
                if (WSAEventSelect (sock, event, (1 << event_bit) | FD_CLOSE) != SOCKET_ERROR) {
-                       LOGDEBUG (g_message ("%06d - Calling WSAWaitForMultipleEvents () on socket %d", GetCurrentThreadId (), sock));
-                       DWORD ret = WSAWaitForMultipleEvents (1, &event, TRUE, timeout, TRUE);
+                       LOGDEBUG (g_message ("%06d - Calling mono_win32_wsa_wait_for_multiple_events () on socket %d", GetCurrentThreadId (), sock));
+                       DWORD ret = mono_win32_wsa_wait_for_multiple_events (1, &event, TRUE, timeout, TRUE);
                        if (ret == WSA_WAIT_IO_COMPLETION) {
-                               LOGDEBUG (g_message ("%06d - WSAWaitForMultipleEvents () returned WSA_WAIT_IO_COMPLETION for socket %d", GetCurrentThreadId (), sock));
+                               LOGDEBUG (g_message ("%06d - mono_win32_wsa_wait_for_multiple_events () returned WSA_WAIT_IO_COMPLETION for socket %d", GetCurrentThreadId (), sock));
                                error = WSAEINTR;
                        } else if (ret == WSA_WAIT_TIMEOUT) {
                                error = WSAETIMEDOUT;
@@ -229,9 +230,9 @@ BOOL mono_w32socket_transmit_file (SOCKET hSocket, gpointer hFile, TRANSMIT_FILE
                        if (error == WSA_IO_PENDING) {
                                error = 0;
                                // NOTE: .NET's Socket.SendFile() doesn't honor the Socket's SendTimeout so we shouldn't either
-                               DWORD ret = WaitForSingleObjectEx (overlapped.hEvent, INFINITE, TRUE);
+                               DWORD ret = mono_win32_wait_for_single_object_ex (overlapped.hEvent, INFINITE, TRUE);
                                if (ret == WAIT_IO_COMPLETION) {
-                                       LOGDEBUG (g_message ("%06d - WaitForSingleObjectEx () returned WSA_WAIT_IO_COMPLETION for socket %d", GetCurrentThreadId (), hSocket));
+                                       LOGDEBUG (g_message ("%06d - mono_win32_wait_for_single_object_ex () returned WSA_WAIT_IO_COMPLETION for socket %d", GetCurrentThreadId (), hSocket));
                                        error = WSAEINTR;
                                } else if (ret == WAIT_TIMEOUT) {
                                        error = WSAETIMEDOUT;
index 118ab953d0e8bcc172995e3e797a268899737113..119d7c94c2cce1c8e2427211a53467708fc0eeb4 100644 (file)
@@ -13,7 +13,8 @@ endif
 
 if HOST_WIN32
 win32_sources = \
-       os-event-win32.c
+       os-event-win32.c \
+       mono-os-wait-win32.c
 
 platform_sources = $(win32_sources)
 else
@@ -61,6 +62,7 @@ monoutils_sources = \
        mono-mmap-windows-internals.h   \
        mono-os-mutex.h         \
        mono-os-mutex.c         \
+       mono-os-wait.h \
        mono-coop-mutex.h               \
        mono-once.h             \
        mono-lazy-init.h                \
index f766529201e3426bf1349b2f3020ad39d9a54932..0f8984ef9d9d2ef19f7a371feeb0726799351f0f 100644 (file)
@@ -31,8 +31,7 @@
 #elif !defined(HOST_WIN32) && defined(HAVE_SEMAPHORE_H)
 #include <semaphore.h>
 #else
-#include <winsock2.h>
-#include <windows.h>
+#include <mono/utils/mono-os-wait.h>
 #endif
 
 #define MONO_HAS_SEMAPHORES 1
@@ -318,9 +317,9 @@ mono_os_sem_timedwait (MonoSemType *sem, guint32 timeout_ms, MonoSemFlags flags)
        BOOL res;
 
 retry:
-       res = WaitForSingleObjectEx (*sem, timeout_ms, flags & MONO_SEM_FLAGS_ALERTABLE);
+       res = mono_win32_wait_for_single_object_ex (*sem, timeout_ms, flags & MONO_SEM_FLAGS_ALERTABLE);
        if (G_UNLIKELY (res != WAIT_OBJECT_0 && res != WAIT_IO_COMPLETION && res != WAIT_TIMEOUT))
-               g_error ("%s: WaitForSingleObjectEx failed with error %d", __func__, GetLastError ());
+               g_error ("%s: mono_win32_wait_for_single_object_ex failed with error %d", __func__, GetLastError ());
 
        if (res == WAIT_IO_COMPLETION && !(flags & MONO_SEM_FLAGS_ALERTABLE))
                goto retry;
diff --git a/mono/utils/mono-os-wait-win32.c b/mono/utils/mono-os-wait-win32.c
new file mode 100644 (file)
index 0000000..5d18a71
--- /dev/null
@@ -0,0 +1,210 @@
+#include <mono/utils/mono-os-wait.h>
+#include <mono/utils/mono-threads.h>
+#include <mono/utils/mono-threads-debug.h>
+
+#define THREAD_WAIT_INFO_CLEARED 0
+#define THREAD_WAIT_INFO_ALERTABLE_WAIT_SLOT 1
+#define THREAD_WAIT_INFO_PENDING_INTERRUPT_APC_SLOT 2
+#define THREAD_WAIT_INFO_PENDING_ABORT_APC_SLOT 4
+
+static inline void
+reqeust_interrupt (gpointer thread_info, HANDLE native_thread_handle, gint32 pending_apc_slot, PAPCFUNC apc_callback, DWORD tid)
+{
+       /*
+       * On Windows platforms the async interrupt/abort requests might need to process
+       * APC on target thread before the thread can return back from OS wait calls
+       * and complete the mono interrupt/abort request. In such cases, just keep on
+       * queuing APC over again again will flood the APC queue preventing the target thread
+       * to return from it's alertable OS wait call. This check makes sure not to issue an APC
+       * as long as there is a pending requests in requested APC slot for the targeted thread.
+       * NOTE, this code will executed regardless if thread is currently in an alertable wait or not.
+       * This is done to prevent races between interrupt/abort occurring just before thread enters an
+       * alertable wait. Threads entering waits already need to handle WAIT_IO_COMPLETION scenarios and
+       * if that happens due to a previous pending interrupt/abort APC, the calling thread should already
+       * have logic to restart the alertable wait operation.
+       */
+       MonoThreadInfo *info = (MonoThreadInfo *)thread_info;
+       gboolean queue_apc = FALSE;
+
+       while (!queue_apc) {
+               gint32 old_wait_info = InterlockedRead (&info->thread_wait_info);
+               if (old_wait_info & pending_apc_slot)
+                       break;
+
+               gint32 new_wait_info = old_wait_info | pending_apc_slot;
+               if (InterlockedCompareExchange (&info->thread_wait_info, new_wait_info, old_wait_info) == old_wait_info) {
+                       queue_apc = TRUE;
+               }
+       }
+
+       if (queue_apc == TRUE) {
+               THREADS_INTERRUPT_DEBUG ("%06d - Interrupting/Aborting syscall in thread %06d", GetCurrentThreadId (), tid);
+               QueueUserAPC (apc_callback, native_thread_handle, (ULONG_PTR)NULL);
+       }
+}
+
+static void CALLBACK
+interrupt_apc (ULONG_PTR param)
+{
+       THREADS_INTERRUPT_DEBUG ("%06d - interrupt_apc () called", GetCurrentThreadId ());
+}
+
+void
+mono_win32_interrupt_wait (PVOID thread_info, HANDLE native_thread_handle, DWORD tid)
+{
+       reqeust_interrupt (thread_info, native_thread_handle, THREAD_WAIT_INFO_PENDING_INTERRUPT_APC_SLOT, interrupt_apc, tid);
+}
+
+static void CALLBACK
+abort_apc (ULONG_PTR param)
+{
+       THREADS_INTERRUPT_DEBUG ("%06d - abort_apc () called", GetCurrentThreadId ());
+}
+
+void
+mono_win32_abort_wait (PVOID thread_info, HANDLE native_thread_handle, DWORD tid)
+{
+       reqeust_interrupt (thread_info, native_thread_handle, THREAD_WAIT_INFO_PENDING_ABORT_APC_SLOT, abort_apc, tid);
+}
+
+static inline void
+enter_alertable_wait (MonoThreadInfo *info)
+{
+       // Clear any previous flags. Set alertable wait flag.
+       InterlockedExchange (&info->thread_wait_info, THREAD_WAIT_INFO_ALERTABLE_WAIT_SLOT);
+}
+
+static inline void
+leave_alertable_wait (MonoThreadInfo *info)
+{
+       // Clear any previous flags. Thread is exiting alertable wait state, and info around pending interrupt/abort APC's
+       // can now be discarded as well, thread is out of wait operation and can proceed it's execution.
+       InterlockedExchange (&info->thread_wait_info, THREAD_WAIT_INFO_CLEARED);
+}
+
+DWORD
+mono_win32_sleep_ex (DWORD timeout, BOOL alertable)
+{
+       DWORD result = WAIT_FAILED;
+       MonoThreadInfo *info = mono_thread_info_current_unchecked ();
+
+       if (alertable && info) {
+               enter_alertable_wait (info);
+       }
+
+       result = SleepEx (timeout, alertable);
+
+       // NOTE, leave_alertable_wait should not affect GetLastError but
+       // if changed, last error need to be preserved and reset before returning.
+       if (alertable && info) {
+               leave_alertable_wait (info);
+       }
+
+       return result;
+}
+
+DWORD
+mono_win32_wait_for_single_object_ex (HANDLE handle, DWORD timeout, BOOL alertable)
+{
+       DWORD result = WAIT_FAILED;
+       MonoThreadInfo *info = mono_thread_info_current_unchecked ();
+
+       if (alertable && info) {
+               enter_alertable_wait (info);
+       }
+
+       result = WaitForSingleObjectEx (handle, timeout, alertable);
+
+       // NOTE, leave_alertable_wait should not affect GetLastError but
+       // if changed, last error need to be preserved and reset before returning.
+       if (alertable && info) {
+               leave_alertable_wait (info);
+       }
+
+       return result;
+}
+
+DWORD
+mono_win32_wait_for_multiple_objects_ex (DWORD count, CONST HANDLE *handles, BOOL waitAll, DWORD timeout, BOOL alertable)
+{
+       DWORD result = WAIT_FAILED;
+       MonoThreadInfo *info = mono_thread_info_current_unchecked ();
+
+       if (alertable && info) {
+               enter_alertable_wait (info);
+       }
+
+       result = WaitForMultipleObjectsEx (count, handles, waitAll, timeout, alertable);
+
+       // NOTE, leave_alertable_wait should not affect GetLastError but
+       // if changed, last error need to be preserved and reset before returning.
+       if (alertable && info) {
+               leave_alertable_wait (info);
+       }
+
+       return result;
+}
+
+DWORD
+mono_win32_signal_object_and_wait (HANDLE toSignal, HANDLE toWait, DWORD timeout, BOOL alertable)
+{
+       DWORD result = WAIT_FAILED;
+       MonoThreadInfo *info = mono_thread_info_current_unchecked ();
+
+       if (alertable && info) {
+               enter_alertable_wait (info);
+       }
+
+       result = SignalObjectAndWait (toSignal, towlower, timeout, alertable);
+
+       // NOTE, leave_alertable_wait should not affect GetLastError but
+       // if changed, last error need to be preserved and reset before returning.
+       if (alertable && info) {
+               leave_alertable_wait (info);
+       }
+
+       return result;
+}
+
+DWORD
+mono_win32_msg_wait_for_multiple_objects_ex (DWORD count, CONST HANDLE *handles, DWORD timeout, DWORD wakeMask, DWORD flags)
+{
+       DWORD result = WAIT_FAILED;
+       MonoThreadInfo *info = mono_thread_info_current_unchecked ();
+       BOOL alertable = flags & MWMO_ALERTABLE;
+
+       if (alertable && info) {
+               enter_alertable_wait (info);
+       }
+
+       result = MsgWaitForMultipleObjectsEx (count, handles, timeout, wakeMask, flags);
+
+       // NOTE, leave_alertable_wait should not affect GetLastError but
+       // if changed, last error need to be preserved and reset before returning.
+       if (alertable && info) {
+               leave_alertable_wait (info);
+       }
+
+       return result;
+}
+
+DWORD
+mono_win32_wsa_wait_for_multiple_events (DWORD count, const WSAEVENT FAR *handles, BOOL waitAll, DWORD timeout, BOOL alertable)
+{
+       DWORD result = WAIT_FAILED;
+       MonoThreadInfo *info = mono_thread_info_current_unchecked ();
+
+       if (alertable && info) {
+               enter_alertable_wait (info);
+       }
+
+       result = WSAWaitForMultipleEvents (count, handles, waitAll, timeout, alertable);
+
+       // NOTE, leave_alertable_wait should not affect GetLastError but
+       // if changed, last error need to be preserved and reset before returning.
+       if (alertable && info) {
+               leave_alertable_wait (info);
+       }
+
+       return result;
+}
diff --git a/mono/utils/mono-os-wait.h b/mono/utils/mono-os-wait.h
new file mode 100644 (file)
index 0000000..29e86c7
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef _MONO_UTILS_OS_WAIT_H_
+#define _MONO_UTILS_OS_WAIT_H_
+
+#include <config.h>
+#ifdef HOST_WIN32
+
+#include <winsock2.h>
+#include <windows.h>
+
+DWORD
+mono_win32_sleep_ex (DWORD timeout, BOOL alertable);
+
+DWORD
+mono_win32_wait_for_single_object_ex (HANDLE handle, DWORD timeout, BOOL alertable);
+
+DWORD
+mono_win32_wait_for_multiple_objects_ex (DWORD count, CONST HANDLE *handles, BOOL waitAll, DWORD timeout, BOOL alertable);
+
+DWORD
+mono_win32_signal_object_and_wait (HANDLE toSignal, HANDLE toWait, DWORD timeout, BOOL alertable);
+
+DWORD
+mono_win32_msg_wait_for_multiple_objects_ex (DWORD count, CONST HANDLE *handles, DWORD timeout, DWORD wakeMask, DWORD flags);
+
+DWORD
+mono_win32_wsa_wait_for_multiple_events (DWORD count, const WSAEVENT FAR *handles, BOOL waitAll, DWORD timeout, BOOL alertable);
+
+void
+mono_win32_interrupt_wait (PVOID thread_info, HANDLE native_thread_handle, DWORD tid);
+
+void
+mono_win32_abort_wait (PVOID thread_info, HANDLE native_thread_handle, DWORD tid);
+
+#endif
+
+#endif /* _MONO_UTILS_OS_WAIT_H_ */
index 9ef565ddf9107934b6c77054a3ecc44f5ad2dcb2..c20cefd5cdf9b8bc367ba728166bed88bd504de2 100644 (file)
 
 #include <mono/utils/mono-compiler.h>
 #include <mono/utils/mono-threads-debug.h>
+#include <mono/utils/mono-os-wait.h>
 #include <limits.h>
 
-
 void
 mono_threads_suspend_init (void)
 {
 }
 
-static void CALLBACK
-interrupt_apc (ULONG_PTR param)
-{
-}
-
 gboolean
 mono_threads_suspend_begin_async_suspend (MonoThreadInfo *info, gboolean interrupt_kernel)
 {
@@ -57,9 +52,8 @@ mono_threads_suspend_begin_async_suspend (MonoThreadInfo *info, gboolean interru
        info->suspend_can_continue = mono_threads_get_runtime_callbacks ()->thread_state_init_from_handle (&info->thread_saved_state [ASYNC_SUSPEND_STATE_INDEX], info);
        THREADS_SUSPEND_DEBUG ("thread state %p -> %d\n", (void*)id, res);
        if (info->suspend_can_continue) {
-               //FIXME do we need to QueueUserAPC on this case?
                if (interrupt_kernel)
-                       QueueUserAPC ((PAPCFUNC)interrupt_apc, handle, (ULONG_PTR)NULL);
+                       mono_win32_interrupt_wait (info, handle, id);
        } else {
                THREADS_SUSPEND_DEBUG ("FAILSAFE RESUME/2 %p -> %d\n", (void*)info->native_handle, 0);
        }
@@ -74,11 +68,7 @@ mono_threads_suspend_check_suspend_result (MonoThreadInfo *info)
        return info->suspend_can_continue;
 }
 
-static void CALLBACK
-abort_apc (ULONG_PTR param)
-{
-       THREADS_INTERRUPT_DEBUG ("%06d - abort_apc () called", GetCurrentThreadId ());
-}
+
 
 void
 mono_threads_suspend_abort_syscall (MonoThreadInfo *info)
@@ -89,8 +79,7 @@ mono_threads_suspend_abort_syscall (MonoThreadInfo *info)
        handle = OpenThread (THREAD_ALL_ACCESS, FALSE, id);
        g_assert (handle);
 
-       THREADS_INTERRUPT_DEBUG ("%06d - Aborting syscall in thread %06d", GetCurrentThreadId (), id);
-       QueueUserAPC ((PAPCFUNC)abort_apc, handle, (ULONG_PTR)NULL);
+       mono_win32_abort_wait (info, handle, id);
 
        CloseHandle (handle);
 }
index b95784fa6fd9ebeb5d69a5f94eba78e658ad4809..be2f8264c71e3da8d38f6f730b5504560249132c 100644 (file)
@@ -230,6 +230,11 @@ typedef struct {
         * handled a sampling signal before sending another one.
         */
        gint32 profiler_signal_ack;
+
+#ifdef USE_WINDOWS_BACKEND
+       gint32 thread_wait_info;
+#endif
+
 } MonoThreadInfo;
 
 typedef struct {
index b63ec21a28f1a424f21ac6f1a8525a17395041ba..095669a0e4aebea91650beee4833ef795d97c8ca 100644 (file)
@@ -14,6 +14,7 @@
 #include <winbase.h>
 
 #include "atomic.h"
+#include "mono-os-wait.h"
 
 void
 mono_os_event_init (MonoOSEvent *event, gboolean initial)
@@ -72,7 +73,7 @@ mono_os_event_wait_one (MonoOSEvent *event, guint32 timeout, gboolean alertable)
        g_assert (event);
        g_assert (event->handle);
 
-       res = WaitForSingleObjectEx (event->handle, timeout, alertable);
+       res = mono_win32_wait_for_single_object_ex (event->handle, timeout, alertable);
        if (res == WAIT_OBJECT_0)
                return MONO_OS_EVENT_WAIT_RET_SUCCESS_0;
        else if (res == WAIT_IO_COMPLETION)
@@ -80,7 +81,7 @@ mono_os_event_wait_one (MonoOSEvent *event, guint32 timeout, gboolean alertable)
        else if (res == WAIT_TIMEOUT)
                return MONO_OS_EVENT_WAIT_RET_TIMEOUT;
        else if (res == WAIT_FAILED)
-               g_error ("%s: WaitForSingleObjectEx failed with error %d", __func__, GetLastError ());
+               g_error ("%s: mono_thread_win32_wait_one_handle failed with error %d", __func__, GetLastError ());
        else
                g_error ("%s: unknown res value %d", __func__, res);
 }
@@ -105,7 +106,7 @@ mono_os_event_wait_multiple (MonoOSEvent **events, gsize nevents, gboolean waita
                handles [i] = events [i]->handle;
        }
 
-       res = WaitForMultipleObjectsEx (nevents, handles, waitall, timeout, alertable);
+       res = mono_win32_wait_for_multiple_objects_ex ((DWORD)nevents, handles, waitall, timeout, alertable);
        if (res >= WAIT_OBJECT_0 && res < WAIT_OBJECT_0 + MONO_OS_EVENT_WAIT_MAXIMUM_OBJECTS)
                return MONO_OS_EVENT_WAIT_RET_SUCCESS_0 + (res - WAIT_OBJECT_0);
        else if (res == WAIT_IO_COMPLETION)
@@ -113,7 +114,7 @@ mono_os_event_wait_multiple (MonoOSEvent **events, gsize nevents, gboolean waita
        else if (res == WAIT_TIMEOUT)
                return MONO_OS_EVENT_WAIT_RET_TIMEOUT;
        else if (res == WAIT_FAILED)
-               g_error ("%s: WaitForSingleObjectEx failed with error %d", __func__, GetLastError ());
+               g_error ("%s: mono_thread_win32_wait_multiple_handle failed with error %d", __func__, GetLastError ());
        else
                g_error ("%s: unknown res value %d", __func__, res);
 }
index 350a54654e475e39aa163f1c125cbaff0c19b47b..beba4278b8e64cf515143a124e9b3f5b39c13b94 100644 (file)
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>\r
+<?xml version="1.0" encoding="utf-8"?>\r
 <Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
   <ItemGroup Label="ProjectConfigurations">\r
     <ProjectConfiguration Include="Debug|Win32">\r
@@ -68,6 +68,7 @@
     <ClCompile Include="..\mono\utils\mono-mmap-windows.c" />\r
     <ClCompile Include="..\mono\utils\mono-mmap.c" />\r
     <ClCompile Include="..\mono\utils\mono-networkinterfaces.c" />\r
+    <ClCompile Include="..\mono\utils\mono-os-wait-win32.c" />\r
     <ClCompile Include="..\mono\utils\mono-proclib-windows.c" />\r
     <ClCompile Include="..\mono\utils\mono-rand-windows.c" />\r
     <ClCompile Include="..\mono\utils\mono-rand.c" />\r
     <ClInclude Include="..\mono\utils\mono-once.h" />\r
     <ClInclude Include="..\mono\utils\mono-os-mutex.h" />\r
     <ClInclude Include="..\mono\utils\mono-os-semaphore.h" />\r
+    <ClInclude Include="..\mono\utils\mono-os-wait.h" />\r
     <ClInclude Include="..\mono\utils\mono-path.h" />\r
     <ClInclude Include="..\mono\utils\mono-poll.h" />\r
     <ClInclude Include="..\mono\utils\mono-proclib-windows-internals.h" />\r
     <ClInclude Include="..\mono\utils\strenc.h" />\r
     <ClInclude Include="..\mono\utils\valgrind.h" />\r
     <ClInclude Include="..\mono\utils\atomic.h" />\r
-    <ClInclude Include="..\mono\utils\unlocked.h" />
+    <ClInclude Include="..\mono\utils\unlocked.h" />\r
     <ClInclude Include="..\mono\utils\mono-hwcap.h" />\r
     <ClInclude Include="..\mono\utils\mono-hwcap-x86.h" />\r
     <ClInclude Include="..\mono\utils\bsearch.h" />\r
index a8b85cafce86e1c03fcf45ec014d136d12f7a423..e4b82690a1821a115451b8f47e75ab4f9aecaa44 100644 (file)
     <ClCompile Include="..\mono\utils\mono-os-mutex.c">\r
       <Filter>Source Files</Filter>\r
     </ClCompile>\r
+    <ClCompile Include="..\mono\utils\mono-os-wait-win32.c">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
   </ItemGroup>\r
   <ItemGroup>\r
     <ClInclude Include="..\mono\utils\atomic.h">\r
     <ClInclude Include="..\mono\utils\os-event.h">\r
       <Filter>Header Files</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\mono\utils\unlocked.h">
-      <Filter>Header Files</Filter>
-    </ClInclude>
+    <ClInclude Include="..\mono\utils\unlocked.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\mono\utils\mono-os-wait.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
   </ItemGroup>\r
   <ItemGroup>\r
     <Filter Include="Header Files">\r