Merge pull request #2819 from BrzVlad/fix-major-log
[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
22 #include <errno.h>
23
24 #if defined(PLATFORM_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
25 #define USE_TKILL_ON_ANDROID 1
26 #endif
27
28 #ifdef USE_TKILL_ON_ANDROID
29 extern int tkill (pid_t tid, int signal);
30 #endif
31
32 #if defined(_POSIX_VERSION) || defined(__native_client__)
33
34 #include <sys/resource.h>
35
36 #if defined(__native_client__)
37 void nacl_shutdown_gc_thread(void);
38 #endif
39
40 typedef struct {
41         void *(*start_routine)(void*);
42         void *arg;
43         int flags;
44         MonoCoopSem registered;
45         HANDLE handle;
46 } StartInfo;
47
48 static void*
49 inner_start_thread (void *arg)
50 {
51         StartInfo *start_info = (StartInfo *) arg;
52         void *t_arg = start_info->arg;
53         int res;
54         void *(*start_func)(void*) = start_info->start_routine;
55         guint32 flags = start_info->flags;
56         void *result;
57         HANDLE handle;
58         MonoThreadInfo *info;
59
60         /* Register the thread with the io-layer */
61         handle = wapi_create_thread_handle ();
62         if (!handle) {
63                 res = mono_coop_sem_post (&(start_info->registered));
64                 g_assert (!res);
65                 return NULL;
66         }
67         start_info->handle = handle;
68
69         info = mono_thread_info_attach (&result);
70
71         info->runtime_thread = TRUE;
72         info->handle = handle;
73
74         if (flags & CREATE_SUSPENDED) {
75                 info->create_suspended = TRUE;
76                 mono_coop_sem_init (&info->create_suspended_sem, 0);
77         }
78
79         /* start_info is not valid after this */
80         res = mono_coop_sem_post (&(start_info->registered));
81         g_assert (!res);
82         start_info = NULL;
83
84         if (flags & CREATE_SUSPENDED) {
85                 res = mono_coop_sem_wait (&info->create_suspended_sem, MONO_SEM_FLAGS_NONE);
86                 g_assert (res != -1);
87
88                 mono_coop_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         mono_threads_core_exit (GPOINTER_TO_UINT (result));
95         g_assert_not_reached ();
96 }
97
98 HANDLE
99 mono_threads_core_create_thread (LPTHREAD_START_ROUTINE start_routine, gpointer arg, guint32 stack_size, guint32 creation_flags, MonoNativeThreadId *out_tid)
100 {
101         pthread_attr_t attr;
102         int res;
103         pthread_t thread;
104         StartInfo start_info;
105
106         res = pthread_attr_init (&attr);
107         g_assert (!res);
108
109         if (stack_size == 0) {
110 #if HAVE_VALGRIND_MEMCHECK_H
111                 if (RUNNING_ON_VALGRIND)
112                         stack_size = 1 << 20;
113                 else
114                         stack_size = (SIZEOF_VOID_P / 4) * 1024 * 1024;
115 #else
116                 stack_size = (SIZEOF_VOID_P / 4) * 1024 * 1024;
117 #endif
118         }
119
120 #ifdef PTHREAD_STACK_MIN
121         if (stack_size < PTHREAD_STACK_MIN)
122                 stack_size = PTHREAD_STACK_MIN;
123 #endif
124
125 #ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE
126         res = pthread_attr_setstacksize (&attr, stack_size);
127         g_assert (!res);
128 #endif
129
130         memset (&start_info, 0, sizeof (StartInfo));
131         start_info.start_routine = (void *(*)(void *)) start_routine;
132         start_info.arg = arg;
133         start_info.flags = creation_flags;
134         mono_coop_sem_init (&(start_info.registered), 0);
135
136         /* Actually start the thread */
137         res = mono_gc_pthread_create (&thread, &attr, inner_start_thread, &start_info);
138         if (res) {
139                 mono_coop_sem_destroy (&(start_info.registered));
140                 return NULL;
141         }
142
143         /* Wait until the thread register itself in various places */
144         res = mono_coop_sem_wait (&start_info.registered, MONO_SEM_FLAGS_NONE);
145         g_assert (res != -1);
146
147         mono_coop_sem_destroy (&(start_info.registered));
148
149         if (out_tid)
150                 *out_tid = thread;
151
152         return start_info.handle;
153 }
154
155 /*
156  * mono_threads_core_resume_created:
157  *
158  *   Resume a newly created thread created using CREATE_SUSPENDED.
159  */
160 void
161 mono_threads_core_resume_created (MonoThreadInfo *info, MonoNativeThreadId tid)
162 {
163         mono_coop_sem_post (&info->create_suspended_sem);
164 }
165
166 gboolean
167 mono_threads_core_yield (void)
168 {
169         return sched_yield () == 0;
170 }
171
172 void
173 mono_threads_core_exit (int exit_code)
174 {
175         MonoThreadInfo *current = mono_thread_info_current ();
176
177 #if defined(__native_client__)
178         nacl_shutdown_gc_thread();
179 #endif
180
181         wapi_thread_handle_set_exited (current->handle, exit_code);
182
183         mono_thread_info_detach ();
184
185         pthread_exit (NULL);
186 }
187
188 void
189 mono_threads_core_unregister (MonoThreadInfo *info)
190 {
191         if (info->handle) {
192                 wapi_thread_handle_set_exited (info->handle, 0);
193                 info->handle = NULL;
194         }
195 }
196
197 HANDLE
198 mono_threads_core_open_handle (void)
199 {
200         MonoThreadInfo *info;
201
202         info = mono_thread_info_current ();
203         g_assert (info);
204
205         if (!info->handle)
206                 info->handle = wapi_create_thread_handle ();
207         else
208                 wapi_ref_thread_handle (info->handle);
209         return info->handle;
210 }
211
212 int
213 mono_threads_get_max_stack_size (void)
214 {
215         struct rlimit lim;
216
217         /* If getrlimit fails, we don't enforce any limits. */
218         if (getrlimit (RLIMIT_STACK, &lim))
219                 return INT_MAX;
220         /* rlim_t is an unsigned long long on 64bits OSX but we want an int response. */
221         if (lim.rlim_max > (rlim_t)INT_MAX)
222                 return INT_MAX;
223         return (int)lim.rlim_max;
224 }
225
226 HANDLE
227 mono_threads_core_open_thread_handle (HANDLE handle, MonoNativeThreadId tid)
228 {
229         wapi_ref_thread_handle (handle);
230
231         return handle;
232 }
233
234 int
235 mono_threads_pthread_kill (MonoThreadInfo *info, int signum)
236 {
237         THREADS_SUSPEND_DEBUG ("sending signal %d to %p[%p]\n", signum, info, mono_thread_info_get_tid (info));
238 #ifdef USE_TKILL_ON_ANDROID
239         int result, old_errno = errno;
240         result = tkill (info->native_handle, signum);
241         if (result < 0) {
242                 result = errno;
243                 errno = old_errno;
244         }
245         return result;
246 #elif defined(__native_client__)
247         /* Workaround pthread_kill abort() in NaCl glibc. */
248         return 0;
249 #elif !defined(HAVE_PTHREAD_KILL)
250         g_error ("pthread_kill() is not supported by this platform");
251 #else
252         return pthread_kill (mono_thread_info_get_tid (info), signum);
253 #endif
254 }
255
256 MonoNativeThreadId
257 mono_native_thread_id_get (void)
258 {
259         return pthread_self ();
260 }
261
262 gboolean
263 mono_native_thread_id_equals (MonoNativeThreadId id1, MonoNativeThreadId id2)
264 {
265         return pthread_equal (id1, id2);
266 }
267
268 /*
269  * mono_native_thread_create:
270  *
271  *   Low level thread creation function without any GC wrappers.
272  */
273 gboolean
274 mono_native_thread_create (MonoNativeThreadId *tid, gpointer func, gpointer arg)
275 {
276         return pthread_create (tid, NULL, (void *(*)(void *)) func, arg) == 0;
277 }
278
279 void
280 mono_threads_core_set_name (MonoNativeThreadId tid, const char *name)
281 {
282 #ifdef __MACH__
283         /*
284          * We can't set the thread name for other threads, but we can at least make
285          * it work for threads that try to change their own name.
286          */
287         if (tid != mono_native_thread_id_get ())
288                 return;
289
290         if (!name) {
291                 pthread_setname_np ("");
292         } else {
293                 char n [63];
294
295                 strncpy (n, name, 63);
296                 n [62] = '\0';
297                 pthread_setname_np (n);
298         }
299 #elif defined (HAVE_PTHREAD_SETNAME_NP)
300         if (!name) {
301                 pthread_setname_np (tid, "");
302         } else {
303                 char n [16];
304
305                 strncpy (n, name, 16);
306                 n [15] = '\0';
307                 pthread_setname_np (tid, n);
308         }
309 #endif
310 }
311
312 #endif /* defined(_POSIX_VERSION) || defined(__native_client__) */
313
314 #if defined(USE_POSIX_BACKEND)
315
316 gboolean
317 mono_threads_core_begin_async_suspend (MonoThreadInfo *info, gboolean interrupt_kernel)
318 {
319         int sig = interrupt_kernel ? mono_threads_posix_get_abort_signal () :  mono_threads_posix_get_suspend_signal ();
320
321         if (!mono_threads_pthread_kill (info, sig)) {
322                 mono_threads_add_to_pending_operation_set (info);
323                 return TRUE;
324         }
325         return FALSE;
326 }
327
328 gboolean
329 mono_threads_core_check_suspend_result (MonoThreadInfo *info)
330 {
331         return info->suspend_can_continue;
332 }
333
334 /*
335 This begins async resume. This function must do the following:
336
337 - Install an async target if one was requested.
338 - Notify the target to resume.
339 */
340 gboolean
341 mono_threads_core_begin_async_resume (MonoThreadInfo *info)
342 {
343         mono_threads_add_to_pending_operation_set (info);
344         return mono_threads_pthread_kill (info, mono_threads_posix_get_restart_signal ()) == 0;
345 }
346
347 void
348 mono_threads_platform_register (MonoThreadInfo *info)
349 {
350 #if defined (PLATFORM_ANDROID)
351         info->native_handle = gettid ();
352 #endif
353 }
354
355 void
356 mono_threads_platform_free (MonoThreadInfo *info)
357 {
358 }
359
360 void
361 mono_threads_init_platform (void)
362 {
363         mono_threads_posix_init_signals (MONO_THREADS_POSIX_INIT_SIGNALS_SUSPEND_RESTART);
364 }
365
366 #endif /* defined(USE_POSIX_BACKEND) */