-/*
- * 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)
{
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
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)
{
{
}
-#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);
+gint
+mono_threads_suspend_search_alternative_signal (void)
+{
+ g_assert_not_reached ();
+}
- /* 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_get_suspend_signal (void)
+{
+ return -1;
+}
- g_assert (!info->handle);
- info->handle = thread_handle;
+gint
+mono_threads_suspend_get_restart_signal (void)
+{
+ return -1;
}
-int
-mono_threads_platform_create_thread (MonoThreadStart thread_fn, gpointer thread_data, gsize stack_size, MonoNativeThreadId *out_tid)
+gint
+mono_threads_suspend_get_abort_signal (void)
+{
+ return -1;
+}
+
+#endif
+
+#if defined (HOST_WIN32)
+
+gboolean
+mono_thread_platform_create_thread (MonoThreadStart thread_fn, gpointer thread_data, gsize* const stack_size, MonoNativeThreadId *tid)
{
HANDLE result;
DWORD thread_id;
- result = CreateThread (NULL, stack_size, (LPTHREAD_START_ROUTINE) thread_fn, thread_data, 0, &thread_id);
+ result = CreateThread (NULL, stack_size ? *stack_size : 0, (LPTHREAD_START_ROUTINE) thread_fn, thread_data, 0, &thread_id);
if (!result)
- return -1;
+ return FALSE;
/* A new handle is open when attaching
* the thread, so we don't need this one */
CloseHandle (result);
- if (out_tid)
- *out_tid = thread_id;
+ if (tid)
+ *tid = thread_id;
+
+ 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;
+ }
- return 0;
+ return TRUE;
}
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)
}
+#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)
{
- mono_thread_info_detach ();
- ExitThread (exit_code);
+ return SwitchToThread ();
}
void
-mono_threads_platform_unregister (MonoThreadInfo *info)
+mono_threads_platform_exit (gsize exit_code)
{
- mono_threads_platform_set_exited (info);
+ ExitThread (exit_code);
}
int
return INT_MAX;
}
-gpointer
-mono_threads_platform_duplicate_handle (MonoThreadInfo *info)
-{
- HANDLE thread_handle;
-
- g_assert (info->handle);
- DuplicateHandle (GetCurrentProcess (), info->handle, GetCurrentProcess (), &thread_handle, THREAD_ALL_ACCESS, TRUE, 0);
-
- return thread_handle;
-}
-
-HANDLE
-mono_threads_platform_open_thread_handle (HANDLE handle, MonoNativeThreadId tid)
-{
- return OpenThread (THREAD_ALL_ACCESS, TRUE, tid);
-}
-
-void
-mono_threads_platform_close_thread_handle (HANDLE handle)
-{
- CloseHandle (handle);
-}
-
#if defined(_MSC_VER)
const DWORD MS_VC_EXCEPTION=0x406D1388;
#pragma pack(push,8)
#endif
}
-void
-mono_threads_platform_set_exited (MonoThreadInfo *info)
-{
- g_assert (info->handle);
- // No need to call CloseHandle() here since the InternalThread
- // destructor will close the handle when the finalizer thread calls it
- info->handle = NULL;
-}
-
-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;
-}
-
-void
-mono_threads_platform_set_priority (MonoThreadInfo *info, MonoThreadPriority priority)
-{
- BOOL res;
-
- g_assert (info->handle);
-
- res = SetThreadPriority (info->handle, priority - 2);
- if (!res)
- g_error ("%s: SetThreadPriority failed, error %d", __func__, GetLastError ());
-}
-
-void
-mono_threads_platform_init (void)
-{
-}
-
#endif