2 * mono-threads-windows.c: Low-level threading, windows version
5 * Rodrigo Kumpera (kumpera@gmail.com)
10 #include <mono/utils/mono-threads.h>
12 #if defined(USE_WINDOWS_BACKEND)
14 #include <mono/utils/mono-compiler.h>
19 mono_threads_init_platform (void)
24 interrupt_apc (ULONG_PTR param)
29 mono_threads_core_abort_syscall (MonoThreadInfo *info)
31 DWORD id = mono_thread_info_get_tid (info);
34 handle = OpenThread (THREAD_ALL_ACCESS, FALSE, id);
37 QueueUserAPC ((PAPCFUNC)interrupt_apc, handle, (ULONG_PTR)NULL);
43 mono_threads_core_needs_abort_syscall (void)
49 mono_threads_core_begin_async_suspend (MonoThreadInfo *info, gboolean interrupt_kernel)
51 DWORD id = mono_thread_info_get_tid (info);
56 handle = OpenThread (THREAD_ALL_ACCESS, FALSE, id);
59 result = SuspendThread (handle);
60 THREADS_SUSPEND_DEBUG ("SUSPEND %p -> %d\n", (void*)id, ret);
61 if (result == (DWORD)-1) {
66 /* We're in the middle of a self-suspend, resume and register */
67 if (!mono_threads_transition_finish_async_suspend (info)) {
68 mono_threads_add_to_pending_operation_set (info);
69 result = ResumeThread (handle);
70 g_assert (result == 1);
72 THREADS_SUSPEND_DEBUG ("FAILSAFE RESUME/1 %p -> %d\n", (void*)id, 0);
73 //XXX interrupt_kernel doesn't make sense in this case as the target is not in a syscall
76 res = mono_threads_get_runtime_callbacks ()->thread_state_init_from_handle (&info->thread_saved_state [ASYNC_SUSPEND_STATE_INDEX], info);
77 THREADS_SUSPEND_DEBUG ("thread state %p -> %d\n", (void*)id, res);
79 //FIXME do we need to QueueUserAPC on this case?
81 QueueUserAPC ((PAPCFUNC)interrupt_apc, handle, (ULONG_PTR)NULL);
83 mono_threads_transition_async_suspend_compensation (info);
84 result = ResumeThread (handle);
85 g_assert (result == 1);
86 THREADS_SUSPEND_DEBUG ("FAILSAFE RESUME/2 %p -> %d\n", (void*)info->native_handle, 0);
94 mono_threads_core_check_suspend_result (MonoThreadInfo *info)
100 mono_threads_core_begin_async_resume (MonoThreadInfo *info)
102 DWORD id = mono_thread_info_get_tid (info);
106 handle = OpenThread (THREAD_ALL_ACCESS, FALSE, id);
109 if (info->async_target) {
114 ctx = info->thread_saved_state [ASYNC_SUSPEND_STATE_INDEX].ctx;
115 mono_threads_get_runtime_callbacks ()->setup_async_callback (&ctx, info->async_target, info->user_data);
116 info->async_target = info->user_data = NULL;
118 context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
120 if (!GetThreadContext (handle, &context)) {
121 CloseHandle (handle);
125 g_assert (context.ContextFlags & CONTEXT_INTEGER);
126 g_assert (context.ContextFlags & CONTEXT_CONTROL);
128 mono_monoctx_to_sigctx (&ctx, &context);
130 context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
131 res = SetThreadContext (handle, &context);
133 CloseHandle (handle);
138 result = ResumeThread (handle);
139 CloseHandle (handle);
141 return result != (DWORD)-1;
146 mono_threads_platform_register (MonoThreadInfo *info)
151 mono_threads_platform_free (MonoThreadInfo *info)
156 mono_threads_core_begin_global_suspend (void)
161 mono_threads_core_end_global_suspend (void)
167 #if defined (HOST_WIN32)
170 LPTHREAD_START_ROUTINE start_routine;
172 MonoSemType registered;
174 HANDLE suspend_event;
178 inner_start_thread (LPVOID arg)
180 ThreadStartInfo *start_info = arg;
181 void *t_arg = start_info->arg;
183 LPTHREAD_START_ROUTINE start_func = start_info->start_routine;
185 gboolean suspend = start_info->suspend;
186 HANDLE suspend_event = start_info->suspend_event;
187 MonoThreadInfo *info;
189 info = mono_thread_info_attach (&result);
190 info->runtime_thread = TRUE;
191 info->create_suspended = suspend;
193 post_result = MONO_SEM_POST (&(start_info->registered));
194 g_assert (!post_result);
197 WaitForSingleObject (suspend_event, INFINITE); /* caller will suspend the thread before setting the event. */
198 CloseHandle (suspend_event);
201 result = start_func (t_arg);
203 mono_thread_info_detach ();
209 mono_threads_core_create_thread (LPTHREAD_START_ROUTINE start_routine, gpointer arg, guint32 stack_size, guint32 creation_flags, MonoNativeThreadId *out_tid)
211 ThreadStartInfo *start_info;
215 start_info = g_malloc0 (sizeof (ThreadStartInfo));
218 MONO_SEM_INIT (&(start_info->registered), 0);
219 start_info->arg = arg;
220 start_info->start_routine = start_routine;
221 start_info->suspend = creation_flags & CREATE_SUSPENDED;
222 creation_flags &= ~CREATE_SUSPENDED;
223 if (start_info->suspend) {
224 start_info->suspend_event = CreateEvent (NULL, TRUE, FALSE, NULL);
225 if (!start_info->suspend_event)
229 result = CreateThread (NULL, stack_size, inner_start_thread, start_info, creation_flags, &thread_id);
231 while (MONO_SEM_WAIT (&(start_info->registered)) != 0) {
232 /*if (EINTR != errno) ABORT("sem_wait failed"); */
234 if (start_info->suspend) {
235 g_assert (SuspendThread (result) != (DWORD)-1);
236 SetEvent (start_info->suspend_event);
238 } else if (start_info->suspend) {
239 CloseHandle (start_info->suspend_event);
242 *out_tid = thread_id;
243 MONO_SEM_DESTROY (&(start_info->registered));
250 mono_native_thread_id_get (void)
252 return GetCurrentThreadId ();
256 mono_native_thread_id_equals (MonoNativeThreadId id1, MonoNativeThreadId id2)
262 mono_native_thread_create (MonoNativeThreadId *tid, gpointer func, gpointer arg)
264 return CreateThread (NULL, 0, (func), (arg), 0, (tid)) != NULL;
268 mono_threads_core_resume_created (MonoThreadInfo *info, MonoNativeThreadId tid)
272 handle = OpenThread (THREAD_ALL_ACCESS, TRUE, tid);
274 ResumeThread (handle);
275 CloseHandle (handle);
278 #if HAVE_DECL___READFSDWORD==0
279 static MONO_ALWAYS_INLINE unsigned long long
280 __readfsdword (unsigned long offset)
283 // __asm__("movl %%fs:%a[offset], %k[value]" : [value] "=q" (value) : [offset] "irm" (offset));
284 __asm__ volatile ("movl %%fs:%1,%0"
285 : "=r" (value) ,"=m" ((*(volatile long *) offset)));
291 mono_threads_core_get_stack_bounds (guint8 **staddr, size_t *stsize)
293 MEMORY_BASIC_INFORMATION meminfo;
296 NT_TIB* tib = (NT_TIB*)NtCurrentTeb();
297 guint8 *stackTop = (guint8*)tib->StackBase;
298 guint8 *stackBottom = (guint8*)tib->StackLimit;
300 /* http://en.wikipedia.org/wiki/Win32_Thread_Information_Block */
301 void* tib = (void*)__readfsdword(0x18);
302 guint8 *stackTop = (guint8*)*(int*)((char*)tib + 4);
303 guint8 *stackBottom = (guint8*)*(int*)((char*)tib + 8);
306 Windows stacks are expanded on demand, one page at time. The TIB reports
307 only the currently allocated amount.
308 VirtualQuery will return the actual limit for the bottom, which is what we want.
310 if (VirtualQuery (&meminfo, &meminfo, sizeof (meminfo)) == sizeof (meminfo))
311 stackBottom = MIN (stackBottom, (guint8*)meminfo.AllocationBase);
313 *staddr = stackBottom;
314 *stsize = stackTop - stackBottom;
319 mono_threads_core_yield (void)
321 return SwitchToThread ();
325 mono_threads_core_exit (int exit_code)
327 ExitThread (exit_code);
331 mono_threads_core_unregister (MonoThreadInfo *info)
336 mono_threads_core_open_handle (void)
338 HANDLE thread_handle;
340 thread_handle = GetCurrentThread ();
341 g_assert (thread_handle);
344 * The handle returned by GetCurrentThread () is a pseudo handle, so it can't be used to
345 * refer to the thread from other threads for things like aborting.
347 DuplicateHandle (GetCurrentProcess (), thread_handle, GetCurrentProcess (), &thread_handle,
348 THREAD_ALL_ACCESS, TRUE, 0);
350 return thread_handle;
354 mono_threads_get_max_stack_size (void)
361 mono_threads_core_open_thread_handle (HANDLE handle, MonoNativeThreadId tid)
363 return OpenThread (THREAD_ALL_ACCESS, TRUE, tid);
366 #if defined(_MSC_VER)
367 const DWORD MS_VC_EXCEPTION=0x406D1388;
369 typedef struct tagTHREADNAME_INFO
371 DWORD dwType; // Must be 0x1000.
372 LPCSTR szName; // Pointer to name (in user addr space).
373 DWORD dwThreadID; // Thread ID (-1=caller thread).
374 DWORD dwFlags; // Reserved for future use, must be zero.
380 mono_threads_core_set_name (MonoNativeThreadId tid, const char *name)
382 #if defined(_MSC_VER)
383 /* http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx */
384 THREADNAME_INFO info;
385 info.dwType = 0x1000;
387 info.dwThreadID = tid;
391 RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info );
393 __except(EXCEPTION_EXECUTE_HANDLER) {
400 mono_threads_core_prepare_interrupt (HANDLE thread_handle)
406 mono_threads_core_finish_interrupt (gpointer wait_handle)
411 mono_threads_core_self_interrupt (void)
416 mono_threads_core_clear_interruption (void)