Merge pull request #5714 from alexischr/update_bockbuild
[mono.git] / mono / utils / mono-threads-windows.c
index 97f75f0db1e5544155933bf8846256723c9f8b36..563d210e8ed5cfe9ef657e7aba24d77d0f0429cf 100644 (file)
@@ -1,5 +1,6 @@
-/*
- * mono-threads-windows.c: Low-level threading, windows version
+/**
+ * \file
+ * Low-level threading, windows version
  *
  * Author:
  *     Rodrigo Kumpera (kumpera@gmail.com)
 #if defined(USE_WINDOWS_BACKEND)
 
 #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)
 {
@@ -55,15 +52,14 @@ 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);
        }
 
        CloseHandle (handle);
-       return info->suspend_can_continue;
+       return TRUE;
 }
 
 gboolean
@@ -72,6 +68,22 @@ mono_threads_suspend_check_suspend_result (MonoThreadInfo *info)
        return info->suspend_can_continue;
 }
 
+
+
+void
+mono_threads_suspend_abort_syscall (MonoThreadInfo *info)
+{
+       DWORD id = mono_thread_info_get_tid (info);
+       HANDLE handle;
+
+       handle = OpenThread (THREAD_ALL_ACCESS, FALSE, id);
+       g_assert (handle);
+
+       mono_win32_abort_wait (info, handle, id);
+
+       CloseHandle (handle);
+}
+
 gboolean
 mono_threads_suspend_begin_async_resume (MonoThreadInfo *info)
 {
@@ -128,104 +140,63 @@ mono_threads_suspend_free (MonoThreadInfo *info)
 {
 }
 
-#endif
-
-#if defined (HOST_WIN32)
-
 void
-mono_threads_platform_register (MonoThreadInfo *info)
+mono_threads_suspend_init_signals (void)
 {
-       HANDLE thread_handle;
-
-       thread_handle = GetCurrentThread ();
-       g_assert (thread_handle);
+}
 
-       /* The handle returned by GetCurrentThread () is a pseudo handle, so it can't
-        * be used to refer to the thread from other threads for things like aborting. */
-       DuplicateHandle (GetCurrentProcess (), thread_handle, GetCurrentProcess (), &thread_handle, THREAD_ALL_ACCESS, TRUE, 0);
+gint
+mono_threads_suspend_search_alternative_signal (void)
+{
+       g_assert_not_reached ();
+}
 
-       g_assert (!info->handle);
-       info->handle = thread_handle;
+gint
+mono_threads_suspend_get_suspend_signal (void)
+{
+       return -1;
 }
 
-typedef struct {
-       LPTHREAD_START_ROUTINE start_routine;
-       void *arg;
-       gint32 priority;
-       MonoCoopSem registered;
-       gboolean suspend;
-       HANDLE handle;
-} ThreadStartInfo;
+gint
+mono_threads_suspend_get_restart_signal (void)
+{
+       return -1;
+}
 
-static DWORD WINAPI
-inner_start_thread (LPVOID arg)
+gint
+mono_threads_suspend_get_abort_signal (void)
 {
-       ThreadStartInfo *start_info = arg;
-       void *t_arg = start_info->arg;
-       LPTHREAD_START_ROUTINE start_func = start_info->start_routine;
-       DWORD result;
-       gboolean suspend = start_info->suspend;
-       MonoThreadInfo *info;
-       int res;
+       return -1;
+}
 
-       info = mono_thread_info_attach (&result);
-       info->runtime_thread = TRUE;
+#endif
 
-       start_info->handle = info->handle;
+#if defined (HOST_WIN32)
 
