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_interrupt (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)
49 mono_threads_core_needs_abort_syscall (void)
55 mono_threads_core_self_suspend (MonoThreadInfo *info)
57 g_assert_not_reached ();
61 mono_threads_core_suspend (MonoThreadInfo *info)
63 DWORD id = mono_thread_info_get_tid (info);
68 g_assert (id != GetCurrentThreadId ());
70 handle = OpenThread (THREAD_ALL_ACCESS, FALSE, id);
73 result = SuspendThread (handle);
74 if (result == (DWORD)-1) {
75 fprintf (stderr, "could not suspend thread %x (handle %p): %d\n", id, handle, GetLastError ()); fflush (stderr);
82 res = mono_threads_get_runtime_callbacks ()->thread_state_init_from_handle (&info->suspend_state, info);
89 mono_threads_core_resume (MonoThreadInfo *info)
91 DWORD id = mono_thread_info_get_tid (info);
95 handle = OpenThread (THREAD_ALL_ACCESS, FALSE, id);
98 if (info->async_target) {
103 ctx = info->suspend_state.ctx;
104 mono_threads_get_runtime_callbacks ()->setup_async_callback (&ctx, info->async_target, info->user_data);
105 info->async_target = info->user_data = NULL;
107 context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
109 if (!GetThreadContext (handle, &context)) {
110 CloseHandle (handle);
114 g_assert (context.ContextFlags & CONTEXT_INTEGER);
115 g_assert (context.ContextFlags & CONTEXT_CONTROL);
117 mono_monoctx_to_sigctx (&ctx, &context);
119 context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
120 res = SetThreadContext (handle, &context);
124 result = ResumeThread (handle);
125 g_assert (result != (DWORD)-1);
127 CloseHandle (handle);
129 return result != (DWORD)-1;
133 mono_threads_platform_register (MonoThreadInfo *info)
138 mono_threads_platform_free (MonoThreadInfo *info)
143 LPTHREAD_START_ROUTINE start_routine;
145 MonoSemType registered;
147 HANDLE suspend_event;
151 inner_start_thread (LPVOID arg)
153 ThreadStartInfo *start_info = arg;
154 void *t_arg = start_info->arg;
156 LPTHREAD_START_ROUTINE start_func = start_info->start_routine;
158 gboolean suspend = start_info->suspend;
159 HANDLE suspend_event = start_info->suspend_event;
160 MonoThreadInfo *info;
162 info = mono_thread_info_attach (&result);
163 info->runtime_thread = TRUE;
164 info->create_suspended = suspend;
166 post_result = MONO_SEM_POST (&(start_info->registered));
167 g_assert (!post_result);
170 WaitForSingleObject (suspend_event, INFINITE); /* caller will suspend the thread before setting the event. */
171 CloseHandle (suspend_event);
174 result = start_func (t_arg);
176 mono_thread_info_detach ();
182 mono_threads_core_create_thread (LPTHREAD_START_ROUTINE start_routine, gpointer arg, guint32 stack_size, guint32 creation_flags, MonoNativeThreadId *out_tid)
184 ThreadStartInfo *start_info;
188 start_info = g_malloc0 (sizeof (ThreadStartInfo));
191 MONO_SEM_INIT (&(start_info->registered), 0);
192 start_info->arg = arg;
193 start_info->start_routine = start_routine;
194 start_info->suspend = creation_flags & CREATE_SUSPENDED;
195 creation_flags &= ~CREATE_SUSPENDED;
196 if (start_info->suspend) {
197 start_info->suspend_event = CreateEvent (NULL, TRUE, FALSE, NULL);
198 if (!start_info->suspend_event)
202 result = CreateThread (NULL, stack_size, inner_start_thread, start_info, creation_flags, &thread_id);
204 while (MONO_SEM_WAIT (&(start_info->registered)) != 0) {
205 /*if (EINTR != errno) ABORT("sem_wait failed"); */
207 if (start_info->suspend) {
208 g_assert (SuspendThread (result) != (DWORD)-1);
209 SetEvent (start_info->suspend_event);
211 } else if (start_info->suspend) {
212 CloseHandle (start_info->suspend_event);
215 *out_tid = thread_id;
216 MONO_SEM_DESTROY (&(start_info->registered));
223 mono_native_thread_id_get (void)
225 return GetCurrentThreadId ();
229 mono_native_thread_id_equals (MonoNativeThreadId id1, MonoNativeThreadId id2)
235 mono_native_thread_create (MonoNativeThreadId *tid, gpointer func, gpointer arg)
237 return CreateThread (NULL, 0, (func), (arg), 0, (tid)) != NULL;
241 mono_threads_core_resume_created (MonoThreadInfo *info, MonoNativeThreadId tid)
245 handle = OpenThread (THREAD_ALL_ACCESS, TRUE, tid);
247 ResumeThread (handle);
248 CloseHandle (handle);
251 #if HAVE_DECL___READFSDWORD==0
252 static MONO_ALWAYS_INLINE unsigned long long
253 __readfsdword (unsigned long offset)
256 // __asm__("movl %%fs:%a[offset], %k[value]" : [value] "=q" (value) : [offset] "irm" (offset));
257 __asm__ volatile ("movl %%fs:%1,%0"
258 : "=r" (value) ,"=m" ((*(volatile long *) offset)));
264 mono_threads_core_get_stack_bounds (guint8 **staddr, size_t *stsize)
266 MEMORY_BASIC_INFORMATION meminfo;
269 NT_TIB* tib = (NT_TIB*)NtCurrentTeb();
270 guint8 *stackTop = (guint8*)tib->StackBase;
271 guint8 *stackBottom = (guint8*)tib->StackLimit;
273 /* http://en.wikipedia.org/wiki/Win32_Thread_Information_Block */
274 void* tib = (void*)__readfsdword(0x18);
275 guint8 *stackTop = (guint8*)*(int*)((char*)tib + 4);
276 guint8 *stackBottom = (guint8*)*(int*)((char*)tib + 8);
279 Windows stacks are expanded on demand, one page at time. The TIB reports
280 only the currently allocated amount.
281 VirtualQuery will return the actual limit for the bottom, which is what we want.
283 if (VirtualQuery (&meminfo, &meminfo, sizeof (meminfo)) == sizeof (meminfo))
284 stackBottom = MIN (stackBottom, (guint8*)meminfo.AllocationBase);
286 *staddr = stackBottom;
287 *stsize = stackTop - stackBottom;
292 mono_threads_core_yield (void)
294 return SwitchToThread ();
298 mono_threads_core_exit (int exit_code)
300 ExitThread (exit_code);
304 mono_threads_core_unregister (MonoThreadInfo *info)
309 mono_threads_core_open_handle (void)
311 HANDLE thread_handle;
313 thread_handle = GetCurrentThread ();
314 g_assert (thread_handle);
317 * The handle returned by GetCurrentThread () is a pseudo handle, so it can't be used to
318 * refer to the thread from other threads for things like aborting.
320 DuplicateHandle (GetCurrentProcess (), thread_handle, GetCurrentProcess (), &thread_handle,
321 THREAD_ALL_ACCESS, TRUE, 0);
323 return thread_handle;
327 mono_threads_get_max_stack_size (void)
334 mono_threads_core_open_thread_handle (HANDLE handle, MonoNativeThreadId tid)
336 return OpenThread (THREAD_ALL_ACCESS, TRUE, tid);
339 #if !defined(__GNUC__)
340 const DWORD MS_VC_EXCEPTION=0x406D1388;
342 typedef struct tagTHREADNAME_INFO
344 DWORD dwType; // Must be 0x1000.
345 LPCSTR szName; // Pointer to name (in user addr space).
346 DWORD dwThreadID; // Thread ID (-1=caller thread).
347 DWORD dwFlags; // Reserved for future use, must be zero.
353 mono_threads_core_set_name (MonoNativeThreadId tid, const char *name)
355 #if !defined(__GNUC__)
356 /* http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx */
357 THREADNAME_INFO info;
358 info.dwType = 0x1000;
360 info.dwThreadID = tid;
364 RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info );
366 __except(EXCEPTION_EXECUTE_HANDLER) {