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);
81 g_assert (!mono_domain_get ());
82 mono_thread_info_dettach ();
85 #if defined(__native_client__)
86 nacl_shutdown_gc_thread();
89 wapi_thread_set_exit_code (GPOINTER_TO_UINT (result), handle);
91 // FIXME: Why is this needed ?
92 mono_gc_pthread_exit (NULL);
94 g_assert_not_reached ();
99 mono_threads_core_create_thread (LPTHREAD_START_ROUTINE start_routine, gpointer arg, guint32 stack_size, guint32 creation_flags, MonoNativeThreadId *out_tid)
104 StartInfo start_info;
106 res = pthread_attr_init (&attr);
109 if (stack_size == 0) {
110 #if HAVE_VALGRIND_MEMCHECK_H
111 if (RUNNING_ON_VALGRIND)
112 stack_size = 1 << 20;
114 stack_size = (SIZEOF_VOID_P / 4) * 1024 * 1024;
116 stack_size = (SIZEOF_VOID_P / 4) * 1024 * 1024;
120 #ifdef PTHREAD_STACK_MIN
121 if (stack_size < PTHREAD_STACK_MIN)
122 stack_size = PTHREAD_STACK_MIN;
125 #ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE
126 res = pthread_attr_setstacksize (&attr, stack_size);
130 memset (&start_info, 0, sizeof (StartInfo));
131 start_info.start_routine = (gpointer)start_routine;
132 start_info.arg = arg;
133 start_info.flags = creation_flags;
134 MONO_SEM_INIT (&(start_info.registered), 0);
136 /* Actually start the thread */
137 res = mono_threads_get_callbacks ()->mono_gc_pthread_create (&thread, &attr, inner_start_thread, &start_info);
140 g_assert_not_reached ();
143 /* Wait until the thread register itself in various places */
144 while (MONO_SEM_WAIT (&(start_info.registered)) != 0) {
145 /*if (EINTR != errno) ABORT("sem_wait failed"); */
147 MONO_SEM_DESTROY (&(start_info.registered));
152 return start_info.handle;
155 #if !defined (__MACH__)
157 #if !defined(__native_client__)
159 suspend_signal_handler (int _dummy, siginfo_t *info, void *context)
161 MonoThreadInfo *current = mono_thread_info_current ();
164 if (current->syscall_break_signal) {
165 current->syscall_break_signal = FALSE;
169 ret = mono_threads_get_runtime_callbacks ()->thread_state_init_from_sigctx (¤t->suspend_state, context);
171 /* thread_state_init_from_sigctx return FALSE if the current thread is detaching and suspend can't continue. */
172 current->suspend_can_continue = ret;
174 MONO_SEM_POST (¤t->begin_suspend_semaphore);
176 /* This thread is doomed, all we can do is give up and let the suspender recover. */
180 while (MONO_SEM_WAIT (¤t->resume_semaphore) != 0) {
181 /*if (EINTR != errno) ABORT("sem_wait failed"); */
184 if (current->async_target) {
185 #if MONO_ARCH_HAS_MONO_CONTEXT
186 MonoContext tmp = current->suspend_state.ctx;
187 mono_threads_get_runtime_callbacks ()->setup_async_callback (&tmp, current->async_target, current->user_data);
188 current->async_target = current->user_data = NULL;
189 mono_monoctx_to_sigctx (&tmp, context);
191 g_error ("The new interruption machinery requires a working mono-context");
195 MONO_SEM_POST (¤t->finish_resume_semaphore);
200 mono_posix_add_signal_handler (int signo, gpointer handler)
202 #if !defined(__native_client__)
203 /*FIXME, move the code from mini to utils and do the right thing!*/
205 struct sigaction previous_sa;
208 sa.sa_sigaction = handler;
209 sigemptyset (&sa.sa_mask);
210 sa.sa_flags = SA_SIGINFO;
211 ret = sigaction (signo, &sa, &previous_sa);
213 g_assert (ret != -1);
218 mono_threads_init_platform (void)
220 #if !defined(__native_client__)
222 FIXME we should use all macros from mini to make this more portable
223 FIXME it would be very sweet if sgen could end up using this too.
225 if (mono_thread_info_new_interrupt_enabled ())
226 mono_posix_add_signal_handler (mono_thread_get_abort_signal (), suspend_signal_handler);
230 /*nothing to be done here since suspend always abort syscalls due using signals*/
232 mono_threads_core_interrupt (MonoThreadInfo *info)
237 mono_threads_pthread_kill (MonoThreadInfo *info, int signum)
239 #if defined (PLATFORM_ANDROID)
240 int result, old_errno = errno;
241 result = tkill (info->native_handle, signum);
247 #elif defined(__native_client__)
248 /* Workaround pthread_kill abort() in NaCl glibc. */
251 return pthread_kill (mono_thread_info_get_tid (info), signum);
257 mono_threads_core_abort_syscall (MonoThreadInfo *info)
260 We signal a thread to break it from the urrent syscall.
261 This signal should not be interpreted as a suspend request.
263 info->syscall_break_signal = TRUE;
264 mono_threads_pthread_kill (info, mono_thread_get_abort_signal ());
268 mono_threads_core_needs_abort_syscall (void)
274 mono_threads_core_suspend (MonoThreadInfo *info)
276 /*FIXME, check return value*/
277 mono_threads_pthread_kill (info, mono_thread_get_abort_signal ());
278 while (MONO_SEM_WAIT (&info->begin_suspend_semaphore) != 0) {
279 /* g_assert (errno == EINTR); */
281 return info->suspend_can_continue;
285 mono_threads_core_resume (MonoThreadInfo *info)
287 MONO_SEM_POST (&info->resume_semaphore);
288 while (MONO_SEM_WAIT (&info->finish_resume_semaphore) != 0) {
289 /* g_assert (errno == EINTR); */
296 mono_threads_platform_register (MonoThreadInfo *info)
298 MONO_SEM_INIT (&info->begin_suspend_semaphore, 0);
300 #if defined (PLATFORM_ANDROID)
301 info->native_handle = (gpointer) gettid ();
306 mono_threads_platform_free (MonoThreadInfo *info)
308 MONO_SEM_DESTROY (&info->begin_suspend_semaphore);
312 mono_native_thread_id_get (void)
314 return pthread_self ();
318 mono_native_thread_id_equals (MonoNativeThreadId id1, MonoNativeThreadId id2)
320 return pthread_equal (id1, id2);
324 * mono_native_thread_create:
326 * Low level thread creation function without any GC wrappers.
329 mono_native_thread_create (MonoNativeThreadId *tid, gpointer func, gpointer arg)
331 return pthread_create (tid, NULL, func, arg) == 0;
334 #endif /*!defined (__MACH__)*/