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_interrupt (MonoThreadInfo *info)
45 mono_threads_core_abort_syscall (info);
49 mono_threads_core_needs_abort_syscall (void)
55 mono_threads_core_begin_async_suspend (MonoThreadInfo *info, gboolean interrupt_kernel)
57 DWORD id = mono_thread_info_get_tid (info);
62 handle = OpenThread (THREAD_ALL_ACCESS, FALSE, id);
65 result = SuspendThread (handle);
66 THREADS_SUSPEND_DEBUG ("SUSPEND %p -> %d\n", (void*)id, ret);
67 if (result == (DWORD)-1) {
72 /* We're in the middle of a self-suspend, resume and register */
73 if (!mono_threads_transition_finish_async_suspend (info)) {
74 mono_threads_add_to_pending_operation_set (info);
75 result = ResumeThread (handle);
76 g_assert (result == 1);
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 result = ResumeThread (handle);
91 g_assert (result == 1);
92 THREADS_SUSPEND_DEBUG ("FAILSAFE RESUME/2 %p -> %d\n", (void*)info->native_handle, 0);
100 mono_threads_core_check_suspend_result (MonoThreadInfo *info)
106 mono_threads_core_begin_async_resume (MonoThreadInfo *info)
108 DWORD id = mono_thread_info_get_tid (info);
112 handle = OpenThread (THREAD_ALL_ACCESS, FALSE, id);
115 if (info->async_target) {
120 ctx = info->thread_saved_state [ASYNC_SUSPEND_STATE_INDEX].ctx;
121 mono_threads_get_runtime_callbacks ()->setup_async_callback (&ctx, info->async_target, info->user_data);
122 info->async_target = info->user_data = NULL;
124 context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
126 if (!GetThreadContext (handle, &context)) {
127 CloseHandle (handle);
131 g_assert (context.ContextFlags & CONTEXT_INTEGER);
132 g_assert (context.ContextFlags & CONTEXT_CONTROL);
134 mono_monoctx_to_sigctx (&ctx, &context);
136 context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
137 res = SetThreadContext (handle, &context);
139 CloseHandle (handle);
144 result = ResumeThread (handle);
145 CloseHandle (handle);
147 return result != (DWORD)-1;
152 mono_threads_platform_register (MonoThreadInfo *info)
157 mono_threads_platform_free (MonoThreadInfo *info)
162 LPTHREAD_START_ROUTINE start_routine;
164 MonoSemType registered;
166 HANDLE suspend_event;
170 inner_start_thread (LPVOID arg)
172 ThreadStartInfo *start_info = arg;
173 void *t_arg = start_info->arg;
175 LPTHREAD_START_ROUTINE start_func = start_info->start_routine;
177 gboolean suspend = start_info->suspend;
178 HANDLE suspend_event = start_info->suspend_event;
179 MonoThreadInfo *info;
181 info = mono_thread_info_attach (&result);
182 info->runtime_thread = TRUE;
183 info->create_suspended = suspend;
185 post_result = MONO_SEM_POST (&(start_info->registered));
186 g_assert (!post_result);
189 WaitForSingleObject (suspend_event, INFINITE); /* caller will suspend the thread before setting the event. */
190 CloseHandle (suspend_event);
193 result = start_func (t_arg);
195 mono_thread_info_detach ();
201 mono_threads_core_create_thread (LPTHREAD_START_ROUTINE start_routine, gpointer arg, guint32 stack_size, guint32 creation_flags, MonoNativeThreadId *out_tid)
203 ThreadStartInfo *start_info;
207 start_info = g_malloc0 (sizeof (ThreadStartInfo));
210 MONO_SEM_INIT (&(start_info->registered), 0);
211 start_info->arg = arg;
212 start_info->start_routine = start_routine;
213 start_info->suspend = creation_flags & CREATE_SUSPENDED;
214 creation_flags &= ~CREATE_SUSPENDED;
215 if (start_info->suspend) {
216 start_info->suspend_event = CreateEvent (NULL, TRUE, FALSE, NULL);
217 if (!start_info->suspend_event)
221 result = CreateThread (NULL, stack_size, inner_start_thread, start_info, creation_flags, &thread_id);
223 while (MONO_SEM_WAIT (&(start_info->registered)) != 0) {
224 /*if (EINTR != errno) ABORT("sem_wait failed"); */
226 if (start_info->suspend) {
227 g_assert (SuspendThread (result) != (DWORD)-1);
228 SetEvent (start_info->suspend_event);
230 } else if (start_info->suspend) {
231 CloseHandle (start_info->suspend_event);
234 *out_tid = thread_id;
235 MONO_SEM_DESTROY (&(start_info->registered));
242 mono_native_thread_id_get (void)
244 return GetCurrentThreadId ();
248 mono_native_thread_id_equals (MonoNativeThreadId id1, MonoNativeThreadId id2)
254 mono_native_thread_create (MonoNativeThreadId *tid, gpointer func, gpointer arg)
256 return CreateThread (NULL, 0, (func), (arg), 0, (tid)) != NULL;
260 mono_threads_core_resume_created (MonoThreadInfo *info, MonoNativeThreadId tid)
264 handle = OpenThread (THREAD_ALL_ACCESS, TRUE, tid);
266 ResumeThread (handle);
267 CloseHandle (handle);
270 #if HAVE_DECL___READFSDWORD==0
271 static MONO_ALWAYS_INLINE unsigned long long
272 __readfsdword (unsigned long offset)
275 // __asm__("movl %%fs:%a[offset], %k[value]" : [value] "=q" (value) : [offset] "irm" (offset));
276 __asm__ volatile ("movl %%fs:%1,%0"
277 : "=r" (value) ,"=m" ((*(volatile long *) offset)));
283 mono_threads_core_get_stack_bounds (guint8 **staddr, size_t *stsize)
285 MEMORY_BASIC_INFORMATION meminfo;
288 NT_TIB* tib = (NT_TIB*)NtCurrentTeb();
289 guint8 *stackTop = (guint8*)tib->StackBase;
290 guint8 *stackBottom = (guint8*)tib->StackLimit;
292 /* http://en.wikipedia.org/wiki/Win32_Thread_Information_Block */
293 void* tib = (void*)__readfsdword(0x18);
294 guint8 *stackTop = (guint8*)*(int*)((char*)tib + 4);
295 guint8 *stackBottom = (guint8*)*(int*)((char*)tib + 8);
298 Windows stacks are expanded on demand, one page at time. The TIB reports
299 only the currently allocated amount.
300 VirtualQuery will return the actual limit for the bottom, which is what we want.
302 if (VirtualQuery (&meminfo, &meminfo, sizeof (meminfo)) == sizeof (meminfo))
303 stackBottom = MIN (stackBottom, (guint8*)meminfo.AllocationBase);
305 *staddr = stackBottom;
306 *stsize = stackTop - stackBottom;
311 mono_threads_core_yield (void)
313 return SwitchToThread ();
317 mono_threads_core_exit (int exit_code)
319 ExitThread (exit_code);
323 mono_threads_core_unregister (MonoThreadInfo *info)
328 mono_threads_core_open_handle (void)
330 HANDLE thread_handle;
332 thread_handle = GetCurrentThread ();
333 g_assert (thread_handle);
336 * The handle returned by GetCurrentThread () is a pseudo handle, so it can't be used to
337 * refer to the thread from other threads for things like aborting.
339 DuplicateHandle (GetCurrentProcess (), thread_handle, GetCurrentProcess (), &thread_handle,
340 THREAD_ALL_ACCESS, TRUE, 0);
342 return thread_handle;
346 mono_threads_get_max_stack_size (void)
353 mono_threads_core_open_thread_handle (HANDLE handle, MonoNativeThreadId tid)
355 return OpenThread (THREAD_ALL_ACCESS, TRUE, tid);
358 #if defined(_MSC_VER)
359 const DWORD MS_VC_EXCEPTION=0x406D1388;
361 typedef struct tagTHREADNAME_INFO
363 DWORD dwType; // Must be 0x1000.
364 LPCSTR szName; // Pointer to name (in user addr space).
365 DWORD dwThreadID; // Thread ID (-1=caller thread).
366 DWORD dwFlags; // Reserved for future use, must be zero.
372 mono_threads_core_set_name (MonoNativeThreadId tid, const char *name)
374 #if defined(_MSC_VER)
375 /* http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx */
376 THREADNAME_INFO info;
377 info.dwType = 0x1000;
379 info.dwThreadID = tid;
383 RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info );
385 __except(EXCEPTION_EXECUTE_HANDLER) {
392 mono_threads_core_prepare_interrupt (HANDLE thread_handle)
398 mono_threads_core_finish_interrupt (gpointer wait_handle)
403 mono_threads_core_self_interrupt (void)
408 mono_threads_core_clear_interruption (void)