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)
23 extern int tkill (pid_t tid, int signal);
26 #if defined(_POSIX_VERSION) || defined(__native_client__)
27 #include <sys/resource.h>
30 #if defined(__native_client__)
31 void nacl_shutdown_gc_thread(void);
35 void *(*start_routine)(void*);
38 MonoSemType registered;
43 inner_start_thread (void *arg)
45 StartInfo *start_info = arg;
46 void *t_arg = start_info->arg;
48 void *(*start_func)(void*) = start_info->start_routine;
49 guint32 flags = start_info->flags;
54 /* Register the thread with the io-layer */
55 handle = wapi_create_thread_handle ();
57 res = MONO_SEM_POST (&(start_info->registered));
61 start_info->handle = handle;
63 info = mono_thread_info_attach (&result);
64 info->runtime_thread = TRUE;
65 info->handle = handle;
67 if (flags & CREATE_SUSPENDED) {
68 info->create_suspended = TRUE;
69 MONO_SEM_INIT (&info->create_suspended_sem, 0);
72 /* start_info is not valid after this */
73 res = MONO_SEM_POST (&(start_info->registered));
77 if (flags & CREATE_SUSPENDED) {
78 while (MONO_SEM_WAIT (&info->create_suspended_sem) != 0 &&
80 MONO_SEM_DESTROY (&info->create_suspended_sem);
83 /* Run the actual main function of the thread */
84 result = start_func (t_arg);
87 mono_thread_info_detach ();
90 #if defined(__native_client__)
91 nacl_shutdown_gc_thread();
94 wapi_thread_handle_set_exited (handle, GPOINTER_TO_UINT (result));
95 /* This is needed by mono_threads_core_unregister () which is called later */
98 g_assert (mono_threads_get_callbacks ()->thread_exit);
99 mono_threads_get_callbacks ()->thread_exit (NULL);
100 g_assert_not_reached ();
105 mono_threads_core_create_thread (LPTHREAD_START_ROUTINE start_routine, gpointer arg, guint32 stack_size, guint32 creation_flags, MonoNativeThreadId *out_tid)
110 StartInfo start_info;
112 res = pthread_attr_init (&attr);
115 if (stack_size == 0) {
116 #if HAVE_VALGRIND_MEMCHECK_H
117 if (RUNNING_ON_VALGRIND)
118 stack_size = 1 << 20;
120 stack_size = (SIZEOF_VOID_P / 4) * 1024 * 1024;
122 stack_size = (SIZEOF_VOID_P / 4) * 1024 * 1024;
126 #ifdef PTHREAD_STACK_MIN
127 if (stack_size < PTHREAD_STACK_MIN)
128 stack_size = PTHREAD_STACK_MIN;
131 #ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE
132 res = pthread_attr_setstacksize (&attr, stack_size);
136 memset (&start_info, 0, sizeof (StartInfo));
137 start_info.start_routine = (gpointer)start_routine;
138 start_info.arg = arg;
139 start_info.flags = creation_flags;
140 MONO_SEM_INIT (&(start_info.registered), 0);
142 /* Actually start the thread */
143 res = mono_threads_get_callbacks ()->mono_gc_pthread_create (&thread, &attr, inner_start_thread, &start_info);
145 MONO_SEM_DESTROY (&(start_info.registered));
149 /* Wait until the thread register itself in various places */
150 while (MONO_SEM_WAIT (&(start_info.registered)) != 0) {
151 /*if (EINTR != errno) ABORT("sem_wait failed"); */
153 MONO_SEM_DESTROY (&(start_info.registered));
158 return start_info.handle;
162 * mono_threads_core_resume_created:
164 * Resume a newly created thread created using CREATE_SUSPENDED.
167 mono_threads_core_resume_created (MonoThreadInfo *info, MonoNativeThreadId tid)
169 MONO_SEM_POST (&info->create_suspended_sem);
173 mono_threads_core_yield (void)
175 return sched_yield () == 0;
179 mono_threads_core_exit (int exit_code)
181 MonoThreadInfo *current = mono_thread_info_current ();
183 #if defined(__native_client__)
184 nacl_shutdown_gc_thread();
187 wapi_thread_handle_set_exited (current->handle, exit_code);
189 g_assert (mono_threads_get_callbacks ()->thread_exit);
190 mono_threads_get_callbacks ()->thread_exit (NULL);
194 mono_threads_core_unregister (MonoThreadInfo *info)
197 wapi_thread_handle_set_exited (info->handle, 0);
203 mono_threads_core_open_handle (void)
205 MonoThreadInfo *info;
207 info = mono_thread_info_current ();
211 info->handle = wapi_create_thread_handle ();
213 wapi_ref_thread_handle (info->handle);
218 mono_threads_get_max_stack_size (void)
222 /* If getrlimit fails, we don't enforce any limits. */
223 if (getrlimit (RLIMIT_STACK, &lim))
225 /* rlim_t is an unsigned long long on 64bits OSX but we want an int response. */
226 if (lim.rlim_max > (rlim_t)INT_MAX)
228 return (int)lim.rlim_max;
232 mono_threads_core_open_thread_handle (HANDLE handle, MonoNativeThreadId tid)
234 wapi_ref_thread_handle (handle);
240 mono_threads_core_prepare_interrupt (HANDLE thread_handle)
242 return wapi_prepare_interrupt_thread (thread_handle);
246 mono_threads_core_finish_interrupt (gpointer wait_handle)
248 wapi_finish_interrupt_thread (wait_handle);
252 mono_threads_core_self_interrupt (void)
254 wapi_self_interrupt ();
258 mono_threads_core_clear_interruption (void)
260 wapi_clear_interruption ();
263 #if !defined (__MACH__)
265 #if !defined(__native_client__)
267 suspend_signal_handler (int _dummy, siginfo_t *info, void *context)
269 MonoThreadInfo *current = mono_thread_info_current ();
272 if (current->syscall_break_signal) {
273 current->syscall_break_signal = FALSE;
277 ret = mono_threads_get_runtime_callbacks ()->thread_state_init_from_sigctx (¤t->suspend_state, context);
279 /* thread_state_init_from_sigctx return FALSE if the current thread is detaching and suspend can't continue. */
280 current->suspend_can_continue = ret;
282 MONO_SEM_POST (¤t->begin_suspend_semaphore);
284 /* This thread is doomed, all we can do is give up and let the suspender recover. */
288 while (MONO_SEM_WAIT (¤t->resume_semaphore) != 0) {
289 /*if (EINTR != errno) ABORT("sem_wait failed"); */
292 if (current->async_target) {
293 #if MONO_ARCH_HAS_MONO_CONTEXT
294 MonoContext tmp = current->suspend_state.ctx;
295 mono_threads_get_runtime_callbacks ()->setup_async_callback (&tmp, current->async_target, current->user_data);
296 current->async_target = current->user_data = NULL;
297 mono_monoctx_to_sigctx (&tmp, context);
299 g_error ("The new interruption machinery requires a working mono-context");
303 MONO_SEM_POST (¤t->finish_resume_semaphore);
308 mono_posix_add_signal_handler (int signo, gpointer handler)
310 #if !defined(__native_client__)
311 /*FIXME, move the code from mini to utils and do the right thing!*/
313 struct sigaction previous_sa;
316 sa.sa_sigaction = handler;
317 sigemptyset (&sa.sa_mask);
318 sa.sa_flags = SA_SIGINFO;
319 ret = sigaction (signo, &sa, &previous_sa);
321 g_assert (ret != -1);
326 mono_threads_init_platform (void)
328 #if !defined(__native_client__)
330 FIXME we should use all macros from mini to make this more portable
331 FIXME it would be very sweet if sgen could end up using this too.
333 if (mono_thread_info_new_interrupt_enabled ())
334 mono_posix_add_signal_handler (mono_thread_get_abort_signal (), suspend_signal_handler);
338 /*nothing to be done here since suspend always abort syscalls due using signals*/
340 mono_threads_core_interrupt (MonoThreadInfo *info)
345 mono_threads_pthread_kill (MonoThreadInfo *info, int signum)
347 #if defined (PLATFORM_ANDROID)
348 int result, old_errno = errno;
349 result = tkill (info->native_handle, signum);
355 #elif defined(__native_client__)
356 /* Workaround pthread_kill abort() in NaCl glibc. */
359 return pthread_kill (mono_thread_info_get_tid (info), signum);
365 mono_threads_core_abort_syscall (MonoThreadInfo *info)
368 We signal a thread to break it from the urrent syscall.
369 This signal should not be interpreted as a suspend request.
371 info->syscall_break_signal = TRUE;
372 mono_threads_pthread_kill (info, mono_thread_get_abort_signal ());
376 mono_threads_core_needs_abort_syscall (void)
382 mono_threads_core_suspend (MonoThreadInfo *info)
384 /*FIXME, check return value*/
385 mono_threads_pthread_kill (info, mono_thread_get_abort_signal ());
386 while (MONO_SEM_WAIT (&info->begin_suspend_semaphore) != 0) {
387 /* g_assert (errno == EINTR); */
389 return info->suspend_can_continue;
393 mono_threads_core_resume (MonoThreadInfo *info)
395 MONO_SEM_POST (&info->resume_semaphore);
396 while (MONO_SEM_WAIT (&info->finish_resume_semaphore) != 0) {
397 /* g_assert (errno == EINTR); */
404 mono_threads_platform_register (MonoThreadInfo *info)
406 MONO_SEM_INIT (&info->begin_suspend_semaphore, 0);
408 #if defined (PLATFORM_ANDROID)
409 info->native_handle = (gpointer) gettid ();
414 mono_threads_platform_free (MonoThreadInfo *info)
416 MONO_SEM_DESTROY (&info->begin_suspend_semaphore);
420 mono_native_thread_id_get (void)
422 return pthread_self ();
426 mono_native_thread_id_equals (MonoNativeThreadId id1, MonoNativeThreadId id2)
428 return pthread_equal (id1, id2);
432 * mono_native_thread_create:
434 * Low level thread creation function without any GC wrappers.
437 mono_native_thread_create (MonoNativeThreadId *tid, gpointer func, gpointer arg)
439 return pthread_create (tid, NULL, func, arg) == 0;
443 mono_threads_core_set_name (MonoNativeThreadId tid, const char *name)
445 #ifdef HAVE_PTHREAD_SETNAME_NP
447 pthread_setname_np (tid, "");
451 strncpy (n, name, 16);
453 pthread_setname_np (tid, n);
458 #endif /*!defined (__MACH__)*/