[runtime] Move thread attaching to mono-threads from the io-layer.
[mono.git] / mono / utils / mono-threads-posix.c
1 /*
2  * mono-threads-posix.c: Low-level threading, posix version
3  *
4  * Author:
5  *      Rodrigo Kumpera (kumpera@gmail.com)
6  *
7  * (C) 2011 Novell, Inc
8  */
9
10 #include <config.h>
11
12 #if defined(__OpenBSD__) || defined(__FreeBSD__)
13 #include <pthread.h>
14 #include <pthread_np.h>
15 #endif
16
17 #include <mono/utils/mono-compiler.h>
18 #include <mono/utils/mono-semaphore.h>
19 #include <mono/utils/mono-threads.h>
20 #include <mono/utils/mono-tls.h>
21 #include <mono/utils/mono-mmap.h>
22 #include <mono/metadata/threads-types.h>
23
24 #include <errno.h>
25
26 #if defined(PLATFORM_ANDROID)
27 extern int tkill (pid_t tid, int signal);
28 #endif
29
30 #if defined(PLATFORM_MACOSX) && defined(HAVE_PTHREAD_GET_STACKADDR_NP)
31 void *pthread_get_stackaddr_np(pthread_t);
32 size_t pthread_get_stacksize_np(pthread_t);
33 #endif
34
35 #if defined(_POSIX_VERSION) || defined(__native_client__)
36 #include <signal.h>
37
38 #if defined(__native_client__)
39 void nacl_shutdown_gc_thread(void);
40 #endif
41
42 typedef struct {
43         void *(*start_routine)(void*);
44         void *arg;
45         int flags;
46         MonoSemType registered;
47         HANDLE handle;
48 } StartInfo;
49
50 static void*
51 inner_start_thread (void *arg)
52 {
53         StartInfo *start_info = arg;
54         void *t_arg = start_info->arg;
55         int res;
56         void *(*start_func)(void*) = start_info->start_routine;
57         guint32 flags = start_info->flags;
58         void *result;
59         HANDLE handle;
60         MonoThreadInfo *info;
61
62         /* Register the thread with the io-layer */
63         handle = wapi_create_thread_handle ();
64         if (!handle) {
65                 res = MONO_SEM_POST (&(start_info->registered));
66                 g_assert (!res);
67                 return NULL;
68         }
69         start_info->handle = handle;
70
71         info = mono_thread_info_attach (&result);
72         info->runtime_thread = TRUE;
73         info->handle = handle;
74
75         if (flags & CREATE_SUSPENDED) {
76                 info->create_suspended = TRUE;
77                 MONO_SEM_INIT (&info->create_suspended_sem, 0);
78         }
79
80         /* start_info is not valid after this */
81         res = MONO_SEM_POST (&(start_info->registered));
82         g_assert (!res);
83         start_info = NULL;
84
85         if (flags & CREATE_SUSPENDED) {
86                 while (MONO_SEM_WAIT (&info->create_suspended_sem) != 0 &&
87                            errno == EINTR);
88                 MONO_SEM_DESTROY (&info->create_suspended_sem);
89         }
90
91         /* Run the actual main function of the thread */
92         result = start_func (t_arg);
93
94         /*
95         mono_thread_info_dettach ();
96         */
97
98 #if defined(__native_client__)
99         nacl_shutdown_gc_thread();
100 #endif
101
102         wapi_thread_handle_set_exited (handle, GPOINTER_TO_UINT (result));
103         /* This is needed by mono_threads_core_unregister () which is called later */
104         info->handle = NULL;
105
106         g_assert (mono_threads_get_callbacks ()->thread_exit);
107         mono_threads_get_callbacks ()->thread_exit (NULL);
108         g_assert_not_reached ();
109         return result;
110 }
111
112 HANDLE
113 mono_threads_core_create_thread (LPTHREAD_START_ROUTINE start_routine, gpointer arg, guint32 stack_size, guint32 creation_flags, MonoNativeThreadId *out_tid)
114 {
115         pthread_attr_t attr;
116         int res;
117         pthread_t thread;
118         StartInfo start_info;
119
120         res = pthread_attr_init (&attr);
121         g_assert (!res);
122
123         if (stack_size == 0) {
124 #if HAVE_VALGRIND_MEMCHECK_H
125                 if (RUNNING_ON_VALGRIND)
126                         stack_size = 1 << 20;
127                 else
128                         stack_size = (SIZEOF_VOID_P / 4) * 1024 * 1024;
129 #else
130                 stack_size = (SIZEOF_VOID_P / 4) * 1024 * 1024;
131 #endif
132         }
133
134 #ifdef PTHREAD_STACK_MIN
135         if (stack_size < PTHREAD_STACK_MIN)
136                 stack_size = PTHREAD_STACK_MIN;
137 #endif
138
139 #ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE
140         res = pthread_attr_setstacksize (&attr, stack_size);
141         g_assert (!res);
142 #endif
143
144         memset (&start_info, 0, sizeof (StartInfo));
145         start_info.start_routine = (gpointer)start_routine;
146         start_info.arg = arg;
147         start_info.flags = creation_flags;
148         MONO_SEM_INIT (&(start_info.registered), 0);
149
150         /* Actually start the thread */
151         res = mono_threads_get_callbacks ()->mono_gc_pthread_create (&thread, &attr, inner_start_thread, &start_info);
152         if (res) {
153                 // FIXME:
154                 g_assert_not_reached ();
155         }
156
157         /* Wait until the thread register itself in various places */
158         while (MONO_SEM_WAIT (&(start_info.registered)) != 0) {
159                 /*if (EINTR != errno) ABORT("sem_wait failed"); */
160         }
161         MONO_SEM_DESTROY (&(start_info.registered));
162
163         if (out_tid)
164                 *out_tid = thread;
165
166         return start_info.handle;
167 }
168
169 /*
170  * mono_threads_core_resume_created:
171  *
172  *   Resume a newly created thread created using CREATE_SUSPENDED.
173  */
174 void
175 mono_threads_core_resume_created (MonoThreadInfo *info, MonoNativeThreadId tid)
176 {
177         MONO_SEM_POST (&info->create_suspended_sem);
178 }
179
180 void
181 mono_threads_core_get_stack_bounds (guint8 **staddr, size_t *stsize)
182 {
183 #if defined(HAVE_PTHREAD_GET_STACKSIZE_NP) && defined(HAVE_PTHREAD_GET_STACKADDR_NP)
184         /* Mac OS X */
185         *staddr = (guint8*)pthread_get_stackaddr_np (pthread_self());
186         *stsize = pthread_get_stacksize_np (pthread_self());
187
188
189 #ifdef TARGET_OSX
190         /*
191          * Mavericks reports stack sizes as 512kb:
192          * http://permalink.gmane.org/gmane.comp.java.openjdk.hotspot.devel/11590
193          * https://bugs.openjdk.java.net/browse/JDK-8020753
194          */
195         if (*stsize == 512 * 1024)
196                 *stsize = 2048 * mono_pagesize ();
197 #endif
198
199         /* staddr points to the start of the stack, not the end */
200         *staddr -= *stsize;
201
202         /* When running under emacs, sometimes staddr is not aligned to a page size */
203         *staddr = (guint8*)((gssize)*staddr & ~(mono_pagesize() - 1));
204         return;
205
206 #elif (defined(HAVE_PTHREAD_GETATTR_NP) || defined(HAVE_PTHREAD_ATTR_GET_NP)) && defined(HAVE_PTHREAD_ATTR_GETSTACK)
207         /* Linux, BSD */
208
209         pthread_attr_t attr;
210         guint8 *current = (guint8*)&attr;
211
212         *staddr = NULL;
213         *stsize = (size_t)-1;
214
215         pthread_attr_init (&attr);
216
217 #if     defined(HAVE_PTHREAD_GETATTR_NP)
218         /* Linux */
219         pthread_getattr_np (pthread_self(), &attr);
220
221 #elif   defined(HAVE_PTHREAD_ATTR_GET_NP)
222         /* BSD */
223         pthread_attr_get_np (pthread_self(), &attr);
224
225 #else
226 #error  Cannot determine which API is needed to retrieve pthread attributes.
227 #endif
228
229         pthread_attr_getstack (&attr, (void**)staddr, stsize);
230         pthread_attr_destroy (&attr);
231
232         if (*staddr)
233                 g_assert ((current > *staddr) && (current < *staddr + *stsize));
234
235         /* When running under emacs, sometimes staddr is not aligned to a page size */
236         *staddr = (guint8*)((gssize)*staddr & ~(mono_pagesize () - 1));
237         return;
238
239 #elif defined(__OpenBSD__)
240         /* OpenBSD */
241         /* TODO :   Determine if this code is actually still needed. It may already be covered by the case above. */
242
243         pthread_attr_t attr;
244         guint8 *current = (guint8*)&attr;
245
246         *staddr = NULL;
247         *stsize = (size_t)-1;
248
249         pthread_attr_init (&attr);
250
251         stack_t ss;
252         int rslt;
253
254         rslt = pthread_stackseg_np(pthread_self(), &ss);
255         g_assert (rslt == 0);
256
257         *staddr = (guint8*)((size_t)ss.ss_sp - ss.ss_size);
258         *stsize = ss.ss_size;
259
260         pthread_attr_destroy (&attr);
261
262         if (*staddr)
263                 g_assert ((current > *staddr) && (current < *staddr + *stsize));
264
265         /* When running under emacs, sometimes staddr is not aligned to a page size */
266         *staddr = (guint8*)((gssize)*staddr & ~(mono_pagesize () - 1));
267         return;
268
269 #elif defined(sun) || defined(__native_client__)
270         /* Solaris/Illumos, NaCl */
271         pthread_attr_t attr;
272         pthread_attr_init (&attr);
273         pthread_attr_getstacksize (&attr, &stsize);
274         pthread_attr_destroy (&attr);
275         *staddr = NULL;
276         return;
277
278 #else
279         /* FIXME:   It'd be better to use the 'error' preprocessor macro here so we know
280                     at compile-time if the target platform isn't supported. */
281 #warning "Unable to determine how to retrieve a thread's stack-bounds for this platform in 'mono_thread_get_stack_bounds()'."
282         *staddr = NULL;
283         *stsize = 0;
284         return;
285 #endif
286 }
287
288 gboolean
289 mono_threads_core_yield (void)
290 {
291         return sched_yield () == 0;
292 }
293
294 void
295 mono_threads_core_exit (int exit_code)
296 {
297         MonoThreadInfo *current = mono_thread_info_current ();
298
299 #if defined(__native_client__)
300         nacl_shutdown_gc_thread();
301 #endif
302
303         wapi_thread_handle_set_exited (current->handle, exit_code);
304
305         g_assert (mono_threads_get_callbacks ()->thread_exit);
306         mono_threads_get_callbacks ()->thread_exit (NULL);
307 }
308
309 void
310 mono_threads_core_unregister (MonoThreadInfo *info)
311 {
312         if (info->handle) {
313                 wapi_thread_handle_set_exited (info->handle, 0);
314                 info->handle = NULL;
315         }
316 }
317
318 #if !defined (__MACH__)
319
320 #if !defined(__native_client__)
321 static void
322 suspend_signal_handler (int _dummy, siginfo_t *info, void *context)
323 {
324         MonoThreadInfo *current = mono_thread_info_current ();
325         gboolean ret;
326         
327         if (current->syscall_break_signal) {
328                 current->syscall_break_signal = FALSE;
329                 return;
330         }
331
332         ret = mono_threads_get_runtime_callbacks ()->thread_state_init_from_sigctx (&current->suspend_state, context);
333
334         /* thread_state_init_from_sigctx return FALSE if the current thread is detaching and suspend can't continue. */
335         current->suspend_can_continue = ret;
336
337         MONO_SEM_POST (&current->begin_suspend_semaphore);
338
339         /* This thread is doomed, all we can do is give up and let the suspender recover. */
340         if (!ret)
341                 return;
342
343         while (MONO_SEM_WAIT (&current->resume_semaphore) != 0) {
344                 /*if (EINTR != errno) ABORT("sem_wait failed"); */
345         }
346
347         if (current->async_target) {
348 #if MONO_ARCH_HAS_MONO_CONTEXT
349                 MonoContext tmp = current->suspend_state.ctx;
350                 mono_threads_get_runtime_callbacks ()->setup_async_callback (&tmp, current->async_target, current->user_data);
351                 current->async_target = current->user_data = NULL;
352                 mono_monoctx_to_sigctx (&tmp, context);
353 #else
354                 g_error ("The new interruption machinery requires a working mono-context");
355 #endif
356         }
357
358         MONO_SEM_POST (&current->finish_resume_semaphore);
359 }
360 #endif
361
362 static void
363 mono_posix_add_signal_handler (int signo, gpointer handler)
364 {
365 #if !defined(__native_client__)
366         /*FIXME, move the code from mini to utils and do the right thing!*/
367         struct sigaction sa;
368         struct sigaction previous_sa;
369         int ret;
370
371         sa.sa_sigaction = handler;
372         sigemptyset (&sa.sa_mask);
373         sa.sa_flags = SA_SIGINFO;
374         ret = sigaction (signo, &sa, &previous_sa);
375
376         g_assert (ret != -1);
377 #endif
378 }
379
380 void
381 mono_threads_init_platform (void)
382 {
383 #if !defined(__native_client__)
384         /*
385         FIXME we should use all macros from mini to make this more portable
386         FIXME it would be very sweet if sgen could end up using this too.
387         */
388         if (mono_thread_info_new_interrupt_enabled ())
389                 mono_posix_add_signal_handler (mono_thread_get_abort_signal (), suspend_signal_handler);
390 #endif
391 }
392
393 /*nothing to be done here since suspend always abort syscalls due using signals*/
394 void
395 mono_threads_core_interrupt (MonoThreadInfo *info)
396 {
397 }
398
399 int
400 mono_threads_pthread_kill (MonoThreadInfo *info, int signum)
401 {
402 #if defined (PLATFORM_ANDROID)
403         int result, old_errno = errno;
404         result = tkill (info->native_handle, signum);
405         if (result < 0) {
406                 result = errno;
407                 errno = old_errno;
408         }
409         return result;
410 #elif defined(__native_client__)
411         /* Workaround pthread_kill abort() in NaCl glibc. */
412         return 0;
413 #else
414         return pthread_kill (mono_thread_info_get_tid (info), signum);
415 #endif
416
417 }
418
419 void
420 mono_threads_core_abort_syscall (MonoThreadInfo *info)
421 {
422         /*
423         We signal a thread to break it from the urrent syscall.
424         This signal should not be interpreted as a suspend request.
425         */
426         info->syscall_break_signal = TRUE;
427         mono_threads_pthread_kill (info, mono_thread_get_abort_signal ());
428 }
429
430 gboolean
431 mono_threads_core_needs_abort_syscall (void)
432 {
433         return TRUE;
434 }
435
436 gboolean
437 mono_threads_core_suspend (MonoThreadInfo *info)
438 {
439         /*FIXME, check return value*/
440         mono_threads_pthread_kill (info, mono_thread_get_abort_signal ());
441         while (MONO_SEM_WAIT (&info->begin_suspend_semaphore) != 0) {
442                 /* g_assert (errno == EINTR); */
443         }
444         return info->suspend_can_continue;
445 }
446
447 gboolean
448 mono_threads_core_resume (MonoThreadInfo *info)
449 {
450         MONO_SEM_POST (&info->resume_semaphore);
451         while (MONO_SEM_WAIT (&info->finish_resume_semaphore) != 0) {
452                 /* g_assert (errno == EINTR); */
453         }
454
455         return TRUE;
456 }
457
458 void
459 mono_threads_platform_register (MonoThreadInfo *info)
460 {
461         MONO_SEM_INIT (&info->begin_suspend_semaphore, 0);
462
463 #if defined (PLATFORM_ANDROID)
464         info->native_handle = (gpointer) gettid ();
465 #endif
466 }
467
468 void
469 mono_threads_platform_free (MonoThreadInfo *info)
470 {
471         MONO_SEM_DESTROY (&info->begin_suspend_semaphore);
472 }
473
474 MonoNativeThreadId
475 mono_native_thread_id_get (void)
476 {
477         return pthread_self ();
478 }
479
480 gboolean
481 mono_native_thread_id_equals (MonoNativeThreadId id1, MonoNativeThreadId id2)
482 {
483         return pthread_equal (id1, id2);
484 }
485
486 /*
487  * mono_native_thread_create:
488  *
489  *   Low level thread creation function without any GC wrappers.
490  */
491 gboolean
492 mono_native_thread_create (MonoNativeThreadId *tid, gpointer func, gpointer arg)
493 {
494         return pthread_create (tid, NULL, func, arg) == 0;
495 }
496
497 #endif /*!defined (__MACH__)*/
498
499 #endif