2 * mono-threads-posix.c: Low-level threading, posix version
5 * Rodrigo Kumpera (kumpera@gmail.com)
12 #include <mono/utils/mono-compiler.h>
13 #include <mono/utils/mono-semaphore.h>
14 #include <mono/utils/mono-threads.h>
15 #include <mono/utils/mono-tls.h>
16 #include <mono/utils/mono-mmap.h>
21 #if defined(PLATFORM_ANDROID) && !defined(TARGET_ARM64)
22 #define USE_TKILL_ON_ANDROID 1
25 #ifdef USE_TKILL_ON_ANDROID
26 extern int tkill (pid_t tid, int signal);
29 #if defined(_POSIX_VERSION) || defined(__native_client__)
30 #include <sys/resource.h>
33 #if defined(__native_client__)
34 void nacl_shutdown_gc_thread(void);
38 void *(*start_routine)(void*);
41 MonoSemType registered;
45 #ifdef PLATFORM_ANDROID
46 static int no_interrupt_signo;
50 inner_start_thread (void *arg)
52 StartInfo *start_info = arg;
53 void *t_arg = start_info->arg;
55 void *(*start_func)(void*) = start_info->start_routine;
56 guint32 flags = start_info->flags;
61 /* Register the thread with the io-layer */
62 handle = wapi_create_thread_handle ();
64 res = MONO_SEM_POST (&(start_info->registered));
68 start_info->handle = handle;
70 info = mono_thread_info_attach (&result);
71 info->runtime_thread = TRUE;
72 info->handle = handle;
74 if (flags & CREATE_SUSPENDED) {
75 info->create_suspended = TRUE;
76 MONO_SEM_INIT (&info->create_suspended_sem, 0);
79 /* start_info is not valid after this */
80 res = MONO_SEM_POST (&(start_info->registered));
84 if (flags & CREATE_SUSPENDED) {
85 while (MONO_SEM_WAIT (&info->create_suspended_sem) != 0 &&
87 MONO_SEM_DESTROY (&info->create_suspended_sem);
90 /* Run the actual main function of the thread */
91 result = start_func (t_arg);
94 mono_thread_info_detach ();
97 #if defined(__native_client__)
98 nacl_shutdown_gc_thread();
101 wapi_thread_handle_set_exited (handle, GPOINTER_TO_UINT (result));
102 /* This is needed by mono_threads_core_unregister () which is called later */
105 g_assert (mono_threads_get_callbacks ()->thread_exit);
106 mono_threads_get_callbacks ()->thread_exit (NULL);
107 g_assert_not_reached ();
112 mono_threads_core_create_thread (LPTHREAD_START_ROUTINE start_routine, gpointer arg, guint32 stack_size, guint32 creation_flags, MonoNativeThreadId *out_tid)
117 StartInfo start_info;
119 res = pthread_attr_init (&attr);
122 if (stack_size == 0) {
123 #if HAVE_VALGRIND_MEMCHECK_H
124 if (RUNNING_ON_VALGRIND)
125 stack_size = 1 << 20;
127 stack_size = (SIZEOF_VOID_P / 4) * 1024 * 1024;
129 stack_size = (SIZEOF_VOID_P / 4) * 1024 * 1024;
133 #ifdef PTHREAD_STACK_MIN
134 if (stack_size < PTHREAD_STACK_MIN)
135 stack_size = PTHREAD_STACK_MIN;
138 #ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE
139 res = pthread_attr_setstacksize (&attr, stack_size);
143 memset (&start_info, 0, sizeof (StartInfo));
144 start_info.start_routine = (gpointer)start_routine;
145 start_info.arg = arg;
146 start_info.flags = creation_flags;
147 MONO_SEM_INIT (&(start_info.registered), 0);
149 /* Actually start the thread */
150 res = mono_threads_get_callbacks ()->mono_gc_pthread_create (&thread, &attr, inner_start_thread, &start_info);
152 MONO_SEM_DESTROY (&(start_info.registered));
156 /* Wait until the thread register itself in various places */
157 while (MONO_SEM_WAIT (&(start_info.registered)) != 0) {
158 /*if (EINTR != errno) ABORT("sem_wait failed"); */
160 MONO_SEM_DESTROY (&(start_info.registered));
165 return start_info.handle;
169 * mono_threads_core_resume_created:
171 * Resume a newly created thread created using CREATE_SUSPENDED.
174 mono_threads_core_resume_created (MonoThreadInfo *info, MonoNativeThreadId tid)
176 MONO_SEM_POST (&info->create_suspended_sem);
180 mono_threads_core_yield (void)
182 return sched_yield () == 0;
186 mono_threads_core_exit (int exit_code)
188 MonoThreadInfo *current = mono_thread_info_current ();
190 #if defined(__native_client__)
191 nacl_shutdown_gc_thread();
194 wapi_thread_handle_set_exited (current->handle, exit_code);
196 g_assert (mono_threads_get_callbacks ()->thread_exit);
197 mono_threads_get_callbacks ()->thread_exit (NULL);
201 mono_threads_core_unregister (MonoThreadInfo *info)
204 wapi_thread_handle_set_exited (info->handle, 0);
210 mono_threads_core_open_handle (void)
212 MonoThreadInfo *info;
214 info = mono_thread_info_current ();
218 info->handle = wapi_create_thread_handle ();
220 wapi_ref_thread_handle (info->handle);
225 mono_threads_get_max_stack_size (void)
229 /* If getrlimit fails, we don't enforce any limits. */
230 if (getrlimit (RLIMIT_STACK, &lim))
232 /* rlim_t is an unsigned long long on 64bits OSX but we want an int response. */
233 if (lim.rlim_max > (rlim_t)INT_MAX)
235 return (int)lim.rlim_max;
239 mono_threads_core_open_thread_handle (HANDLE handle, MonoNativeThreadId tid)
241 wapi_ref_thread_handle (handle);
247 mono_threads_core_prepare_interrupt (HANDLE thread_handle)
249 return wapi_prepare_interrupt_thread (thread_handle);
253 mono_threads_core_finish_interrupt (gpointer wait_handle)
255 wapi_finish_interrupt_thread (wait_handle);
259 mono_threads_core_self_interrupt (void)
261 wapi_self_interrupt ();
265 mono_threads_core_clear_interruption (void)
267 wapi_clear_interruption ();
271 mono_threads_pthread_kill (MonoThreadInfo *info, int signum)
273 #ifdef USE_TKILL_ON_ANDROID
274 int result, old_errno = errno;
275 result = tkill (info->native_handle, signum);
281 #elif defined(__native_client__)
282 /* Workaround pthread_kill abort() in NaCl glibc. */
285 return pthread_kill (mono_thread_info_get_tid (info), signum);
290 #if !defined (__MACH__)
292 #if !defined(__native_client__)
294 suspend_signal_handler (int _dummy, siginfo_t *info, void *context)
296 MonoThreadInfo *current = mono_thread_info_current ();
299 if (current->syscall_break_signal) {
300 current->syscall_break_signal = FALSE;
304 ret = mono_threads_get_runtime_callbacks ()->thread_state_init_from_sigctx (¤t->suspend_state, context);
306 /* thread_state_init_from_sigctx return FALSE if the current thread is detaching and suspend can't continue. */
307 current->suspend_can_continue = ret;
309 MONO_SEM_POST (¤t->begin_suspend_semaphore);
311 /* This thread is doomed, all we can do is give up and let the suspender recover. */
315 while (MONO_SEM_WAIT (¤t->resume_semaphore) != 0) {
316 /*if (EINTR != errno) ABORT("sem_wait failed"); */
319 if (current->async_target) {
320 #if MONO_ARCH_HAS_MONO_CONTEXT
321 MonoContext tmp = current->suspend_state.ctx;
322 mono_threads_get_runtime_callbacks ()->setup_async_callback (&tmp, current->async_target, current->user_data);
323 current->async_target = current->user_data = NULL;
324 mono_monoctx_to_sigctx (&tmp, context);
326 g_error ("The new interruption machinery requires a working mono-context");
330 MONO_SEM_POST (¤t->finish_resume_semaphore);
335 mono_posix_add_signal_handler (int signo, gpointer handler, int flags)
337 #if !defined(__native_client__)
338 /*FIXME, move the code from mini to utils and do the right thing!*/
340 struct sigaction previous_sa;
343 sa.sa_sigaction = handler;
344 sigemptyset (&sa.sa_mask);
345 sa.sa_flags = SA_SIGINFO | flags;
346 ret = sigaction (signo, &sa, &previous_sa);
348 g_assert (ret != -1);
353 mono_threads_init_platform (void)
355 #if !defined(__native_client__)
359 FIXME we should use all macros from mini to make this more portable
360 FIXME it would be very sweet if sgen could end up using this too.
362 if (!mono_thread_info_new_interrupt_enabled ())
364 abort_signo = mono_thread_get_abort_signal ();
365 mono_posix_add_signal_handler (abort_signo, suspend_signal_handler, 0);
367 #ifdef PLATFORM_ANDROID
369 * Lots of android native code can't handle the EINTR caused by
370 * the normal abort signal, so use a different signal for the
371 * no interruption case, which is used by sdb.
372 * FIXME: Use this on all platforms.
373 * SIGUSR1 is used by dalvik/art.
375 no_interrupt_signo = SIGUSR2;
376 g_assert (abort_signo != no_interrupt_signo);
377 mono_posix_add_signal_handler (no_interrupt_signo, suspend_signal_handler, SA_RESTART);
383 mono_threads_core_interrupt (MonoThreadInfo *info)
385 /* Handled in mono_threads_core_suspend () */
389 mono_threads_core_abort_syscall (MonoThreadInfo *info)
392 We signal a thread to break it from the urrent syscall.
393 This signal should not be interpreted as a suspend request.
395 info->syscall_break_signal = TRUE;
396 mono_threads_pthread_kill (info, mono_thread_get_abort_signal ());
400 mono_threads_core_needs_abort_syscall (void)
406 mono_threads_core_suspend (MonoThreadInfo *info, gboolean interrupt_kernel)
408 /*FIXME, check return value*/
409 #ifdef PLATFORM_ANDROID
410 if (!interrupt_kernel)
411 mono_threads_pthread_kill (info, no_interrupt_signo);
413 mono_threads_pthread_kill (info, mono_thread_get_abort_signal ());
415 mono_threads_pthread_kill (info, mono_thread_get_abort_signal ());
417 while (MONO_SEM_WAIT (&info->begin_suspend_semaphore) != 0) {
418 /* g_assert (errno == EINTR); */
420 return info->suspend_can_continue;
424 mono_threads_core_resume (MonoThreadInfo *info)
426 MONO_SEM_POST (&info->resume_semaphore);
427 while (MONO_SEM_WAIT (&info->finish_resume_semaphore) != 0) {
428 /* g_assert (errno == EINTR); */
435 mono_threads_platform_register (MonoThreadInfo *info)
437 MONO_SEM_INIT (&info->begin_suspend_semaphore, 0);
439 #if defined (PLATFORM_ANDROID)
440 info->native_handle = gettid ();
445 mono_threads_platform_free (MonoThreadInfo *info)
447 MONO_SEM_DESTROY (&info->begin_suspend_semaphore);
451 mono_native_thread_id_get (void)
453 return pthread_self ();
457 mono_native_thread_id_equals (MonoNativeThreadId id1, MonoNativeThreadId id2)
459 return pthread_equal (id1, id2);
463 * mono_native_thread_create:
465 * Low level thread creation function without any GC wrappers.
468 mono_native_thread_create (MonoNativeThreadId *tid, gpointer func, gpointer arg)
470 return pthread_create (tid, NULL, func, arg) == 0;
474 mono_threads_core_set_name (MonoNativeThreadId tid, const char *name)
476 #ifdef HAVE_PTHREAD_SETNAME_NP
478 pthread_setname_np (tid, "");
482 strncpy (n, name, 16);
484 pthread_setname_np (tid, n);
489 #endif /*!defined (__MACH__)*/