-       mono_threads_platform_set_priority(info, start_info->priority);
+gboolean
+mono_thread_platform_create_thread (MonoThreadStart thread_fn, gpointer thread_data, gsize* const stack_size, MonoNativeThreadId *tid)
+{
+       HANDLE result;
+       DWORD thread_id;
 
-       if (suspend) {
-               info->create_suspended = TRUE;
-               mono_coop_sem_init (&info->create_suspended_sem, 0);
-       }
+       result = CreateThread (NULL, stack_size ? *stack_size : 0, (LPTHREAD_START_ROUTINE) thread_fn, thread_data, 0, &thread_id);
+       if (!result)
+               return FALSE;
 
-       mono_coop_sem_post (&(start_info->registered));
+       /* A new handle is open when attaching
+        * the thread, so we don't need this one */
+       CloseHandle (result);
 
-       if (suspend) {
-               res = mono_coop_sem_wait (&info->create_suspended_sem, MONO_SEM_FLAGS_NONE);
-               g_assert (res != -1);
+       if (tid)
+               *tid = thread_id;
 
-               mono_coop_sem_destroy (&info->create_suspended_sem);
+       if (stack_size) {
+               // TOOD: Use VirtualQuery to get correct value 
+               // http://stackoverflow.com/questions/2480095/thread-stack-size-on-windows-visual-c
+               *stack_size = 2 * 1024 * 1024;
        }
 
-       result = start_func (t_arg);
-
-       mono_thread_info_detach ();
-
-       return result;
-}
-
-HANDLE
-mono_threads_platform_create_thread (MonoThreadStart start_routine, gpointer arg, MonoThreadParm *tp, MonoNativeThreadId *out_tid)
-{
-       ThreadStartInfo start_info;
-       HANDLE result;
-       DWORD thread_id;
-       guint32 creation_flags = tp->creation_flags;
-       int res;
-
-       memset (&start_info, 0, sizeof (start_info));
-       mono_coop_sem_init (&(start_info.registered), 0);
-       start_info.arg = arg;
-       start_info.start_routine = start_routine;
-       start_info.suspend = creation_flags & CREATE_SUSPENDED;
-       start_info.priority = tp->priority;
-       creation_flags &= ~CREATE_SUSPENDED;
-
-       result = CreateThread (NULL, tp->stack_size, inner_start_thread, &start_info, creation_flags, &thread_id);
-       if (result) {
-               res = mono_coop_sem_wait (&(start_info.registered), MONO_SEM_FLAGS_NONE);
-               g_assert (res != -1);
-
-               /* A new handle has been opened when attaching
-                * the thread, so we don't need this one */
-               CloseHandle (result);
-       }
-       if (out_tid)
-               *out_tid = thread_id;
-       mono_coop_sem_destroy (&(start_info.registered));
-       return start_info.handle;
+       return TRUE;
 }
 
 
@@ -247,6 +218,28 @@ mono_native_thread_create (MonoNativeThreadId *tid, gpointer func, gpointer arg)
        return CreateThread (NULL, 0, (func), (arg), 0, (tid)) != NULL;
 }
 
+gboolean
+mono_native_thread_join_handle (HANDLE thread_handle, gboolean close_handle)
+{
+       DWORD res = WaitForSingleObject (thread_handle, INFINITE);
+
+       if (close_handle)
+               CloseHandle (thread_handle);
+
+       return res != WAIT_FAILED;
+}
+
+gboolean
+mono_native_thread_join (MonoNativeThreadId tid)
+{
+       HANDLE handle;
+
+       if (!(handle = OpenThread (SYNCHRONIZE, TRUE, tid)))
+               return FALSE;
+
+       return mono_native_thread_join_handle (handle, TRUE);
+}
+
 #if HAVE_DECL___READFSDWORD==0
 static MONO_ALWAYS_INLINE unsigned long long
 __readfsdword (unsigned long offset)
@@ -287,21 +280,66 @@ mono_threads_platform_get_stack_bounds (guint8 **staddr, size_t *stsize)
 
 }
 
