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>
17 #include <mono/metadata/threads-types.h>
22 #if defined(PLATFORM_ANDROID) && !defined(TARGET_ARM64)
23 #define USE_TKILL_ON_ANDROID 1
26 #ifdef USE_TKILL_ON_ANDROID
27 extern int tkill (pid_t tid, int signal);
30 #if defined(_POSIX_VERSION) || defined(__native_client__)
31 #include <sys/resource.h>
34 #if defined(__native_client__)
35 void nacl_shutdown_gc_thread(void);
39 void *(*start_routine)(void*);
42 MonoSemType registered;
46 #ifdef PLATFORM_ANDROID
47 static int no_interrupt_signo;
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_detach ();
98 #if defined(__native_client__)
99 nacl_shutdown_gc_thread();
102 wapi_thread_handle_set_exited (handle, GPOINTER_TO_UINT (result));
103 /* This is needed by mono_threads_core_unregister () which is called later */
106 g_assert (mono_threads_get_callbacks ()->thread_exit);
107 mono_threads_get_callbacks ()->thread_exit (NULL);
108 g_assert_not_reached ();
113 mono_threads_core_create_thread (LPTHREAD_START_ROUTINE start_routine, gpointer arg, guint32 stack_size, guint32 creation_flags, MonoNativeThreadId *out_tid)
118 StartInfo start_info;
120 res = pthread_attr_init (&attr);
123 if (stack_size == 0) {
124 #if HAVE_VALGRIND_MEMCHECK_H
125 if (RUNNING_ON_VALGRIND)
126 stack_size = 1 << 20;
128 stack_size = (SIZEOF_VOID_P / 4) * 1024 * 1024;
130 stack_size = (SIZEOF_VOID_P / 4) * 1024 * 1024;
134 #ifdef PTHREAD_STACK_MIN
135 if (stack_size < PTHREAD_STACK_MIN)
136 stack_size = PTHREAD_STACK_MIN;
139 #ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE
140 res = pthread_attr_setstacksize (&attr, stack_size);
144 memset (&start_info, 0, sizeof (StartInfo));
145 start_info.start_routine = (gpointer)start_routine;
146 start_info.arg = arg;
147 start_info.flags = creation_flags;
148 MONO_SEM_INIT (&(start_info.registered), 0);
150 /* Actually start the thread */
151 res = mono_threads_get_callbacks ()->mono_gc_pthread_create (&thread, &attr, inner_start_thread, &start_info);
153 MONO_SEM_DESTROY (&(start_info.registered));
157 /* Wait until the thread register itself in various places */
158 while (MONO_SEM_WAIT (&(start_info.registered)) != 0) {
159 /*if (EINTR != errno) ABORT("sem_wait failed"); */
161 MONO_SEM_DESTROY (&(start_info.registered));
166 return start_info.handle;
170 * mono_threads_core_resume_created:
172 * Resume a newly created thread created using CREATE_SUSPENDED.
175 mono_threads_core_resume_created (MonoThreadInfo *info, MonoNativeThreadId tid)
177 MONO_SEM_POST (&info->create_suspended_sem);
181 mono_threads_core_yield (void)
183 return sched_yield () == 0;
187 mono_threads_core_exit (int exit_code)
189 MonoThreadInfo *current = mono_thread_info_current ();
191 #if defined(__native_client__)
192 nacl_shutdown_gc_thread();
195 wapi_thread_handle_set_exited (current->handle, exit_code);
197 g_assert (mono_threads_get_callbacks ()->thread_exit);
198 mono_threads_get_callbacks ()->thread_exit (NULL);
202 mono_threads_core_unregister (MonoThreadInfo *info)
205 wapi_thread_handle_set_exited (info->handle, 0);
211 mono_threads_core_open_handle (void)
213 MonoThreadInfo *info;
215 info = mono_thread_info_current ();
219 info->handle = wapi_create_thread_handle ();
221 wapi_ref_thread_handle (info->handle);
226 mono_threads_get_max_stack_size (void)
230 /* If getrlimit fails, we don't enforce any limits. */
231 if (getrlimit (RLIMIT_STACK, &lim))
233 /* rlim_t is an unsigned long long on 64bits OSX but we want an int response. */
234 if (lim.rlim_max > (rlim_t)INT_MAX)
236 return (int)lim.rlim_max;
240 mono_threads_core_open_thread_handle (HANDLE handle, MonoNativeThreadId tid)
242 wapi_ref_thread_handle (handle);
248 mono_threads_core_prepare_interrupt (HANDLE thread_handle)
250 return wapi_prepare_interrupt_thread (thread_handle);
254 mono_threads_core_finish_interrupt (gpointer wait_handle)
256 wapi_finish_interrupt_thread (wait_handle);
260 mono_threads_core_self_interrupt (void)
262 wapi_self_interrupt ();
266 mono_threads_core_clear_interruption (void)
268 wapi_clear_interruption ();
272 mono_threads_pthread_kill (MonoThreadInfo *info, int signum)
274 #ifdef USE_TKILL_ON_ANDROID
275 int result, old_errno = errno;
276 result = tkill (info->native_handle, signum);
282 #elif defined(__native_client__)
283 /* Workaround pthread_kill abort() in NaCl glibc. */
286 return pthread_kill (mono_thread_info_get_tid (info), signum);
291 #if !defined (__MACH__)
293 #if !defined(__native_client__)
295 suspend_signal_handler (int _dummy, siginfo_t *info, void *context)
297 MonoThreadInfo *current = mono_thread_info_current ();
300 if (current->syscall_break_signal) {
301 current->syscall_break_signal = FALSE;
305 ret = mono_threads_get_runtime_callbacks ()->thread_state_init_from_sigctx (¤t->suspend_state, context);
307 /* thread_state_init_from_sigctx return FALSE if the current thread is detaching and suspend can't continue. */
308 current->suspend_can_continue = ret;
310 MONO_SEM_POST (¤t->begin_suspend_semaphore);
312 /* This thread is doomed, all we can do is give up and let the suspender recover. */
316 while (MONO_SEM_WAIT (¤t->resume_semaphore) != 0) {
317 /*if (EINTR != errno) ABORT("sem_wait failed"); */
320 if (current->async_target) {
321 #if MONO_ARCH_HAS_MONO_CONTEXT
322 MonoContext tmp = current->suspend_state.ctx;
323 mono_threads_get_runtime_callbacks ()->setup_async_callback (&tmp, current->async_target, current->user_data);
324 current->async_target = current->user_data = NULL;
325 mono_monoctx_to_sigctx (&tmp, context);
327 g_error ("The new interruption machinery requires a working mono-context");
331 MONO_SEM_POST (¤t->finish_resume_semaphore);
336 mono_posix_add_signal_handler (int signo, gpointer handler, int flags)
338 #if !defined(__native_client__)
339 /*FIXME, move the code from mini to utils and do the right thing!*/
341 struct sigaction previous_sa;
344 sa.sa_sigaction = handler;
345 sigemptyset (&sa.sa_mask);
346 sa.sa_flags = SA_SIGINFO | flags;
347 ret = sigaction (signo, &sa, &previous_sa);
349 g_assert (ret != -1);
354 mono_threads_init_platform (void)
356 #if !defined(__native_client__)
360 FIXME we should use all macros from mini to make this more portable
361 FIXME it would be very sweet if sgen could end up using this too.
363 if (!mono_thread_info_new_interrupt_enabled ())
365 abort_signo = mono_thread_get_abort_signal ();
366 mono_posix_add_signal_handler (abort_signo, suspend_signal_handler, 0);
368 #ifdef PLATFORM_ANDROID
370 * Lots of android native code can't handle the EINTR caused by
371 * the normal abort signal, so use a different signal for the
372 * no interruption case, which is used by sdb.
373 * FIXME: Use this on all platforms.
374 * SIGUSR1 is used by dalvik/art.
376 no_interrupt_signo = SIGWINCH;
377 g_assert (abort_signo != no_interrupt_signo);
378 mono_posix_add_signal_handler (no_interrupt_signo, suspend_signal_handler, SA_RESTART);
384 mono_threads_core_interrupt (MonoThreadInfo *info)
386 /* Handled in mono_threads_core_suspend () */
390 mono_threads_core_abort_syscall (MonoThreadInfo *info)
393 We signal a thread to break it from the urrent syscall.
394 This signal should not be interpreted as a suspend request.
396 info->syscall_break_signal = TRUE;
397 mono_threads_pthread_kill (info, mono_thread_get_abort_signal ());
401 mono_threads_core_needs_abort_syscall (void)
407 mono_threads_core_suspend (MonoThreadInfo *info, gboolean interrupt_kernel)
409 /*FIXME, check return value*/
410 #ifdef PLATFORM_ANDROID
411 if (!interrupt_kernel)
412 mono_threads_pthread_kill (info, no_interrupt_signo);
414 mono_threads_pthread_kill (info, mono_thread_get_abort_signal ());
416 mono_threads_pthread_kill (info, mono_thread_get_abort_signal ());
418 while (MONO_SEM_WAIT (&info->begin_suspend_semaphore) != 0) {
419 /* g_assert (errno == EINTR); */
421 return info->suspend_can_continue;
425 mono_threads_core_resume (MonoThreadInfo *info)
427 MONO_SEM_POST (&info->resume_semaphore);
428 while (MONO_SEM_WAIT (&info->finish_resume_semaphore) != 0) {
429 /* g_assert (errno == EINTR); */
436 mono_threads_platform_register (MonoThreadInfo *info)
438 MONO_SEM_INIT (&info->begin_suspend_semaphore, 0);
440 #if defined (PLATFORM_ANDROID)
441 info->native_handle = gettid ();
446 mono_threads_platform_free (MonoThreadInfo *info)
448 MONO_SEM_DESTROY (&info->begin_suspend_semaphore);
452 mono_native_thread_id_get (void)
454 return pthread_self ();
458 mono_native_thread_id_equals (MonoNativeThreadId id1, MonoNativeThreadId id2)
460 return pthread_equal (id1, id2);
464 * mono_native_thread_create:
466 * Low level thread creation function without any GC wrappers.
469 mono_native_thread_create (MonoNativeThreadId *tid, gpointer func, gpointer arg)
471 return pthread_create (tid, NULL, func, arg) == 0;
475 mono_threads_core_set_name (MonoNativeThreadId tid, const char *name)
477 #ifdef HAVE_PTHREAD_SETNAME_NP
479 pthread_setname_np (tid, "");
483 strncpy (n, name, 16);
485 pthread_setname_np (tid, n);
490 #endif /*!defined (__MACH__)*/