2 * mono-threads-windows.c: Low-level threading, windows version
5 * Rodrigo Kumpera (kumpera@gmail.com)
12 #if defined(HOST_WIN32)
14 #include <mono/utils/mono-threads.h>
15 #include <mono/utils/mono-compiler.h>
20 mono_threads_init_platform (void)
25 interrupt_apc (ULONG_PTR param)
30 mono_threads_core_abort_syscall (MonoThreadInfo *info)
32 DWORD id = mono_thread_info_get_tid (info);
35 handle = OpenThread (THREAD_ALL_ACCESS, FALSE, id);
38 QueueUserAPC ((PAPCFUNC)interrupt_apc, handle, (ULONG_PTR)NULL);
44 mono_threads_core_interrupt (MonoThreadInfo *info)
46 mono_threads_core_abort_syscall (info);
50 mono_threads_core_needs_abort_syscall (void)
56 mono_threads_core_begin_async_suspend (MonoThreadInfo *info, gboolean interrupt_kernel)
58 DWORD id = mono_thread_info_get_tid (info);
63 handle = OpenThread (THREAD_ALL_ACCESS, FALSE, id);
66 result = SuspendThread (handle);
67 THREADS_SUSPEND_DEBUG ("SUSPEND %p -> %d\n", (void*)id, ret);
68 if (result == (DWORD)-1) {
73 /* We're in the middle of a self-suspend, resume and register */
74 if (!mono_threads_transition_finish_async_suspend (info)) {
75 mono_threads_add_to_pending_operation_set (info);
76 result = ResumeThread (handle);
77 g_assert (result == 1);
79 THREADS_SUSPEND_DEBUG ("FAILSAFE RESUME/1 %p -> %d\n", (void*)id, 0);
80 //XXX interrupt_kernel doesn't make sense in this case as the target is not in a syscall
83 res = mono_threads_get_runtime_callbacks ()->thread_state_init_from_handle (&info->thread_saved_state [ASYNC_SUSPEND_STATE_INDEX], info);
84 THREADS_SUSPEND_DEBUG ("thread state %p -> %d\n", (void*)id, res);
86 //FIXME do we need to QueueUserAPC on this case?
88 QueueUserAPC ((PAPCFUNC)interrupt_apc, handle, (ULONG_PTR)NULL);
90 mono_threads_transition_async_suspend_compensation (info);
91 result = ResumeThread (handle);
92 g_assert (result == 1);
93 THREADS_SUSPEND_DEBUG ("FAILSAFE RESUME/2 %p -> %d\n", (void*)info->native_handle, 0);
101 mono_threads_core_check_suspend_result (MonoThreadInfo *info)
107 mono_threads_core_begin_async_resume (MonoThreadInfo *info)
109 DWORD id = mono_thread_info_get_tid (info);
113 handle = OpenThread (THREAD_ALL_ACCESS, FALSE, id);
116 if (info->async_target) {
121 ctx = info->thread_saved_state [ASYNC_SUSPEND_STATE_INDEX].ctx;
122 mono_threads_get_runtime_callbacks ()->setup_async_callback (&ctx, info->async_target, info->user_data);
123 info->async_target = info->user_data = NULL;
125 context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
127 if (!GetThreadContext (handle, &context)) {
128 CloseHandle (handle);
132 g_assert (context.ContextFlags & CONTEXT_INTEGER);
133 g_assert (context.ContextFlags & CONTEXT_CONTROL);
135 mono_monoctx_to_sigctx (&ctx, &context);
137 context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
138 res = SetThreadContext (handle, &context);
140 CloseHandle (handle);
145 result = ResumeThread (handle);
146 CloseHandle (handle);
148 return result != (DWORD)-1;
153 mono_threads_platform_register (MonoThreadInfo *info)
158 mono_threads_platform_free (MonoThreadInfo *info)
163 LPTHREAD_START_ROUTINE start_routine;
165 MonoSemType registered;
167 HANDLE suspend_event;
171 inner_start_thread (LPVOID arg)
173 ThreadStartInfo *start_info = arg;
174 void *t_arg = start_info->arg;
176 LPTHREAD_START_ROUTINE start_func = start_info->start_routine;
178 gboolean suspend = start_info->suspend;
179 HANDLE suspend_event = start_info->suspend_event;
180 MonoThreadInfo *info;
182 info = mono_thread_info_attach (&result);
183 info->runtime_thread = TRUE;
184 info->create_suspended = suspend;
186 post_result = MONO_SEM_POST (&(start_info->registered));
187 g_assert (!post_result);
190 WaitForSingleObject (suspend_event, INFINITE); /* caller will suspend the thread before setting the event. */
191 CloseHandle (suspend_event);
194 result = start_func (t_arg);
196 mono_thread_info_detach ();
202 mono_threads_core_create_thread (LPTHREAD_START_ROUTINE start_routine, gpointer arg, guint32 stack_size, guint32 creation_flags, MonoNativeThreadId *out_tid)
204 ThreadStartInfo *start_info;
208 start_info = g_malloc0 (sizeof (ThreadStartInfo));
211 MONO_SEM_INIT (&(start_info->registered), 0);
212 start_info->arg = arg;
213 start_info->start_routine = start_routine;
214 start_info->suspend = creation_flags & CREATE_SUSPENDED;
215 creation_flags &= ~CREATE_SUSPENDED;
216 if (start_info->suspend) {
217 start_info->suspend_event = CreateEvent (NULL, TRUE, FALSE, NULL);
218 if (!start_info->suspend_event)
222 result = CreateThread (NULL, stack_size, inner_start_thread, start_info, creation_flags, &thread_id);
224 while (MONO_SEM_WAIT (&(start_info->registered)) != 0) {
225 /*if (EINTR != errno) ABORT("sem_wait failed"); */
227 if (start_info->suspend) {
228 g_assert (SuspendThread (result) != (DWORD)-1);
229 SetEvent (start_info->suspend_event);
231 } else if (start_info->suspend) {
232 CloseHandle (start_info->suspend_event);
235 *out_tid = thread_id;
236 MONO_SEM_DESTROY (&(start_info->registered));
243 mono_native_thread_id_get (void)
245 return GetCurrentThreadId ();
249 mono_native_thread_id_equals (MonoNativeThreadId id1, MonoNativeThreadId id2)
255 mono_native_thread_create (MonoNativeThreadId *tid, gpointer func, gpointer arg)
257 return CreateThread (NULL, 0, (func), (arg), 0, (tid)) != NULL;
261 mono_threads_core_resume_created (MonoThreadInfo *info, MonoNativeThreadId tid)
265 handle = OpenThread (THREAD_ALL_ACCESS, TRUE, tid);
267 ResumeThread (handle);
268 CloseHandle (handle);
271 #if HAVE_DECL___READFSDWORD==0
272 static MONO_ALWAYS_INLINE unsigned long long
273 __readfsdword (unsigned long offset)
276 // __asm__("movl %%fs:%a[offset], %k[value]" : [value] "=q" (value) : [offset] "irm" (offset));
277 __asm__ volatile ("movl %%fs:%1,%0"
278 : "=r" (value) ,"=m" ((*(volatile long *) offset)));
284 mono_threads_core_get_stack_bounds (guint8 **staddr, size_t *stsize)
286 MEMORY_BASIC_INFORMATION meminfo;
289 NT_TIB* tib = (NT_TIB*)NtCurrentTeb();
290 guint8 *stackTop = (guint8*)tib->StackBase;
291 guint8 *stackBottom = (guint8*)tib->StackLimit;
293 /* http://en.wikipedia.org/wiki/Win32_Thread_Information_Block */
294 void* tib = (void*)__readfsdword(0x18);
295 guint8 *stackTop = (guint8*)*(int*)((char*)tib + 4);
296 guint8 *stackBottom = (guint8*)*(int*)((char*)tib + 8);
299 Windows stacks are expanded on demand, one page at time. The TIB reports
300 only the currently allocated amount.
301 VirtualQuery will return the actual limit for the bottom, which is what we want.
303 if (VirtualQuery (&meminfo, &meminfo, sizeof (meminfo)) == sizeof (meminfo))
304 stackBottom = MIN (stackBottom, (guint8*)meminfo.AllocationBase);
306 *staddr = stackBottom;
307 *stsize = stackTop - stackBottom;
312 mono_threads_core_yield (void)
314 return SwitchToThread ();
318 mono_threads_core_exit (int exit_code)
320 ExitThread (exit_code);
324 mono_threads_core_unregister (MonoThreadInfo *info)
329 mono_threads_core_open_handle (void)
331 HANDLE thread_handle;
333 thread_handle = GetCurrentThread ();
334 g_assert (thread_handle);
337 * The handle returned by GetCurrentThread () is a pseudo handle, so it can't be used to
338 * refer to the thread from other threads for things like aborting.
340 DuplicateHandle (GetCurrentProcess (), thread_handle, GetCurrentProcess (), &thread_handle,
341 THREAD_ALL_ACCESS, TRUE, 0);
343 return thread_handle;
347 mono_threads_get_max_stack_size (void)
354 mono_threads_core_open_thread_handle (HANDLE handle, MonoNativeThreadId tid)
356 return OpenThread (THREAD_ALL_ACCESS, TRUE, tid);
359 #if defined(_MSC_VER)
360 const DWORD MS_VC_EXCEPTION=0x406D1388;
362 typedef struct tagTHREADNAME_INFO
364 DWORD dwType; // Must be 0x1000.
365 LPCSTR szName; // Pointer to name (in user addr space).
366 DWORD dwThreadID; // Thread ID (-1=caller thread).
367 DWORD dwFlags; // Reserved for future use, must be zero.
373 mono_threads_core_set_name (MonoNativeThreadId tid, const char *name)
375 #if defined(_MSC_VER)
376 /* http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx */
377 THREADNAME_INFO info;
378 info.dwType = 0x1000;
380 info.dwThreadID = tid;
384 RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info );
386 __except(EXCEPTION_EXECUTE_HANDLER) {
393 mono_threads_core_prepare_interrupt (HANDLE thread_handle)
399 mono_threads_core_finish_interrupt (gpointer wait_handle)
404 mono_threads_core_self_interrupt (void)
409 mono_threads_core_clear_interruption (void)