+#if SIZEOF_VOID_P == 4 && G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
+typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
+static gboolean is_wow64 = FALSE;
+#endif
+
+/* We do this at init time to avoid potential races with module opening */
+void
+mono_threads_platform_init (void)
+{
+#if SIZEOF_VOID_P == 4 && G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
+       LPFN_ISWOW64PROCESS is_wow64_func = (LPFN_ISWOW64PROCESS) GetProcAddress (GetModuleHandle (TEXT ("kernel32")), "IsWow64Process");
+       if (is_wow64_func)
+               is_wow64_func (GetCurrentProcess (), &is_wow64);
+#endif
+}
+
+/*
+ * When running x86 process under x64 system syscalls are done through WoW64. This
+ * needs to do a transition from x86 mode to x64 so it can syscall into the x64 system.
+ * Apparently this transition invalidates the ESP that we would get from calling
+ * GetThreadContext, so we would fail to scan parts of the thread stack. We attempt
+ * to query whether the thread is in such a transition so we try to restart it later.
+ * We check CONTEXT_EXCEPTION_ACTIVE for this, which is highly undocumented.
+ */
 gboolean
-mono_threads_platform_yield (void)
+mono_threads_platform_in_critical_region (MonoNativeThreadId tid)
 {
-       return SwitchToThread ();
+       gboolean ret = FALSE;
+#if SIZEOF_VOID_P == 4 && G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
+/* FIXME On cygwin these are not defined */
+#if defined(CONTEXT_EXCEPTION_REQUEST) && defined(CONTEXT_EXCEPTION_REPORTING) && defined(CONTEXT_EXCEPTION_ACTIVE)
+       if (is_wow64) {
+               HANDLE handle = OpenThread (THREAD_ALL_ACCESS, FALSE, tid);
+               if (handle) {
+                       CONTEXT context;
+                       ZeroMemory (&context, sizeof (CONTEXT));
+                       context.ContextFlags = CONTEXT_EXCEPTION_REQUEST;
+                       if (GetThreadContext (handle, &context)) {
+                               if ((context.ContextFlags & CONTEXT_EXCEPTION_REPORTING) &&
+                                               (context.ContextFlags & CONTEXT_EXCEPTION_ACTIVE))
+                                       ret = TRUE;
+                       }
+                       CloseHandle (handle);
+               }
+       }
+#endif
+#endif
+       return ret;
 }
 
-void
-mono_threads_platform_exit (int exit_code)
+gboolean
+mono_threads_platform_yield (void)
 {
-       ExitThread (exit_code);
+       return SwitchToThread ();
 }
 
 void
-mono_threads_platform_unregister (MonoThreadInfo *info)
+mono_threads_platform_exit (gsize exit_code)
 {
+       ExitThread (exit_code);
 }
 
 int
@@ -311,12 +349,6 @@ mono_threads_get_max_stack_size (void)
        return INT_MAX;
 }
 
-HANDLE
-mono_threads_platform_open_thread_handle (HANDLE handle, MonoNativeThreadId tid)
-{
-       return OpenThread (THREAD_ALL_ACCESS, TRUE, tid);
-}
-
 #if defined(_MSC_VER)
 const DWORD MS_VC_EXCEPTION=0x406D1388;
 #pragma pack(push,8)
@@ -349,46 +381,4 @@ mono_native_thread_set_name (MonoNativeThreadId tid, const char *name)
 #endif
 }
 
-void
-mono_threads_platform_set_exited (MonoThreadInfo *info)
-{
-}
-
-void
-mono_threads_platform_describe (MonoThreadInfo *info, GString *text)
-{
-       /* TODO */
-}
-
-void
-mono_threads_platform_own_mutex (MonoThreadInfo *info, gpointer mutex_handle)
-{
-       g_assert_not_reached ();
-}
-
-void
-mono_threads_platform_disown_mutex (MonoThreadInfo *info, gpointer mutex_handle)
-{
-       g_assert_not_reached ();
-}
-
-MonoThreadPriority
-mono_threads_platform_get_priority (MonoThreadInfo *info)
-{
-       g_assert (info->handle);
-       return GetThreadPriority (info->handle) + 2;
-}
-
-gboolean
-mono_threads_platform_set_priority (MonoThreadInfo *info, MonoThreadPriority priority)
-{
-       g_assert (info->handle);
-       return SetThreadPriority (info->handle, priority - 2);
-}
-
-void
-mono_threads_platform_init (void)
-{
-}
-
 #endif