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 mono_threads_core_interrupt (MonoThreadInfo *info)
30 mono_threads_core_abort_syscall (MonoThreadInfo *info)
35 mono_threads_core_needs_abort_syscall (void)
41 mono_threads_core_self_suspend (MonoThreadInfo *info)
43 g_assert_not_reached ();
47 mono_threads_core_suspend (MonoThreadInfo *info)
49 g_assert_not_reached ();
53 mono_threads_core_resume (MonoThreadInfo *info)
55 g_assert_not_reached ();
59 mono_threads_platform_register (MonoThreadInfo *info)
64 mono_threads_platform_free (MonoThreadInfo *info)
69 LPTHREAD_START_ROUTINE start_routine;
71 MonoSemType registered;
77 inner_start_thread (LPVOID arg)
79 ThreadStartInfo *start_info = arg;
80 void *t_arg = start_info->arg;
82 LPTHREAD_START_ROUTINE start_func = start_info->start_routine;
84 gboolean suspend = start_info->suspend;
85 HANDLE suspend_event = start_info->suspend_event;
88 info = mono_thread_info_attach (&result);
89 info->runtime_thread = TRUE;
90 info->create_suspended = suspend;
92 post_result = MONO_SEM_POST (&(start_info->registered));
93 g_assert (!post_result);
96 WaitForSingleObject (suspend_event, INFINITE); /* caller will suspend the thread before setting the event. */
97 CloseHandle (suspend_event);
100 result = start_func (t_arg);
102 mono_thread_info_detach ();
108 mono_threads_core_create_thread (LPTHREAD_START_ROUTINE start_routine, gpointer arg, guint32 stack_size, guint32 creation_flags, MonoNativeThreadId *out_tid)
110 ThreadStartInfo *start_info;
114 start_info = g_malloc0 (sizeof (ThreadStartInfo));
117 MONO_SEM_INIT (&(start_info->registered), 0);
118 start_info->arg = arg;
119 start_info->start_routine = start_routine;
120 start_info->suspend = creation_flags & CREATE_SUSPENDED;
121 creation_flags &= ~CREATE_SUSPENDED;
122 if (start_info->suspend) {
123 start_info->suspend_event = CreateEvent (NULL, TRUE, FALSE, NULL);
124 if (!start_info->suspend_event)
128 result = CreateThread (NULL, stack_size, inner_start_thread, start_info, creation_flags, &thread_id);
130 while (MONO_SEM_WAIT (&(start_info->registered)) != 0) {
131 /*if (EINTR != errno) ABORT("sem_wait failed"); */
133 if (start_info->suspend) {
134 g_assert (SuspendThread (result) != (DWORD)-1);
135 SetEvent (start_info->suspend_event);
137 } else if (start_info->suspend) {
138 CloseHandle (start_info->suspend_event);
141 *out_tid = thread_id;
142 MONO_SEM_DESTROY (&(start_info->registered));
149 mono_native_thread_id_get (void)
151 return GetCurrentThreadId ();
155 mono_native_thread_id_equals (MonoNativeThreadId id1, MonoNativeThreadId id2)
161 mono_native_thread_create (MonoNativeThreadId *tid, gpointer func, gpointer arg)
163 return CreateThread (NULL, 0, (func), (arg), 0, (tid)) != NULL;
167 mono_threads_core_resume_created (MonoThreadInfo *info, MonoNativeThreadId tid)
171 handle = OpenThread (THREAD_ALL_ACCESS, TRUE, tid);
173 ResumeThread (handle);
174 CloseHandle (handle);
177 #if HAVE_DECL___READFSDWORD==0
178 static __inline__ __attribute__((always_inline))
180 __readfsdword (unsigned long offset)
183 // __asm__("movl %%fs:%a[offset], %k[value]" : [value] "=q" (value) : [offset] "irm" (offset));
184 __asm__ volatile ("movl %%fs:%1,%0"
185 : "=r" (value) ,"=m" ((*(volatile long *) offset)));
191 mono_threads_core_get_stack_bounds (guint8 **staddr, size_t *stsize)
193 MEMORY_BASIC_INFORMATION meminfo;
196 NT_TIB* tib = (NT_TIB*)NtCurrentTeb();
197 guint8 *stackTop = (guint8*)tib->StackBase;
198 guint8 *stackBottom = (guint8*)tib->StackLimit;
200 /* http://en.wikipedia.org/wiki/Win32_Thread_Information_Block */
201 void* tib = (void*)__readfsdword(0x18);
202 guint8 *stackTop = (guint8*)*(int*)((char*)tib + 4);
203 guint8 *stackBottom = (guint8*)*(int*)((char*)tib + 8);
206 Windows stacks are expanded on demand, one page at time. The TIB reports
207 only the currently allocated amount.
208 VirtualQuery will return the actual limit for the bottom, which is what we want.
210 if (VirtualQuery (&meminfo, &meminfo, sizeof (meminfo)) == sizeof (meminfo))
211 stackBottom = MIN (stackBottom, (guint8*)meminfo.AllocationBase);
213 *staddr = stackBottom;
214 *stsize = stackTop - stackBottom;
219 mono_threads_core_yield (void)
221 return SwitchToThread ();
225 mono_threads_core_exit (int exit_code)
227 ExitThread (exit_code);
231 mono_threads_core_unregister (MonoThreadInfo *info)
236 mono_threads_core_open_handle (void)
238 HANDLE thread_handle;
240 thread_handle = GetCurrentThread ();
241 g_assert (thread_handle);
244 * The handle returned by GetCurrentThread () is a pseudo handle, so it can't be used to
245 * refer to the thread from other threads for things like aborting.
247 DuplicateHandle (GetCurrentProcess (), thread_handle, GetCurrentProcess (), &thread_handle,
248 THREAD_ALL_ACCESS, TRUE, 0);
250 return thread_handle;
254 mono_threads_get_max_stack_size (void)
261 mono_threads_core_open_thread_handle (HANDLE handle, MonoNativeThreadId tid)
263 return OpenThread (THREAD_ALL_ACCESS, TRUE, tid);
267 mono_threads_core_set_name (MonoNativeThreadId tid, const char *name)