2 * mono-threads-posix.c: Low-level threading, posix version
5 * Rodrigo Kumpera (kumpera@gmail.com)
12 #if defined(__OpenBSD__) || defined(__FreeBSD__)
14 #include <pthread_np.h>
17 #include <mono/utils/mono-compiler.h>
18 #include <mono/utils/mono-semaphore.h>
19 #include <mono/utils/mono-threads.h>
20 #include <mono/utils/mono-tls.h>
21 #include <mono/utils/mono-mmap.h>
22 #include <mono/metadata/threads-types.h>
26 #if defined(PLATFORM_ANDROID)
27 extern int tkill (pid_t tid, int signal);
30 #if defined(PLATFORM_MACOSX) && defined(HAVE_PTHREAD_GET_STACKADDR_NP)
31 void *pthread_get_stackaddr_np(pthread_t);
32 size_t pthread_get_stacksize_np(pthread_t);
35 #if defined(_POSIX_VERSION) || defined(__native_client__)
38 #if defined(__native_client__)
39 void nacl_shutdown_gc_thread(void);
43 void *(*start_routine)(void*);
46 MonoSemType registered;
51 inner_start_thread (void *arg)
53 StartInfo *start_info = arg;
54 void *t_arg = start_info->arg;
56 void *(*start_func)(void*) = start_info->start_routine;
57 guint32 flags = start_info->flags;
62 /* Register the thread with the io-layer */
63 handle = wapi_create_thread_handle ();
65 res = MONO_SEM_POST (&(start_info->registered));
69 start_info->handle = handle;
71 info = mono_thread_info_attach (&result);
72 info->runtime_thread = TRUE;
73 info->handle = handle;
75 if (flags & CREATE_SUSPENDED) {
76 info->create_suspended = TRUE;
77 MONO_SEM_INIT (&info->create_suspended_sem, 0);
80 /* start_info is not valid after this */
81 res = MONO_SEM_POST (&(start_info->registered));
85 if (flags & CREATE_SUSPENDED) {
86 while (MONO_SEM_WAIT (&info->create_suspended_sem) != 0 &&
88 MONO_SEM_DESTROY (&info->create_suspended_sem);
91 /* Run the actual main function of the thread */
92 result = start_func (t_arg);
95 mono_thread_info_dettach ();
98 #if defined(__native_client__)
99 nacl_shutdown_gc_thread();
102 wapi_thread_handle_set_exited (handle, GPOINTER_TO_UINT (result));
104 g_assert (mono_threads_get_callbacks ()->thread_exit);
105 mono_threads_get_callbacks ()->thread_exit (NULL);
106 g_assert_not_reached ();
111 mono_threads_core_create_thread (LPTHREAD_START_ROUTINE start_routine, gpointer arg, guint32 stack_size, guint32 creation_flags, MonoNativeThreadId *out_tid)
116 StartInfo start_info;
118 res = pthread_attr_init (&attr);
121 if (stack_size == 0) {
122 #if HAVE_VALGRIND_MEMCHECK_H
123 if (RUNNING_ON_VALGRIND)
124 stack_size = 1 << 20;
126 stack_size = (SIZEOF_VOID_P / 4) * 1024 * 1024;
128 stack_size = (SIZEOF_VOID_P / 4) * 1024 * 1024;
132 #ifdef PTHREAD_STACK_MIN
133 if (stack_size < PTHREAD_STACK_MIN)
134 stack_size = PTHREAD_STACK_MIN;
137 #ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE
138 res = pthread_attr_setstacksize (&attr, stack_size);
142 memset (&start_info, 0, sizeof (StartInfo));
143 start_info.start_routine = (gpointer)start_routine;
144 start_info.arg = arg;
145 start_info.flags = creation_flags;
146 MONO_SEM_INIT (&(start_info.registered), 0);
148 /* Actually start the thread */
149 res = mono_threads_get_callbacks ()->mono_gc_pthread_create (&thread, &attr, inner_start_thread, &start_info);
152 g_assert_not_reached ();
155 /* Wait until the thread register itself in various places */
156 while (MONO_SEM_WAIT (&(start_info.registered)) != 0) {
157 /*if (EINTR != errno) ABORT("sem_wait failed"); */
159 MONO_SEM_DESTROY (&(start_info.registered));
164 return start_info.handle;
168 * mono_threads_core_resume_created:
170 * Resume a newly created thread created using CREATE_SUSPENDED.
173 mono_threads_core_resume_created (MonoThreadInfo *info, MonoNativeThreadId tid)
175 MONO_SEM_POST (&info->create_suspended_sem);
179 mono_threads_core_get_stack_bounds (guint8 **staddr, size_t *stsize)
181 #if defined(HAVE_PTHREAD_GET_STACKSIZE_NP) && defined(HAVE_PTHREAD_GET_STACKADDR_NP)
183 *staddr = (guint8*)pthread_get_stackaddr_np (pthread_self());
184 *stsize = pthread_get_stacksize_np (pthread_self());
189 * Mavericks reports stack sizes as 512kb:
190 * http://permalink.gmane.org/gmane.comp.java.openjdk.hotspot.devel/11590
191 * https://bugs.openjdk.java.net/browse/JDK-8020753
193 if (*stsize == 512 * 1024)
194 *stsize = 2048 * mono_pagesize ();
197 /* staddr points to the start of the stack, not the end */
200 /* When running under emacs, sometimes staddr is not aligned to a page size */
201 *staddr = (guint8*)((gssize)*staddr & ~(mono_pagesize() - 1));
204 #elif (defined(HAVE_PTHREAD_GETATTR_NP) || defined(HAVE_PTHREAD_ATTR_GET_NP)) && defined(HAVE_PTHREAD_ATTR_GETSTACK)
208 guint8 *current = (guint8*)&attr;
211 *stsize = (size_t)-1;
213 pthread_attr_init (&attr);
215 #if defined(HAVE_PTHREAD_GETATTR_NP)
217 pthread_getattr_np (pthread_self(), &attr);
219 #elif defined(HAVE_PTHREAD_ATTR_GET_NP)
221 pthread_attr_get_np (pthread_self(), &attr);
224 #error Cannot determine which API is needed to retrieve pthread attributes.
227 pthread_attr_getstack (&attr, (void**)staddr, stsize);
228 pthread_attr_destroy (&attr);
231 g_assert ((current > *staddr) && (current < *staddr + *stsize));
233 /* When running under emacs, sometimes staddr is not aligned to a page size */
234 *staddr = (guint8*)((gssize)*staddr & ~(mono_pagesize () - 1));
237 #elif defined(__OpenBSD__)
239 /* TODO : Determine if this code is actually still needed. It may already be covered by the case above. */
242 guint8 *current = (guint8*)&attr;
245 *stsize = (size_t)-1;
247 pthread_attr_init (&attr);
252 rslt = pthread_stackseg_np(pthread_self(), &ss);
253 g_assert (rslt == 0);
255 *staddr = (guint8*)((size_t)ss.ss_sp - ss.ss_size);
256 *stsize = ss.ss_size;
258 pthread_attr_destroy (&attr);
261 g_assert ((current > *staddr) && (current < *staddr + *stsize));
263 /* When running under emacs, sometimes staddr is not aligned to a page size */
264 *staddr = (guint8*)((gssize)*staddr & ~(mono_pagesize () - 1));
267 #elif defined(sun) || defined(__native_client__)
268 /* Solaris/Illumos, NaCl */
270 pthread_attr_init (&attr);
271 pthread_attr_getstacksize (&attr, &stsize);
272 pthread_attr_destroy (&attr);
277 /* FIXME: It'd be better to use the 'error' preprocessor macro here so we know
278 at compile-time if the target platform isn't supported. */
279 #warning "Unable to determine how to retrieve a thread's stack-bounds for this platform in 'mono_thread_get_stack_bounds()'."
287 mono_threads_core_yield (void)
289 return sched_yield () == 0;
293 mono_threads_core_exit (int exit_code)
295 MonoThreadInfo *current = mono_thread_info_current ();
297 #if defined(__native_client__)
298 nacl_shutdown_gc_thread();
301 wapi_thread_handle_set_exited (current->handle, exit_code);
303 g_assert (mono_threads_get_callbacks ()->thread_exit);
304 mono_threads_get_callbacks ()->thread_exit (NULL);
307 #if !defined (__MACH__)
309 #if !defined(__native_client__)
311 suspend_signal_handler (int _dummy, siginfo_t *info, void *context)
313 MonoThreadInfo *current = mono_thread_info_current ();
316 if (current->syscall_break_signal) {
317 current->syscall_break_signal = FALSE;
321 ret = mono_threads_get_runtime_callbacks ()->thread_state_init_from_sigctx (¤t->suspend_state, context);
323 /* thread_state_init_from_sigctx return FALSE if the current thread is detaching and suspend can't continue. */
324 current->suspend_can_continue = ret;
326 MONO_SEM_POST (¤t->begin_suspend_semaphore);
328 /* This thread is doomed, all we can do is give up and let the suspender recover. */
332 while (MONO_SEM_WAIT (¤t->resume_semaphore) != 0) {
333 /*if (EINTR != errno) ABORT("sem_wait failed"); */
336 if (current->async_target) {
337 #if MONO_ARCH_HAS_MONO_CONTEXT
338 MonoContext tmp = current->suspend_state.ctx;
339 mono_threads_get_runtime_callbacks ()->setup_async_callback (&tmp, current->async_target, current->user_data);
340 current->async_target = current->user_data = NULL;
341 mono_monoctx_to_sigctx (&tmp, context);
343 g_error ("The new interruption machinery requires a working mono-context");
347 MONO_SEM_POST (¤t->finish_resume_semaphore);
352 mono_posix_add_signal_handler (int signo, gpointer handler)
354 #if !defined(__native_client__)
355 /*FIXME, move the code from mini to utils and do the right thing!*/
357 struct sigaction previous_sa;
360 sa.sa_sigaction = handler;
361 sigemptyset (&sa.sa_mask);
362 sa.sa_flags = SA_SIGINFO;
363 ret = sigaction (signo, &sa, &previous_sa);
365 g_assert (ret != -1);
370 mono_threads_init_platform (void)
372 #if !defined(__native_client__)
374 FIXME we should use all macros from mini to make this more portable
375 FIXME it would be very sweet if sgen could end up using this too.
377 if (mono_thread_info_new_interrupt_enabled ())
378 mono_posix_add_signal_handler (mono_thread_get_abort_signal (), suspend_signal_handler);
382 /*nothing to be done here since suspend always abort syscalls due using signals*/
384 mono_threads_core_interrupt (MonoThreadInfo *info)
389 mono_threads_pthread_kill (MonoThreadInfo *info, int signum)
391 #if defined (PLATFORM_ANDROID)
392 int result, old_errno = errno;
393 result = tkill (info->native_handle, signum);
399 #elif defined(__native_client__)
400 /* Workaround pthread_kill abort() in NaCl glibc. */
403 return pthread_kill (mono_thread_info_get_tid (info), signum);
409 mono_threads_core_abort_syscall (MonoThreadInfo *info)
412 We signal a thread to break it from the urrent syscall.
413 This signal should not be interpreted as a suspend request.
415 info->syscall_break_signal = TRUE;
416 mono_threads_pthread_kill (info, mono_thread_get_abort_signal ());
420 mono_threads_core_needs_abort_syscall (void)
426 mono_threads_core_suspend (MonoThreadInfo *info)
428 /*FIXME, check return value*/
429 mono_threads_pthread_kill (info, mono_thread_get_abort_signal ());
430 while (MONO_SEM_WAIT (&info->begin_suspend_semaphore) != 0) {
431 /* g_assert (errno == EINTR); */
433 return info->suspend_can_continue;
437 mono_threads_core_resume (MonoThreadInfo *info)
439 MONO_SEM_POST (&info->resume_semaphore);
440 while (MONO_SEM_WAIT (&info->finish_resume_semaphore) != 0) {
441 /* g_assert (errno == EINTR); */
448 mono_threads_platform_register (MonoThreadInfo *info)
450 MONO_SEM_INIT (&info->begin_suspend_semaphore, 0);
452 #if defined (PLATFORM_ANDROID)
453 info->native_handle = (gpointer) gettid ();
458 mono_threads_platform_free (MonoThreadInfo *info)
460 MONO_SEM_DESTROY (&info->begin_suspend_semaphore);
464 mono_native_thread_id_get (void)
466 return pthread_self ();
470 mono_native_thread_id_equals (MonoNativeThreadId id1, MonoNativeThreadId id2)
472 return pthread_equal (id1, id2);
476 * mono_native_thread_create:
478 * Low level thread creation function without any GC wrappers.
481 mono_native_thread_create (MonoNativeThreadId *tid, gpointer func, gpointer arg)
483 return pthread_create (tid, NULL, func, arg) == 0;
486 #endif /*!defined (__MACH__)*/