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);
173 return pthread_kill (mono_thread_info_get_tid (info), signum);
179 mono_threads_core_abort_syscall (MonoThreadInfo *info)
182 We signal a thread to break it from the urrent syscall.
183 This signal should not be interpreted as a suspend request.
185 info->syscall_break_signal = TRUE;
186 mono_threads_pthread_kill (info, mono_thread_get_abort_signal ());
190 mono_threads_core_needs_abort_syscall (void)
196 mono_threads_core_suspend (MonoThreadInfo *info)
198 /*FIXME, check return value*/
199 mono_threads_pthread_kill (info, mono_thread_get_abort_signal ());
200 while (MONO_SEM_WAIT (&info->suspend_semaphore) != 0) {
201 /* g_assert (errno == EINTR); */
203 return info->suspend_can_continue;
207 mono_threads_core_resume (MonoThreadInfo *info)
209 MONO_SEM_POST (&info->resume_semaphore);
210 while (MONO_SEM_WAIT (&info->finish_resume_semaphore) != 0) {
211 /* g_assert (errno == EINTR); */
218 mono_threads_platform_register (MonoThreadInfo *info)
220 MONO_SEM_INIT (&info->suspend_semaphore, 0);
222 #if defined (PLATFORM_ANDROID)
223 info->native_handle = (gpointer) gettid ();
228 mono_threads_platform_free (MonoThreadInfo *info)
230 MONO_SEM_DESTROY (&info->suspend_semaphore);
234 mono_native_thread_id_get (void)
236 return pthread_self ();
240 mono_native_thread_id_equals (MonoNativeThreadId id1, MonoNativeThreadId id2)
242 return pthread_equal (id1, id2);
246 * mono_native_thread_create:
248 * Low level thread creation function without any GC wrappers.
251 mono_native_thread_create (MonoNativeThreadId *tid, gpointer func, gpointer arg)
253 return pthread_create (tid, NULL, func, arg) == 0;
256 #endif /*!defined (__MACH__)*/