X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Futils%2Fmono-threads-windows.c;h=04430fb021f274ad99d4312d0290f42df875a5df;hb=b7a308f660de8174b64697a422abfc7315d07b8c;hp=92457cc9b8984dea182966482530c9d35fc23314;hpb=eee540621a25b57dbad6a41dd62a559e43a766c1;p=mono.git diff --git a/mono/utils/mono-threads-windows.c b/mono/utils/mono-threads-windows.c index 92457cc9b89..29703b11f6f 100644 --- a/mono/utils/mono-threads-windows.c +++ b/mono/utils/mono-threads-windows.c @@ -7,11 +7,12 @@ * (C) 2011 Novell, Inc */ -#include "config.h" +#include -#if defined(HOST_WIN32) +#if defined(USE_WINDOWS_BACKEND) -#include +#include +#include void @@ -19,51 +20,132 @@ mono_threads_init_platform (void) { } -void -mono_threads_core_interrupt (MonoThreadInfo *info) +static void CALLBACK +interrupt_apc (ULONG_PTR param) { - g_assert (0); } -void -mono_threads_core_abort_syscall (MonoThreadInfo *info) +gboolean +mono_threads_core_begin_async_suspend (MonoThreadInfo *info, gboolean interrupt_kernel) { + DWORD id = mono_thread_info_get_tid (info); + HANDLE handle; + DWORD result; + gboolean res; + + handle = OpenThread (THREAD_ALL_ACCESS, FALSE, id); + g_assert (handle); + + result = SuspendThread (handle); + THREADS_SUSPEND_DEBUG ("SUSPEND %p -> %d\n", (void*)id, ret); + if (result == (DWORD)-1) { + CloseHandle (handle); + return FALSE; + } + + /* We're in the middle of a self-suspend, resume and register */ + if (!mono_threads_transition_finish_async_suspend (info)) { + mono_threads_add_to_pending_operation_set (info); + result = ResumeThread (handle); + g_assert (result == 1); + CloseHandle (handle); + THREADS_SUSPEND_DEBUG ("FAILSAFE RESUME/1 %p -> %d\n", (void*)id, 0); + //XXX interrupt_kernel doesn't make sense in this case as the target is not in a syscall + return TRUE; + } + res = 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 (res) { + //FIXME do we need to QueueUserAPC on this case? + if (interrupt_kernel) + QueueUserAPC ((PAPCFUNC)interrupt_apc, handle, (ULONG_PTR)NULL); + } else { + mono_threads_transition_async_suspend_compensation (info); + result = ResumeThread (handle); + g_assert (result == 1); + THREADS_SUSPEND_DEBUG ("FAILSAFE RESUME/2 %p -> %d\n", (void*)info->native_handle, 0); + } + + CloseHandle (handle); + return res; } gboolean -mono_threads_core_needs_abort_syscall (void) +mono_threads_core_check_suspend_result (MonoThreadInfo *info) { - return FALSE; + return TRUE; } -void -mono_threads_core_self_suspend (MonoThreadInfo *info) +gboolean +mono_threads_core_begin_async_resume (MonoThreadInfo *info) { - g_assert (0); + DWORD id = mono_thread_info_get_tid (info); + HANDLE handle; + DWORD result; + + handle = OpenThread (THREAD_ALL_ACCESS, FALSE, id); + g_assert (handle); + + if (info->async_target) { + MonoContext ctx; + CONTEXT context; + gboolean res; + + ctx = info->thread_saved_state [ASYNC_SUSPEND_STATE_INDEX].ctx; + mono_threads_get_runtime_callbacks ()->setup_async_callback (&ctx, info->async_target, info->user_data); + info->async_target = info->user_data = NULL; + + context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL; + + if (!GetThreadContext (handle, &context)) { + CloseHandle (handle); + return FALSE; + } + + g_assert (context.ContextFlags & CONTEXT_INTEGER); + g_assert (context.ContextFlags & CONTEXT_CONTROL); + + mono_monoctx_to_sigctx (&ctx, &context); + + context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL; + res = SetThreadContext (handle, &context); + if (!res) { + CloseHandle (handle); + return FALSE; + } + } + + result = ResumeThread (handle); + CloseHandle (handle); + + return result != (DWORD)-1; } -gboolean -mono_threads_core_suspend (MonoThreadInfo *info) + +void +mono_threads_platform_register (MonoThreadInfo *info) { - g_assert (0); } -gboolean -mono_threads_core_resume (MonoThreadInfo *info) +void +mono_threads_platform_free (MonoThreadInfo *info) { - g_assert (0); } void -mono_threads_platform_register (MonoThreadInfo *info) +mono_threads_core_begin_global_suspend (void) { } void -mono_threads_platform_free (MonoThreadInfo *info) +mono_threads_core_end_global_suspend (void) { } +#endif + +#if defined (HOST_WIN32) + typedef struct { LPTHREAD_START_ROUTINE start_routine; void *arg; @@ -98,9 +180,7 @@ inner_start_thread (LPVOID arg) result = start_func (t_arg); - g_assert (!mono_domain_get ()); - - mono_thread_info_dettach (); + mono_thread_info_detach (); return result; } @@ -176,8 +256,7 @@ mono_threads_core_resume_created (MonoThreadInfo *info, MonoNativeThreadId tid) } #if HAVE_DECL___READFSDWORD==0 -static __inline__ __attribute__((always_inline)) -unsigned long long +static MONO_ALWAYS_INLINE unsigned long long __readfsdword (unsigned long offset) { unsigned long value; @@ -191,14 +270,29 @@ __readfsdword (unsigned long offset) void mono_threads_core_get_stack_bounds (guint8 **staddr, size_t *stsize) { - /* Windows */ + MEMORY_BASIC_INFORMATION meminfo; +#ifdef _WIN64 + /* win7 apis */ + NT_TIB* tib = (NT_TIB*)NtCurrentTeb(); + guint8 *stackTop = (guint8*)tib->StackBase; + guint8 *stackBottom = (guint8*)tib->StackLimit; +#else /* http://en.wikipedia.org/wiki/Win32_Thread_Information_Block */ void* tib = (void*)__readfsdword(0x18); guint8 *stackTop = (guint8*)*(int*)((char*)tib + 4); guint8 *stackBottom = (guint8*)*(int*)((char*)tib + 8); +#endif + /* + Windows stacks are expanded on demand, one page at time. The TIB reports + only the currently allocated amount. + VirtualQuery will return the actual limit for the bottom, which is what we want. + */ + if (VirtualQuery (&meminfo, &meminfo, sizeof (meminfo)) == sizeof (meminfo)) + stackBottom = MIN (stackBottom, (guint8*)meminfo.AllocationBase); *staddr = stackBottom; *stsize = stackTop - stackBottom; + } gboolean @@ -207,4 +301,78 @@ mono_threads_core_yield (void) return SwitchToThread (); } +void +mono_threads_core_exit (int exit_code) +{ + ExitThread (exit_code); +} + +void +mono_threads_core_unregister (MonoThreadInfo *info) +{ +} + +HANDLE +mono_threads_core_open_handle (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); + + return thread_handle; +} + +int +mono_threads_get_max_stack_size (void) +{ + //FIXME + return INT_MAX; +} + +HANDLE +mono_threads_core_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) +typedef struct tagTHREADNAME_INFO +{ + DWORD dwType; // Must be 0x1000. + LPCSTR szName; // Pointer to name (in user addr space). + DWORD dwThreadID; // Thread ID (-1=caller thread). + DWORD dwFlags; // Reserved for future use, must be zero. +} THREADNAME_INFO; +#pragma pack(pop) +#endif + +void +mono_threads_core_set_name (MonoNativeThreadId tid, const char *name) +{ +#if defined(_MSC_VER) + /* http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx */ + THREADNAME_INFO info; + info.dwType = 0x1000; + info.szName = name; + info.dwThreadID = tid; + info.dwFlags = 0; + + __try { + RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info ); + } + __except(EXCEPTION_EXECUTE_HANDLER) { + } +#endif +} + #endif