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_abort_syscall (MonoThreadInfo *info)
46 mono_threads_core_interrupt (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 g_assert (ResumeThread (handle) == KERN_SUCCESS);
78 THREADS_SUSPEND_DEBUG ("FAILSAFE RESUME/1 %p -> %d\n", (void*)id, 0);
79 //XXX interrupt_kernel doesn't make sense in this case as the target is not in a syscall
82 res = mono_threads_get_runtime_callbacks ()->thread_state_init_from_handle (&info->thread_saved_state [ASYNC_SUSPEND_STATE_INDEX], info);
83 THREADS_SUSPEND_DEBUG ("thread state %p -> %d\n", (void*)id, res);
85 //FIXME do we need to QueueUserAPC on this case?
87 QueueUserAPC ((PAPCFUNC)interrupt_apc, handle, (ULONG_PTR)NULL);
89 mono_threads_transition_async_suspend_compensation (info);
90 g_assert (ResumeThread (handle) == KERN_SUCCESS);
91 THREADS_SUSPEND_DEBUG ("FAILSAFE RESUME/2 %p -> %d\n", (void*)info->native_handle, 0);
99 mono_threads_core_check_suspend_result (MonoThreadInfo *info)
105 mono_threads_core_begin_async_resume (MonoThreadInfo *info)
107 DWORD id = mono_thread_info_get_tid (info);
111 handle = OpenThread (THREAD_ALL_ACCESS, FALSE, id);
114 if (info->async_target) {
119 ctx = info->thread_saved_state [ASYNC_SUSPEND_STATE_INDEX].ctx;
120 mono_threads_get_runtime_callbacks ()->setup_async_callback (&ctx, info->async_target, info->user_data);
121 info->async_target = info->user_data = NULL;
123 context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
125 if (!GetThreadContext (handle, &context)) {
126 CloseHandle (handle);
130 g_assert (context.ContextFlags & CONTEXT_INTEGER);
131 g_assert (context.ContextFlags & CONTEXT_CONTROL);
133 mono_monoctx_to_sigctx (&ctx, &context);
135 context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
136 res = SetThreadContext (handle, &context);
138 CloseHandle (handle);
143 result = ResumeThread (handle);
144 CloseHandle (handle);
146 return result != (DWORD)-1;
151 mono_threads_platform_register (MonoThreadInfo *info)
156 mono_threads_platform_free (MonoThreadInfo *info)
161 LPTHREAD_START_ROUTINE start_routine;
163 MonoSemType registered;
165 HANDLE suspend_event;
169 inner_start_thread (LPVOID arg)
171 ThreadStartInfo *start_info = arg;
172 void *t_arg = start_info->arg;
174 LPTHREAD_START_ROUTINE start_func = start_info->start_routine;
176 gboolean suspend = start_info->suspend;
177 HANDLE suspend_event = start_info->suspend_event;
178 MonoThreadInfo *info;
180 info = mono_thread_info_attach (&result);
181 info->runtime_thread = TRUE;
182 info->create_suspended = suspend;
184 post_result = MONO_SEM_POST (&(start_info->registered));
185 g_assert (!post_result);
188 WaitForSingleObject (suspend_event, INFINITE); /* caller will suspend the thread before setting the event. */
189 CloseHandle (suspend_event);
192 result = start_func (t_arg);
194 mono_thread_info_detach ();
200 mono_threads_core_create_thread (LPTHREAD_START_ROUTINE start_routine, gpointer arg, guint32 stack_size, guint32 creation_flags, MonoNativeThreadId *out_tid)
202 ThreadStartInfo *start_info;
206 start_info = g_malloc0 (sizeof (ThreadStartInfo));
209 MONO_SEM_INIT (&(start_info->registered), 0);
210 start_info->arg = arg;
211 start_info->start_routine = start_routine;
212 start_info->suspend = creation_flags & CREATE_SUSPENDED;
213 creation_flags &= ~CREATE_SUSPENDED;
214 if (start_info->suspend) {
215 start_info->suspend_event = CreateEvent (NULL, TRUE, FALSE, NULL);
216 if (!start_info->suspend_event)
220 result = CreateThread (NULL, stack_size, inner_start_thread, start_info, creation_flags, &thread_id);
222 while (MONO_SEM_WAIT (&(start_info->registered)) != 0) {
223 /*if (EINTR != errno) ABORT("sem_wait failed"); */
225 if (start_info->suspend) {
226 g_assert (SuspendThread (result) != (DWORD)-1);
227 SetEvent (start_info->suspend_event);
229 } else if (start_info->suspend) {
230 CloseHandle (start_info->suspend_event);
233 *out_tid = thread_id;
234 MONO_SEM_DESTROY (&(start_info->registered));
241 mono_native_thread_id_get (void)
243 return GetCurrentThreadId ();
247 mono_native_thread_id_equals (MonoNativeThreadId id1, MonoNativeThreadId id2)
253 mono_native_thread_create (MonoNativeThreadId *tid, gpointer func, gpointer arg)
255 return CreateThread (NULL, 0, (func), (arg), 0, (tid)) != NULL;
259 mono_threads_core_resume_created (MonoThreadInfo *info, MonoNativeThreadId tid)
263 handle = OpenThread (THREAD_ALL_ACCESS, TRUE, tid);
265 ResumeThread (handle);
266 CloseHandle (handle);
269 #if HAVE_DECL___READFSDWORD==0
270 static MONO_ALWAYS_INLINE unsigned long long
271 __readfsdword (unsigned long offset)
274 // __asm__("movl %%fs:%a[offset], %k[value]" : [value] "=q" (value) : [offset] "irm" (offset));
275 __asm__ volatile ("movl %%fs:%1,%0"
276 : "=r" (value) ,"=m" ((*(volatile long *) offset)));
282 mono_threads_core_get_stack_bounds (guint8 **staddr, size_t *stsize)
284 MEMORY_BASIC_INFORMATION meminfo;
287 NT_TIB* tib = (NT_TIB*)NtCurrentTeb();
288 guint8 *stackTop = (guint8*)tib->StackBase;
289 guint8 *stackBottom = (guint8*)tib->StackLimit;
291 /* http://en.wikipedia.org/wiki/Win32_Thread_Information_Block */
292 void* tib = (void*)__readfsdword(0x18);
293 guint8 *stackTop = (guint8*)*(int*)((char*)tib + 4);
294 guint8 *stackBottom = (guint8*)*(int*)((char*)tib + 8);
297 Windows stacks are expanded on demand, one page at time. The TIB reports
298 only the currently allocated amount.
299 VirtualQuery will return the actual limit for the bottom, which is what we want.
301 if (VirtualQuery (&meminfo, &meminfo, sizeof (meminfo)) == sizeof (meminfo))
302 stackBottom = MIN (stackBottom, (guint8*)meminfo.AllocationBase);
304 *staddr = stackBottom;
305 *stsize = stackTop - stackBottom;
310 mono_threads_core_yield (void)
312 return SwitchToThread ();
316 mono_threads_core_exit (int exit_code)
318 ExitThread (exit_code);
322 mono_threads_core_unregister (MonoThreadInfo *info)
327 mono_threads_core_open_handle (void)
329 HANDLE thread_handle;
331 thread_handle = GetCurrentThread ();
332 g_assert (thread_handle);
335 * The handle returned by GetCurrentThread () is a pseudo handle, so it can't be used to
336 * refer to the thread from other threads for things like aborting.
338 DuplicateHandle (GetCurrentProcess (), thread_handle, GetCurrentProcess (), &thread_handle,
339 THREAD_ALL_ACCESS, TRUE, 0);
341 return thread_handle;
345 mono_threads_get_max_stack_size (void)
352 mono_threads_core_open_thread_handle (HANDLE handle, MonoNativeThreadId tid)
354 return OpenThread (THREAD_ALL_ACCESS, TRUE, tid);
357 #if !defined(__GNUC__)
358 const DWORD MS_VC_EXCEPTION=0x406D1388;
360 typedef struct tagTHREADNAME_INFO
362 DWORD dwType; // Must be 0x1000.
363 LPCSTR szName; // Pointer to name (in user addr space).
364 DWORD dwThreadID; // Thread ID (-1=caller thread).
365 DWORD dwFlags; // Reserved for future use, must be zero.
371 mono_threads_core_set_name (MonoNativeThreadId tid, const char *name)
373 #if !defined(__GNUC__)
374 /* http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx */
375 THREADNAME_INFO info;
376 info.dwType = 0x1000;
378 info.dwThreadID = tid;
382 RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info );
384 __except(EXCEPTION_EXECUTE_HANDLER) {
391 mono_threads_core_prepare_interrupt (HANDLE thread_handle)
397 mono_threads_core_finish_interrupt (gpointer wait_handle)
402 mono_threads_core_self_interrupt (void)
407 mono_threads_core_clear_interruption (void)