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/gc_wrapper.h>
17 #include <mono/metadata/threads-types.h>
21 #if defined(PLATFORM_ANDROID)
22 extern int tkill (pid_t tid, int signal);
25 #if defined(_POSIX_VERSION) || defined(__native_client__)
28 #if defined(__native_client__)
29 void nacl_shutdown_gc_thread(void);
33 void *(*start_routine)(void*);
36 MonoSemType registered;
41 inner_start_thread (void *arg)
43 StartInfo *start_info = arg;
44 void *t_arg = start_info->arg;
46 void *(*start_func)(void*) = start_info->start_routine;
47 guint32 flags = start_info->flags;
52 /* Register the thread with the io-layer */
53 handle = wapi_create_thread_handle ();
55 res = MONO_SEM_POST (&(start_info->registered));
59 start_info->handle = handle;
61 if (!(flags & CREATE_NO_DETACH)) {
62 res = mono_gc_pthread_detach (pthread_self ());
66 info = mono_thread_info_attach (&result);
67 info->runtime_thread = TRUE;
69 if (flags & CREATE_SUSPENDED) {
70 info->create_suspended = TRUE;
71 MONO_SEM_INIT (&info->create_suspended_sem, 0);
74 /* start_info is not valid after this */
75 res = MONO_SEM_POST (&(start_info->registered));
79 if (flags & CREATE_SUSPENDED) {
80 while (MONO_SEM_WAIT (&info->create_suspended_sem) != 0 &&
82 MONO_SEM_DESTROY (&info->create_suspended_sem);
85 /* Run the actual main function of the thread */
86 result = start_func (t_arg);
89 g_assert (!mono_domain_get ());
90 mono_thread_info_dettach ();
93 #if defined(__native_client__)
94 nacl_shutdown_gc_thread();
97 wapi_thread_set_exit_code (GPOINTER_TO_UINT (result), handle);
99 // FIXME: Why is this needed ?
100 mono_gc_pthread_exit (NULL);
102 g_assert_not_reached ();
107 mono_threads_core_create_thread (LPTHREAD_START_ROUTINE start_routine, gpointer arg, guint32 stack_size, guint32 creation_flags, MonoNativeThreadId *out_tid)
112 StartInfo start_info;
114 res = pthread_attr_init (&attr);
117 if (stack_size == 0) {
118 #if HAVE_VALGRIND_MEMCHECK_H
119 if (RUNNING_ON_VALGRIND)
120 stack_size = 1 << 20;
122 stack_size = (SIZEOF_VOID_P / 4) * 1024 * 1024;
124 stack_size = (SIZEOF_VOID_P / 4) * 1024 * 1024;
128 #ifdef PTHREAD_STACK_MIN
129 if (stack_size < PTHREAD_STACK_MIN)
130 stack_size = PTHREAD_STACK_MIN;
133 #ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE
134 res = pthread_attr_setstacksize (&attr, stack_size);
138 memset (&start_info, 0, sizeof (StartInfo));
139 start_info.start_routine = (gpointer)start_routine;
140 start_info.arg = arg;
141 start_info.flags = creation_flags;
142 MONO_SEM_INIT (&(start_info.registered), 0);
144 /* Actually start the thread */
145 res = mono_threads_get_callbacks ()->mono_gc_pthread_create (&thread, &attr, inner_start_thread, &start_info);
148 g_assert_not_reached ();
151 /* Wait until the thread register itself in various places */
152 while (MONO_SEM_WAIT (&(start_info.registered)) != 0) {
153 /*if (EINTR != errno) ABORT("sem_wait failed"); */
155 MONO_SEM_DESTROY (&(start_info.registered));
160 return start_info.handle;
164 * mono_threads_core_resume_created:
166 * Resume a newly created thread created using CREATE_SUSPENDED.
169 mono_threads_core_resume_created (MonoThreadInfo *info, MonoNativeThreadId tid)
171 MONO_SEM_POST (&info->create_suspended_sem);
174 #if !defined (__MACH__)
176 #if !defined(__native_client__)
178 suspend_signal_handler (int _dummy, siginfo_t *info, void *context)
180 MonoThreadInfo *current = mono_thread_info_current ();
183 if (current->syscall_break_signal) {
184 current->syscall_break_signal = FALSE;
188 ret = mono_threads_get_runtime_callbacks ()->thread_state_init_from_sigctx (¤t->suspend_state, context);
190 /* thread_state_init_from_sigctx return FALSE if the current thread is detaching and suspend can't continue. */
191 current->suspend_can_continue = ret;
193 MONO_SEM_POST (¤t->begin_suspend_semaphore);
195 /* This thread is doomed, all we can do is give up and let the suspender recover. */
199 while (MONO_SEM_WAIT (¤t->resume_semaphore) != 0) {
200 /*if (EINTR != errno) ABORT("sem_wait failed"); */
203 if (current->async_target) {
204 #if MONO_ARCH_HAS_MONO_CONTEXT
205 MonoContext tmp = current->suspend_state.ctx;
206 mono_threads_get_runtime_callbacks ()->setup_async_callback (&tmp, current->async_target, current->user_data);
207 current->async_target = current->user_data = NULL;
208 mono_monoctx_to_sigctx (&tmp, context);
210 g_error ("The new interruption machinery requires a working mono-context");
214 MONO_SEM_POST (¤t->finish_resume_semaphore);
219 mono_posix_add_signal_handler (int signo, gpointer handler)
221 #if !defined(__native_client__)
222 /*FIXME, move the code from mini to utils and do the right thing!*/
224 struct sigaction previous_sa;
227 sa.sa_sigaction = handler;
228 sigemptyset (&sa.sa_mask);
229 sa.sa_flags = SA_SIGINFO;
230 ret = sigaction (signo, &sa, &previous_sa);
232 g_assert (ret != -1);
237 mono_threads_init_platform (void)
239 #if !defined(__native_client__)
241 FIXME we should use all macros from mini to make this more portable
242 FIXME it would be very sweet if sgen could end up using this too.
244 if (mono_thread_info_new_interrupt_enabled ())
245 mono_posix_add_signal_handler (mono_thread_get_abort_signal (), suspend_signal_handler);
249 /*nothing to be done here since suspend always abort syscalls due using signals*/
251 mono_threads_core_interrupt (MonoThreadInfo *info)
256 mono_threads_pthread_kill (MonoThreadInfo *info, int signum)
258 #if defined (PLATFORM_ANDROID)
259 int result, old_errno = errno;
260 result = tkill (info->native_handle, signum);
266 #elif defined(__native_client__)
267 /* Workaround pthread_kill abort() in NaCl glibc. */
270 return pthread_kill (mono_thread_info_get_tid (info), signum);
276 mono_threads_core_abort_syscall (MonoThreadInfo *info)
279 We signal a thread to break it from the urrent syscall.
280 This signal should not be interpreted as a suspend request.
282 info->syscall_break_signal = TRUE;
283 mono_threads_pthread_kill (info, mono_thread_get_abort_signal ());
287 mono_threads_core_needs_abort_syscall (void)
293 mono_threads_core_suspend (MonoThreadInfo *info)
295 /*FIXME, check return value*/
296 mono_threads_pthread_kill (info, mono_thread_get_abort_signal ());
297 while (MONO_SEM_WAIT (&info->begin_suspend_semaphore) != 0) {
298 /* g_assert (errno == EINTR); */
300 return info->suspend_can_continue;
304 mono_threads_core_resume (MonoThreadInfo *info)
306 MONO_SEM_POST (&info->resume_semaphore);
307 while (MONO_SEM_WAIT (&info->finish_resume_semaphore) != 0) {
308 /* g_assert (errno == EINTR); */
315 mono_threads_platform_register (MonoThreadInfo *info)
317 MONO_SEM_INIT (&info->begin_suspend_semaphore, 0);
319 #if defined (PLATFORM_ANDROID)
320 info->native_handle = (gpointer) gettid ();
325 mono_threads_platform_free (MonoThreadInfo *info)
327 MONO_SEM_DESTROY (&info->begin_suspend_semaphore);
331 mono_native_thread_id_get (void)
333 return pthread_self ();
337 mono_native_thread_id_equals (MonoNativeThreadId id1, MonoNativeThreadId id2)
339 return pthread_equal (id1, id2);
343 * mono_native_thread_create:
345 * Low level thread creation function without any GC wrappers.
348 mono_native_thread_create (MonoNativeThreadId *tid, gpointer func, gpointer arg)
350 return pthread_create (tid, NULL, func, arg) == 0;
353 #endif /*!defined (__MACH__)*/