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 /* start_info is not valid after this */
70 res = MONO_SEM_POST (&(start_info->registered));
74 if (flags & CREATE_SUSPENDED)
75 wapi_thread_suspend (handle);
77 /* Run the actual main function of the thread */
78 result = start_func (t_arg);
80 g_assert (!mono_domain_get ());
81 mono_thread_info_dettach ();
83 #if defined(__native_client__)
84 nacl_shutdown_gc_thread();
87 wapi_thread_set_exit_code (GPOINTER_TO_UINT (result), handle);
89 // FIXME: Why is this needed ?
90 mono_gc_pthread_exit (NULL);
92 g_assert_not_reached ();
97 mono_threads_core_create_thread (LPTHREAD_START_ROUTINE start_routine, gpointer arg, guint32 stack_size, guint32 creation_flags, MonoNativeThreadId *out_tid)
102 StartInfo start_info;
104 res = pthread_attr_init (&attr);
107 if (stack_size == 0) {
108 #if HAVE_VALGRIND_MEMCHECK_H
109 if (RUNNING_ON_VALGRIND)
110 stack_size = 1 << 20;
112 stack_size = (SIZEOF_VOID_P / 4) * 1024 * 1024;
114 stack_size = (SIZEOF_VOID_P / 4) * 1024 * 1024;
118 #ifdef PTHREAD_STACK_MIN
119 if (stack_size < PTHREAD_STACK_MIN)
120 stack_size = PTHREAD_STACK_MIN;
123 #ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE
124 res = pthread_attr_setstacksize (&attr, stack_size);
128 memset (&start_info, 0, sizeof (StartInfo));
129 start_info.start_routine = (gpointer)start_routine;
130 start_info.arg = arg;
131 start_info.flags = creation_flags;
132 MONO_SEM_INIT (&(start_info.registered), 0);
134 /* Actually start the thread */
135 res = mono_threads_get_callbacks ()->mono_gc_pthread_create (&thread, &attr, inner_start_thread, &start_info);
138 g_assert_not_reached ();
141 /* Wait until the thread register itself in various places */
142 while (MONO_SEM_WAIT (&(start_info.registered)) != 0) {
143 /*if (EINTR != errno) ABORT("sem_wait failed"); */
145 MONO_SEM_DESTROY (&(start_info.registered));
150 return start_info.handle;
153 #if !defined (__MACH__)
155 #if !defined(__native_client__)
157 suspend_signal_handler (int _dummy, siginfo_t *info, void *context)
159 MonoThreadInfo *current = mono_thread_info_current ();
162 if (current->syscall_break_signal) {
163 current->syscall_break_signal = FALSE;
167 ret = mono_threads_get_runtime_callbacks ()->thread_state_init_from_sigctx (¤t->suspend_state, context);
169 /* thread_state_init_from_sigctx return FALSE if the current thread is detaching and suspend can't continue. */
170 current->suspend_can_continue = ret;
172 MONO_SEM_POST (¤t->begin_suspend_semaphore);
174 /* This thread is doomed, all we can do is give up and let the suspender recover. */
178 while (MONO_SEM_WAIT (¤t->resume_semaphore) != 0) {
179 /*if (EINTR != errno) ABORT("sem_wait failed"); */
182 if (current->async_target) {
183 #if MONO_ARCH_HAS_MONO_CONTEXT
184 MonoContext tmp = current->suspend_state.ctx;
185 mono_threads_get_runtime_callbacks ()->setup_async_callback (&tmp, current->async_target, current->user_data);
186 current->async_target = current->user_data = NULL;
187 mono_monoctx_to_sigctx (&tmp, context);
189 g_error ("The new interruption machinery requires a working mono-context");
193 MONO_SEM_POST (¤t->finish_resume_semaphore);
198 mono_posix_add_signal_handler (int signo, gpointer handler)
200 #if !defined(__native_client__)
201 /*FIXME, move the code from mini to utils and do the right thing!*/
203 struct sigaction previous_sa;
206 sa.sa_sigaction = handler;
207 sigemptyset (&sa.sa_mask);
208 sa.sa_flags = SA_SIGINFO;
209 ret = sigaction (signo, &sa, &previous_sa);
211 g_assert (ret != -1);
216 mono_threads_init_platform (void)
218 #if !defined(__native_client__)
220 FIXME we should use all macros from mini to make this more portable
221 FIXME it would be very sweet if sgen could end up using this too.
223 if (mono_thread_info_new_interrupt_enabled ())
224 mono_posix_add_signal_handler (mono_thread_get_abort_signal (), suspend_signal_handler);
228 /*nothing to be done here since suspend always abort syscalls due using signals*/
230 mono_threads_core_interrupt (MonoThreadInfo *info)
235 mono_threads_pthread_kill (MonoThreadInfo *info, int signum)
237 #if defined (PLATFORM_ANDROID)
238 int result, old_errno = errno;
239 result = tkill (info->native_handle, signum);
245 #elif defined(__native_client__)
246 /* Workaround pthread_kill abort() in NaCl glibc. */
249 return pthread_kill (mono_thread_info_get_tid (info), signum);
255 mono_threads_core_abort_syscall (MonoThreadInfo *info)
258 We signal a thread to break it from the urrent syscall.
259 This signal should not be interpreted as a suspend request.
261 info->syscall_break_signal = TRUE;
262 mono_threads_pthread_kill (info, mono_thread_get_abort_signal ());
266 mono_threads_core_needs_abort_syscall (void)
272 mono_threads_core_suspend (MonoThreadInfo *info)
274 /*FIXME, check return value*/
275 mono_threads_pthread_kill (info, mono_thread_get_abort_signal ());
276 while (MONO_SEM_WAIT (&info->begin_suspend_semaphore) != 0) {
277 /* g_assert (errno == EINTR); */
279 return info->suspend_can_continue;
283 mono_threads_core_resume (MonoThreadInfo *info)
285 MONO_SEM_POST (&info->resume_semaphore);
286 while (MONO_SEM_WAIT (&info->finish_resume_semaphore) != 0) {
287 /* g_assert (errno == EINTR); */
294 mono_threads_platform_register (MonoThreadInfo *info)
296 MONO_SEM_INIT (&info->begin_suspend_semaphore, 0);
298 #if defined (PLATFORM_ANDROID)
299 info->native_handle = (gpointer) gettid ();
304 mono_threads_platform_free (MonoThreadInfo *info)
306 MONO_SEM_DESTROY (&info->begin_suspend_semaphore);
310 mono_native_thread_id_get (void)
312 return pthread_self ();
316 mono_native_thread_id_equals (MonoNativeThreadId id1, MonoNativeThreadId id2)
318 return pthread_equal (id1, id2);
322 * mono_native_thread_create:
324 * Low level thread creation function without any GC wrappers.
327 mono_native_thread_create (MonoNativeThreadId *tid, gpointer func, gpointer arg)
329 return pthread_create (tid, NULL, func, arg) == 0;
332 #endif /*!defined (__MACH__)*/