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)->runtime_thread = TRUE;
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 ());
52 mono_thread_info_dettach ();
58 mono_threads_pthread_create (pthread_t *new_thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg)
60 ThreadStartInfo *start_info;
63 start_info = g_malloc0 (sizeof (ThreadStartInfo));
66 MONO_SEM_INIT (&(start_info->registered), 0);
67 start_info->arg = arg;
68 start_info->start_routine = start_routine;
70 result = mono_threads_get_callbacks ()->mono_gc_pthread_create (new_thread, attr, inner_start_thread, start_info);
72 while (MONO_SEM_WAIT (&(start_info->registered)) != 0) {
73 /*if (EINTR != errno) ABORT("sem_wait failed"); */
76 MONO_SEM_DESTROY (&(start_info->registered));
81 #if !defined (__MACH__)
83 #if !defined(__native_client__)
85 suspend_signal_handler (int _dummy, siginfo_t *info, void *context)
87 MonoThreadInfo *current = mono_thread_info_current ();
90 if (current->syscall_break_signal) {
91 current->syscall_break_signal = FALSE;
95 ret = mono_threads_get_runtime_callbacks ()->thread_state_init_from_sigctx (¤t->suspend_state, context);
97 /* thread_state_init_from_sigctx return FALSE if the current thread is detaching and suspend can't continue. */
98 current->suspend_can_continue = ret;
100 MONO_SEM_POST (¤t->begin_suspend_semaphore);
102 /* This thread is doomed, all we can do is give up and let the suspender recover. */
106 while (MONO_SEM_WAIT (¤t->resume_semaphore) != 0) {
107 /*if (EINTR != errno) ABORT("sem_wait failed"); */
110 if (current->async_target) {
111 #if MONO_ARCH_HAS_MONO_CONTEXT
112 MonoContext tmp = current->suspend_state.ctx;
113 mono_threads_get_runtime_callbacks ()->setup_async_callback (&tmp, current->async_target, current->user_data);
114 current->async_target = current->user_data = NULL;
115 mono_monoctx_to_sigctx (&tmp, context);
117 g_error ("The new interruption machinery requires a working mono-context");
121 MONO_SEM_POST (¤t->finish_resume_semaphore);
126 mono_posix_add_signal_handler (int signo, gpointer handler)
128 #if !defined(__native_client__)
129 /*FIXME, move the code from mini to utils and do the right thing!*/
131 struct sigaction previous_sa;
134 sa.sa_sigaction = handler;
135 sigemptyset (&sa.sa_mask);
136 sa.sa_flags = SA_SIGINFO;
137 ret = sigaction (signo, &sa, &previous_sa);
139 g_assert (ret != -1);
144 mono_threads_init_platform (void)
146 #if !defined(__native_client__)
148 FIXME we should use all macros from mini to make this more portable
149 FIXME it would be very sweet if sgen could end up using this too.
151 if (mono_thread_info_new_interrupt_enabled ())
152 mono_posix_add_signal_handler (mono_thread_get_abort_signal (), suspend_signal_handler);
156 /*nothing to be done here since suspend always abort syscalls due using signals*/
158 mono_threads_core_interrupt (MonoThreadInfo *info)
163 mono_threads_pthread_kill (MonoThreadInfo *info, int signum)
165 #if defined (PLATFORM_ANDROID)
166 int result, old_errno = errno;
167 result = tkill (info->native_handle, signum);
173 #elif defined(__native_client__)
174 /* Workaround pthread_kill abort() in NaCl glibc. */
177 return pthread_kill (mono_thread_info_get_tid (info), signum);
183 mono_threads_core_abort_syscall (MonoThreadInfo *info)
186 We signal a thread to break it from the urrent syscall.
187 This signal should not be interpreted as a suspend request.
189 info->syscall_break_signal = TRUE;
190 mono_threads_pthread_kill (info, mono_thread_get_abort_signal ());
194 mono_threads_core_needs_abort_syscall (void)
200 mono_threads_core_suspend (MonoThreadInfo *info)
202 /*FIXME, check return value*/
203 mono_threads_pthread_kill (info, mono_thread_get_abort_signal ());
204 while (MONO_SEM_WAIT (&info->begin_suspend_semaphore) != 0) {
205 /* g_assert (errno == EINTR); */
207 return info->suspend_can_continue;
211 mono_threads_core_resume (MonoThreadInfo *info)
213 MONO_SEM_POST (&info->resume_semaphore);
214 while (MONO_SEM_WAIT (&info->finish_resume_semaphore) != 0) {
215 /* g_assert (errno == EINTR); */
222 mono_threads_platform_register (MonoThreadInfo *info)
224 MONO_SEM_INIT (&info->begin_suspend_semaphore, 0);
226 #if defined (PLATFORM_ANDROID)
227 info->native_handle = (gpointer) gettid ();
232 mono_threads_platform_free (MonoThreadInfo *info)
234 MONO_SEM_DESTROY (&info->begin_suspend_semaphore);
238 mono_native_thread_id_get (void)
240 return pthread_self ();
244 mono_native_thread_id_equals (MonoNativeThreadId id1, MonoNativeThreadId id2)
246 return pthread_equal (id1, id2);
250 * mono_native_thread_create:
252 * Low level thread creation function without any GC wrappers.
255 mono_native_thread_create (MonoNativeThreadId *tid, gpointer func, gpointer arg)
257 return pthread_create (tid, NULL, func, arg) == 0;
260 #endif /*!defined (__MACH__)*/