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