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/metadata/threads-types.h>
20 #if defined(PLATFORM_ANDROID)
21 extern int tkill (pid_t tid, int signal);
24 #if defined(_POSIX_VERSION) || defined(__native_client__)
28 void *(*start_routine)(void*);
31 MonoSemType registered;
36 inner_start_thread (void *arg)
38 ThreadStartInfo *start_info = arg;
39 void *t_arg = start_info->arg;
41 void *(*start_func)(void*) = start_info->start_routine;
44 mono_thread_info_attach (&result);
46 post_result = MONO_SEM_POST (&(start_info->registered));
47 g_assert (!post_result);
49 result = start_func (t_arg);
50 g_assert (!mono_domain_get ());
57 mono_threads_pthread_create (pthread_t *new_thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg)
59 ThreadStartInfo *start_info;
62 start_info = g_malloc0 (sizeof (ThreadStartInfo));
65 MONO_SEM_INIT (&(start_info->registered), 0);
66 start_info->arg = arg;
67 start_info->start_routine = start_routine;
69 result = mono_threads_get_callbacks ()->mono_gc_pthread_create (new_thread, attr, inner_start_thread, start_info);
71 while (MONO_SEM_WAIT (&(start_info->registered)) != 0) {
72 /*if (EINTR != errno) ABORT("sem_wait failed"); */
75 MONO_SEM_DESTROY (&(start_info->registered));
80 #if !defined (__MACH__)
82 #if !defined(__native_client__)
84 suspend_signal_handler (int _dummy, siginfo_t *info, void *context)
86 MonoThreadInfo *current = mono_thread_info_current ();
89 if (current->syscall_break_signal) {
90 current->syscall_break_signal = FALSE;
94 ret = mono_threads_get_runtime_callbacks ()->thread_state_init_from_sigctx (¤t->suspend_state, context);
96 /* thread_state_init_from_sigctx return FALSE if the current thread is detaching and suspend can't continue. */
97 current->suspend_can_continue = ret;
99 MONO_SEM_POST (¤t->suspend_semaphore);
101 /* This thread is doomed, all we can do is give up and let the suspender recover. */
105 while (MONO_SEM_WAIT (¤t->resume_semaphore) != 0) {
106 /*if (EINTR != errno) ABORT("sem_wait failed"); */
109 if (current->async_target) {
110 #if MONO_ARCH_HAS_MONO_CONTEXT
111 MonoContext tmp = current->suspend_state.ctx;
112 mono_threads_get_runtime_callbacks ()->setup_async_callback (&tmp, current->async_target, current->user_data);
113 current->async_target = current->user_data = NULL;
114 mono_monoctx_to_sigctx (&tmp, context);
116 g_error ("The new interruption machinery requires a working mono-context");
120 MONO_SEM_POST (¤t->finish_resume_semaphore);
125 mono_posix_add_signal_handler (int signo, gpointer handler)
127 #if !defined(__native_client__)
128 /*FIXME, move the code from mini to utils and do the right thing!*/
130 struct sigaction previous_sa;
133 sa.sa_sigaction = handler;
134 sigemptyset (&sa.sa_mask);
135 sa.sa_flags = SA_SIGINFO;
136 ret = sigaction (signo, &sa, &previous_sa);
138 g_assert (ret != -1);
143 mono_threads_init_platform (void)
145 #if !defined(__native_client__)
147 FIXME we should use all macros from mini to make this more portable
148 FIXME it would be very sweet if sgen could end up using this too.
150 if (mono_thread_info_new_interrupt_enabled ())
151 mono_posix_add_signal_handler (mono_thread_get_abort_signal (), suspend_signal_handler);
155 /*nothing to be done here since suspend always abort syscalls due using signals*/
157 mono_threads_core_interrupt (MonoThreadInfo *info)
162 mono_threads_pthread_kill (MonoThreadInfo *info, int signum)
164 #if defined (PLATFORM_ANDROID)
165 int result, old_errno = errno;
166 result = tkill (info->native_handle, signum);
172 #elif defined(__native_client__)
173 /* Workaround pthread_kill abort() in NaCl glibc. */
176 return pthread_kill (mono_thread_info_get_tid (info), signum);
182 mono_threads_core_abort_syscall (MonoThreadInfo *info)
185 We signal a thread to break it from the urrent syscall.
186 This signal should not be interpreted as a suspend request.
188 info->syscall_break_signal = TRUE;
189 mono_threads_pthread_kill (info, mono_thread_get_abort_signal ());
193 mono_threads_core_needs_abort_syscall (void)
199 mono_threads_core_suspend (MonoThreadInfo *info)
201 /*FIXME, check return value*/
202 mono_threads_pthread_kill (info, mono_thread_get_abort_signal ());
203 while (MONO_SEM_WAIT (&info->suspend_semaphore) != 0) {
204 /* g_assert (errno == EINTR); */
206 return info->suspend_can_continue;
210 mono_threads_core_resume (MonoThreadInfo *info)
212 MONO_SEM_POST (&info->resume_semaphore);
213 while (MONO_SEM_WAIT (&info->finish_resume_semaphore) != 0) {
214 /* g_assert (errno == EINTR); */
221 mono_threads_platform_register (MonoThreadInfo *info)
223 MONO_SEM_INIT (&info->suspend_semaphore, 0);
225 #if defined (PLATFORM_ANDROID)
226 info->native_handle = (gpointer) gettid ();
231 mono_threads_platform_free (MonoThreadInfo *info)
233 MONO_SEM_DESTROY (&info->suspend_semaphore);
237 mono_native_thread_id_get (void)
239 return pthread_self ();
243 mono_native_thread_id_equals (MonoNativeThreadId id1, MonoNativeThreadId id2)
245 return pthread_equal (id1, id2);
249 * mono_native_thread_create:
251 * Low level thread creation function without any GC wrappers.
254 mono_native_thread_create (MonoNativeThreadId *tid, gpointer func, gpointer arg)
256 return pthread_create (tid, NULL, func, arg) == 0;
259 #endif /*!defined (__MACH__)*/