[io-layer] Extract wapi_create_thread_handle
[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 /* For pthread_main_np, pthread_get_stackaddr_np and pthread_get_stacksize_np */
13 #if defined (__MACH__)
14 #define _DARWIN_C_SOURCE 1
15 #endif
16
17 #include <mono/utils/mono-threads.h>
18 #include <mono/utils/mono-threads-posix-signals.h>
19 #include <mono/utils/mono-coop-semaphore.h>
20 #include <mono/metadata/gc-internals.h>
21 #include <mono/utils/w32handle.h>
22
23 #include <errno.h>
24
25 #if defined(PLATFORM_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
26 #define USE_TKILL_ON_ANDROID 1
27 #endif
28
29 #ifdef USE_TKILL_ON_ANDROID
30 extern int tkill (pid_t tid, int signal);
31 #endif
32
33 #if defined(_POSIX_VERSION) || defined(__native_client__)
34
35 #include <pthread.h>
36
37 #include <sys/resource.h>
38
39 #if defined(__native_client__)
40 void nacl_shutdown_gc_thread(void);
41 #endif
42
43 static gpointer
44 thread_handle_create (void)
45 {
46         MonoW32HandleThread thread_data;
47         gpointer thread_handle;
48
49         thread_data.id = pthread_self ();
50         thread_data.owned_mutexes = g_ptr_array_new ();
51         thread_data.priority = THREAD_PRIORITY_NORMAL;
52
53         thread_handle = mono_w32handle_new (MONO_W32HANDLE_THREAD, (gpointer) &thread_data);
54         if (thread_handle == INVALID_HANDLE_VALUE)
55                 return NULL;
56
57         /* We need to keep the handle alive, as long as the corresponding managed
58          * thread object is alive. The handle is going to be unref when calling
59          * the finalizer on the MonoThreadInternal object */
60         mono_w32handle_ref (thread_handle);
61
62         return thread_handle;
63 }
64
65 typedef struct {
66         void *(*start_routine)(void*);
67         void *arg;
68         int flags;
69         gint32 priority;
70         MonoCoopSem registered;
71         HANDLE handle;
72 } StartInfo;
73
74 static void*
75 inner_start_thread (void *arg)
76 {
77         StartInfo *start_info = (StartInfo *) arg;
78         void *t_arg = start_info->arg;
79         int res;
80         void *(*start_func)(void*) = start_info->start_routine;
81         guint32 flags = start_info->flags;
82         void *result;
83         HANDLE handle;
84         MonoThreadInfo *info;
85
86         /* Register the thread with the io-layer */
87         handle = thread_handle_create ();
88         if (!handle) {
89                 mono_coop_sem_post (&(start_info->registered));
90                 return NULL;
91         }
92         start_info->handle = handle;
93
94         info = mono_thread_info_attach (&result);
95
96         info->runtime_thread = TRUE;
97         info->handle = handle;
98
99         wapi_init_thread_info_priority(handle, start_info->priority);
100
101         if (flags & CREATE_SUSPENDED) {
102                 info->create_suspended = TRUE;
103                 mono_coop_sem_init (&info->create_suspended_sem, 0);
104         }
105
106         /* start_info is not valid after this */
107         mono_coop_sem_post (&(start_info->registered));
108         start_info = NULL;
109
110         if (flags & CREATE_SUSPENDED) {
111                 res = mono_coop_sem_wait (&info->create_suspended_sem, MONO_SEM_FLAGS_NONE);
112                 g_assert (res != -1);
113
114                 mono_coop_sem_destroy (&info->create_suspended_sem);
115         }
116
117         /* Run the actual main function of the thread */
118         result = start_func (t_arg);
119
120         mono_threads_platform_exit (GPOINTER_TO_UINT (result));
121         g_assert_not_reached ();
122 }
123
124 HANDLE
125 mono_threads_platform_create_thread (LPTHREAD_START_ROUTINE start_routine, gpointer arg, MonoThreadParm *tp, MonoNativeThreadId *out_tid)
126 {
127         pthread_attr_t attr;
128         int res;
129         pthread_t thread;
130         StartInfo start_info;
131         guint32 stack_size;
132         int policy;
133         struct sched_param sp;
134
135         res = pthread_attr_init (&attr);
136         g_assert (!res);
137
138         if (tp->stack_size == 0) {
139 #if HAVE_VALGRIND_MEMCHECK_H
140                 if (RUNNING_ON_VALGRIND)
141                         stack_size = 1 << 20;
142                 else
143                         stack_size = (SIZEOF_VOID_P / 4) * 1024 * 1024;
144 #else
145                 stack_size = (SIZEOF_VOID_P / 4) * 1024 * 1024;
146 #endif
147         } else
148                 stack_size = tp->stack_size;
149
150 #ifdef PTHREAD_STACK_MIN
151         if (stack_size < PTHREAD_STACK_MIN)
152                 stack_size = PTHREAD_STACK_MIN;
153 #endif
154
155 #ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE
156         res = pthread_attr_setstacksize (&attr, stack_size);
157         g_assert (!res);
158 #endif
159
160         /*
161          * For policies that respect priorities set the prirority for the new thread
162          */ 
163         pthread_getschedparam(pthread_self(), &policy, &sp);
164         if ((policy == SCHED_FIFO) || (policy == SCHED_RR)) {
165                 sp.sched_priority = wapi_thread_priority_to_posix_priority (tp->priority, policy);
166                 res = pthread_attr_setschedparam (&attr, &sp);
167         }
168
169         memset (&start_info, 0, sizeof (StartInfo));
170         start_info.start_routine = (void *(*)(void *)) start_routine;
171         start_info.arg = arg;
172         start_info.flags = tp->creation_flags;
173         start_info.priority = tp->priority;
174         mono_coop_sem_init (&(start_info.registered), 0);
175
176         /* Actually start the thread */
177         res = mono_gc_pthread_create (&thread, &attr, inner_start_thread, &start_info);
178         if (res) {
179                 mono_coop_sem_destroy (&(start_info.registered));
180                 return NULL;
181         }
182
183         /* Wait until the thread register itself in various places */
184         res = mono_coop_sem_wait (&start_info.registered, MONO_SEM_FLAGS_NONE);
185         g_assert (res != -1);
186
187         mono_coop_sem_destroy (&(start_info.registered));
188
189         if (out_tid)
190                 *out_tid = thread;
191
192         return start_info.handle;
193 }
194
195 /*
196  * mono_threads_platform_resume_created:
197  *
198  *   Resume a newly created thread created using CREATE_SUSPENDED.
199  */
200 void
201 mono_threads_platform_resume_created (MonoThreadInfo *info, MonoNativeThreadId tid)
202 {
203         mono_coop_sem_post (&info->create_suspended_sem);
204 }
205
206 gboolean
207 mono_threads_platform_yield (void)
208 {
209         return sched_yield () == 0;
210 }
211
212 void
213 mono_threads_platform_exit (int exit_code)
214 {
215         MonoThreadInfo *current = mono_thread_info_current ();
216
217 #if defined(__native_client__)
218         nacl_shutdown_gc_thread();
219 #endif
220
221         mono_threads_platform_set_exited (current);
222
223         mono_thread_info_detach ();
224
225         pthread_exit (NULL);
226 }
227
228 void
229 mono_threads_platform_unregister (MonoThreadInfo *info)
230 {
231         if (info->handle) {
232                 mono_threads_platform_set_exited (info);
233                 info->handle = NULL;
234         }
235 }
236
237 HANDLE
238 mono_threads_platform_open_handle (void)
239 {
240         MonoThreadInfo *info;
241
242         info = mono_thread_info_current ();
243         g_assert (info);
244
245         if (!info->handle)
246                 info->handle = thread_handle_create ();
247         else
248                 mono_w32handle_ref (info->handle);
249         return info->handle;
250 }
251
252 int
253 mono_threads_get_max_stack_size (void)
254 {
255         struct rlimit lim;
256
257         /* If getrlimit fails, we don't enforce any limits. */
258         if (getrlimit (RLIMIT_STACK, &lim))
259                 return INT_MAX;
260         /* rlim_t is an unsigned long long on 64bits OSX but we want an int response. */
261         if (lim.rlim_max > (rlim_t)INT_MAX)
262                 return INT_MAX;
263         return (int)lim.rlim_max;
264 }
265
266 HANDLE
267 mono_threads_platform_open_thread_handle (HANDLE handle, MonoNativeThreadId tid)
268 {
269         mono_w32handle_ref (handle);
270
271         return handle;
272 }
273
274 int
275 mono_threads_pthread_kill (MonoThreadInfo *info, int signum)
276 {
277         THREADS_SUSPEND_DEBUG ("sending signal %d to %p[%p]\n", signum, info, mono_thread_info_get_tid (info));
278 #ifdef USE_TKILL_ON_ANDROID
279         int result, old_errno = errno;
280         result = tkill (info->native_handle, signum);
281         if (result < 0) {
282                 result = errno;
283                 errno = old_errno;
284         }
285         return result;
286 #elif defined(__native_client__)
287         /* Workaround pthread_kill abort() in NaCl glibc. */
288         return 0;
289 #elif !defined(HAVE_PTHREAD_KILL)
290         g_error ("pthread_kill() is not supported by this platform");
291 #else
292         return pthread_kill (mono_thread_info_get_tid (info), signum);
293 #endif
294 }
295
296 MonoNativeThreadId
297 mono_native_thread_id_get (void)
298 {
299         return pthread_self ();
300 }
301
302 gboolean
303 mono_native_thread_id_equals (MonoNativeThreadId id1, MonoNativeThreadId id2)
304 {
305         return pthread_equal (id1, id2);
306 }
307
308 /*
309  * mono_native_thread_create:
310  *
311  *   Low level thread creation function without any GC wrappers.
312  */
313 gboolean
314 mono_native_thread_create (MonoNativeThreadId *tid, gpointer func, gpointer arg)
315 {
316         return pthread_create (tid, NULL, (void *(*)(void *)) func, arg) == 0;
317 }
318
319 void
320 mono_native_thread_set_name (MonoNativeThreadId tid, const char *name)
321 {
322 #ifdef __MACH__
323         /*
324          * We can't set the thread name for other threads, but we can at least make
325          * it work for threads that try to change their own name.
326          */
327         if (tid != mono_native_thread_id_get ())
328                 return;
329
330         if (!name) {
331                 pthread_setname_np ("");
332         } else {
333                 char n [63];
334
335                 strncpy (n, name, 63);
336                 n [62] = '\0';
337                 pthread_setname_np (n);
338         }
339 #elif defined (__NetBSD__)
340         if (!name) {
341                 pthread_setname_np (tid, "%s", (void*)"");
342         } else {
343                 char n [PTHREAD_MAX_NAMELEN_NP];
344
345                 strncpy (n, name, PTHREAD_MAX_NAMELEN_NP);
346                 n [PTHREAD_MAX_NAMELEN_NP - 1] = '\0';
347                 pthread_setname_np (tid, "%s", (void*)n);
348         }
349 #elif defined (HAVE_PTHREAD_SETNAME_NP)
350         if (!name) {
351                 pthread_setname_np (tid, "");
352         } else {
353                 char n [16];
354
355                 strncpy (n, name, 16);
356                 n [15] = '\0';
357                 pthread_setname_np (tid, n);
358         }
359 #endif
360 }
361
362 void
363 mono_threads_platform_set_exited (MonoThreadInfo *info)
364 {
365         MonoW32HandleThread *thread_data;
366         gpointer mutex_handle;
367         int i, thr_ret;
368         pid_t pid;
369         pthread_t tid;
370
371         if (!info->handle || mono_w32handle_issignalled (info->handle) || mono_w32handle_get_type (info->handle) == MONO_W32HANDLE_UNUSED) {
372                 /* We must have already deliberately finished
373                  * with this thread, so don't do any more now */
374                 return;
375         }
376
377         if (!mono_w32handle_lookup (info->handle, MONO_W32HANDLE_THREAD, (gpointer*) &thread_data))
378                 g_error ("unknown thread handle %p", info->handle);
379
380         pid = wapi_getpid ();
381         tid = pthread_self ();
382
383         for (i = 0; i < thread_data->owned_mutexes->len; i++) {
384                 mutex_handle = g_ptr_array_index (thread_data->owned_mutexes, i);
385                 wapi_mutex_abandon (mutex_handle, pid, tid);
386                 mono_thread_info_disown_mutex (info, mutex_handle);
387         }
388
389         g_ptr_array_free (thread_data->owned_mutexes, TRUE);
390
391         thr_ret = mono_w32handle_lock_handle (info->handle);
392         g_assert (thr_ret == 0);
393
394         mono_w32handle_set_signal_state (info->handle, TRUE, TRUE);
395
396         thr_ret = mono_w32handle_unlock_handle (info->handle);
397         g_assert (thr_ret == 0);
398
399         /* The thread is no longer active, so unref it */
400         mono_w32handle_unref (info->handle);
401
402         info->handle = NULL;
403 }
404
405 void
406 mono_threads_platform_describe (MonoThreadInfo *info, GString *text)
407 {
408         MonoW32HandleThread *thread_data;
409         int i;
410
411         g_assert (info->handle);
412
413         if (!mono_w32handle_lookup (info->handle, MONO_W32HANDLE_THREAD, (gpointer*) &thread_data))
414                 g_error ("unknown thread handle %p", info->handle);
415
416         g_string_append_printf (text, "thread handle %p state : ", info->handle);
417
418         mono_thread_info_describe_interrupt_token (info, text);
419
420         g_string_append_printf (text, ", owns (");
421         for (i = 0; i < thread_data->owned_mutexes->len; i++)
422                 g_string_append_printf (text, i > 0 ? ", %p" : "%p", g_ptr_array_index (thread_data->owned_mutexes, i));
423         g_string_append_printf (text, ")");
424 }
425
426 void
427 mono_threads_platform_own_mutex (MonoThreadInfo *info, gpointer mutex_handle)
428 {
429         MonoW32HandleThread *thread_data;
430
431         g_assert (info->handle);
432
433         if (!mono_w32handle_lookup (info->handle, MONO_W32HANDLE_THREAD, (gpointer*) &thread_data))
434                 g_error ("unknown thread handle %p", info->handle);
435
436         mono_w32handle_ref (mutex_handle);
437
438         g_ptr_array_add (thread_data->owned_mutexes, mutex_handle);
439 }
440
441 void
442 mono_threads_platform_disown_mutex (MonoThreadInfo *info, gpointer mutex_handle)
443 {
444         MonoW32HandleThread *thread_data;
445
446         g_assert (info->handle);
447
448         if (!mono_w32handle_lookup (info->handle, MONO_W32HANDLE_THREAD, (gpointer*) &thread_data))
449                 g_error ("unknown thread handle %p", info->handle);
450
451         mono_w32handle_unref (mutex_handle);
452
453         g_ptr_array_remove (thread_data->owned_mutexes, mutex_handle);
454 }
455
456 #endif /* defined(_POSIX_VERSION) || defined(__native_client__) */
457
458 #if defined(USE_POSIX_BACKEND)
459
460 gboolean
461 mono_threads_suspend_begin_async_suspend (MonoThreadInfo *info, gboolean interrupt_kernel)
462 {
463         int sig = interrupt_kernel ? mono_threads_posix_get_abort_signal () :  mono_threads_posix_get_suspend_signal ();
464
465         if (!mono_threads_pthread_kill (info, sig)) {
466                 mono_threads_add_to_pending_operation_set (info);
467                 return TRUE;
468         }
469         return FALSE;
470 }
471
472 gboolean
473 mono_threads_suspend_check_suspend_result (MonoThreadInfo *info)
474 {
475         return info->suspend_can_continue;
476 }
477
478 /*
479 This begins async resume. This function must do the following:
480
481 - Install an async target if one was requested.
482 - Notify the target to resume.
483 */
484 gboolean
485 mono_threads_suspend_begin_async_resume (MonoThreadInfo *info)
486 {
487         mono_threads_add_to_pending_operation_set (info);
488         return mono_threads_pthread_kill (info, mono_threads_posix_get_restart_signal ()) == 0;
489 }
490
491 void
492 mono_threads_suspend_register (MonoThreadInfo *info)
493 {
494 #if defined (PLATFORM_ANDROID)
495         info->native_handle = gettid ();
496 #endif
497
498         g_assert (!info->handle);
499         info->handle = thread_handle_create ();
500 }
501
502 void
503 mono_threads_suspend_free (MonoThreadInfo *info)
504 {
505 }
506
507 void
508 mono_threads_suspend_init (void)
509 {
510         mono_threads_posix_init_signals (MONO_THREADS_POSIX_INIT_SIGNALS_SUSPEND_RESTART);
511 }
512
513 #endif /* defined(USE_POSIX_BACKEND) */