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>
19 mono_threads_init_platform (void)
24 interrupt_apc (ULONG_PTR param)
29 mono_threads_core_interrupt (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_abort_syscall (MonoThreadInfo *info)
48 mono_threads_core_needs_abort_syscall (void)
54 mono_threads_core_self_suspend (MonoThreadInfo *info)
56 g_assert_not_reached ();
60 mono_threads_core_suspend (MonoThreadInfo *info)
62 DWORD id = mono_thread_info_get_tid (info);
67 g_assert (id != GetCurrentThreadId ());
69 handle = OpenThread (THREAD_ALL_ACCESS, FALSE, id);
72 result = SuspendThread (handle);
73 if (result == (DWORD)-1) {
74 fprintf (stderr, "could not suspend thread %x (handle %p): %d\n", id, handle, GetLastError ()); fflush (stderr);
81 res = mono_threads_get_runtime_callbacks ()->thread_state_init_from_handle (&info->suspend_state, info);
88 mono_threads_core_resume (MonoThreadInfo *info)
90 DWORD id = mono_thread_info_get_tid (info);
94 handle = OpenThread (THREAD_ALL_ACCESS, FALSE, id);
97 if (info->async_target) {
102 ctx = info->suspend_state.ctx;
103 mono_threads_get_runtime_callbacks ()->setup_async_callback (&ctx, info->async_target, info->user_data);
104 info->async_target = info->user_data = NULL;
106 context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
108 if (!GetThreadContext (handle, &context)) {
109 CloseHandle (handle);
113 g_assert (context.ContextFlags & CONTEXT_INTEGER);
114 g_assert (context.ContextFlags & CONTEXT_CONTROL);
116 mono_monoctx_to_sigctx (&ctx, &context);
118 context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
119 res = SetThreadContext (handle, &context);
123 result = ResumeThread (handle);
124 g_assert (result != (DWORD)-1);
126 CloseHandle (handle);
128 return result != (DWORD)-1;
132 mono_threads_platform_register (MonoThreadInfo *info)
137 mono_threads_platform_free (MonoThreadInfo *info)
142 LPTHREAD_START_ROUTINE start_routine;
144 MonoSemType registered;
146 HANDLE suspend_event;
150 inner_start_thread (LPVOID arg)
152 ThreadStartInfo *start_info = arg;
153 void *t_arg = start_info->arg;
155 LPTHREAD_START_ROUTINE start_func = start_info->start_routine;
157 gboolean suspend = start_info->suspend;
158 HANDLE suspend_event = start_info->suspend_event;
159 MonoThreadInfo *info;
161 info = mono_thread_info_attach (&result);
162 info->runtime_thread = TRUE;
163 info->create_suspended = suspend;
165 post_result = MONO_SEM_POST (&(start_info->registered));
166 g_assert (!post_result);
169 WaitForSingleObject (suspend_event, INFINITE); /* caller will suspend the thread before setting the event. */
170 CloseHandle (suspend_event);
173 result = start_func (t_arg);
175 mono_thread_info_detach ();
181 mono_threads_core_create_thread (LPTHREAD_START_ROUTINE start_routine, gpointer arg, guint32 stack_size, guint32 creation_flags, MonoNativeThreadId *out_tid)
183 ThreadStartInfo *start_info;
187 start_info = g_malloc0 (sizeof (ThreadStartInfo));
190 MONO_SEM_INIT (&(start_info->registered), 0);
191 start_info->arg = arg;
192 start_info->start_routine = start_routine;
193 start_info->suspend = creation_flags & CREATE_SUSPENDED;
194 creation_flags &= ~CREATE_SUSPENDED;
195 if (start_info->suspend) {
196 start_info->suspend_event = CreateEvent (NULL, TRUE, FALSE, NULL);
197 if (!start_info->suspend_event)
201 result = CreateThread (NULL, stack_size, inner_start_thread, start_info, creation_flags, &thread_id);
203 while (MONO_SEM_WAIT (&(start_info->registered)) != 0) {
204 /*if (EINTR != errno) ABORT("sem_wait failed"); */
206 if (start_info->suspend) {
207 g_assert (SuspendThread (result) != (DWORD)-1);
208 SetEvent (start_info->suspend_event);
210 } else if (start_info->suspend) {
211 CloseHandle (start_info->suspend_event);
214 *out_tid = thread_id;
215 MONO_SEM_DESTROY (&(start_info->registered));
222 mono_native_thread_id_get (void)
224 return GetCurrentThreadId ();
228 mono_native_thread_id_equals (MonoNativeThreadId id1, MonoNativeThreadId id2)
234 mono_native_thread_create (MonoNativeThreadId *tid, gpointer func, gpointer arg)
236 return CreateThread (NULL, 0, (func), (arg), 0, (tid)) != NULL;
240 mono_threads_core_resume_created (MonoThreadInfo *info, MonoNativeThreadId tid)
244 handle = OpenThread (THREAD_ALL_ACCESS, TRUE, tid);
246 ResumeThread (handle);
247 CloseHandle (handle);
250 #if HAVE_DECL___READFSDWORD==0
251 static __inline__ __attribute__((always_inline))
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) {