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