Changed link from GUID to URL
[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/metadata/gc-internal.h>
20
21 #include <errno.h>
22
23 #if defined(PLATFORM_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
24 #define USE_TKILL_ON_ANDROID 1
25 #endif
26
27 #ifdef USE_TKILL_ON_ANDROID
28 extern int tkill (pid_t tid, int signal);
29 #endif
30
31 #if defined(_POSIX_VERSION) || defined(__native_client__)
32
33 #include <sys/resource.h>
34
35 #if defined(__native_client__)
36 void nacl_shutdown_gc_thread(void);
37 #endif
38
39 typedef struct {
40         void *(*start_routine)(void*);
41         void *arg;
42         int flags;
43         MonoSemType registered;
44         HANDLE handle;
45 } StartInfo;
46
47 static void*
48 inner_start_thread (void *arg)
49 {
50         StartInfo *start_info = (StartInfo *) arg;
51         void *t_arg = start_info->arg;
52         int res;
53         void *(*start_func)(void*) = start_info->start_routine;
54         guint32 flags = start_info->flags;
55         void *result;
56         HANDLE handle;
57         MonoThreadInfo *info;
58
59         /* Register the thread with the io-layer */
60         handle = wapi_create_thread_handle ();
61         if (!handle) {
62                 res = MONO_SEM_POST (&(start_info->registered));
63                 g_assert (!res);
64                 return NULL;
65         }
66         start_info->handle = handle;
67
68         info = mono_thread_info_attach (&result);
69         MONO_PREPARE_BLOCKING;
70
71         info->runtime_thread = TRUE;
72         info->handle = handle;
73
74         if (flags & CREATE_SUSPENDED) {
75                 info->create_suspended = TRUE;
76                 MONO_SEM_INIT (&info->create_suspended_sem, 0);
77         }
78
79         /* start_info is not valid after this */
80         res = MONO_SEM_POST (&(start_info->registered));
81         g_assert (!res);
82         start_info = NULL;
83
84         if (flags & CREATE_SUSPENDED) {
85                 while (MONO_SEM_WAIT (&info->create_suspended_sem) != 0 &&
86                            errno == EINTR);
87                 MONO_SEM_DESTROY (&info->create_suspended_sem);
88         }
89
90         MONO_FINISH_BLOCKING;
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_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_SEM_DESTROY (&(start_info.registered));
140                 return NULL;
141         }
142
143         MONO_TRY_BLOCKING;
144         /* Wait until the thread register itself in various places */
145         while (MONO_SEM_WAIT (&(start_info.registered)) != 0) {
146                 /*if (EINTR != errno) ABORT("sem_wait failed"); */
147         }
148         MONO_FINISH_TRY_BLOCKING;
149
150         MONO_SEM_DESTROY (&(start_info.registered));
151
152         if (out_tid)
153                 *out_tid = thread;
154
155         return start_info.handle;
156 }
157
158 /*
159  * mono_threads_core_resume_created:
160  *
161  *   Resume a newly created thread created using CREATE_SUSPENDED.
162  */
163 void
164 mono_threads_core_resume_created (MonoThreadInfo *info, MonoNativeThreadId tid)
165 {
166         MONO_SEM_POST (&info->create_suspended_sem);
167 }
168
169 gboolean
170 mono_threads_core_yield (void)
171 {
172         return sched_yield () == 0;
173 }
174
175 void
176 mono_threads_core_exit (int exit_code)
177 {
178         MonoThreadInfo *current = mono_thread_info_current ();
179
180 #if defined(__native_client__)
181         nacl_shutdown_gc_thread();
182 #endif
183
184         wapi_thread_handle_set_exited (current->handle, exit_code);
185
186         mono_thread_info_detach ();
187
188         pthread_exit (NULL);
189 }
190
191 void
192 mono_threads_core_unregister (MonoThreadInfo *info)
193 {
194         if (info->handle) {
195                 wapi_thread_handle_set_exited (info->handle, 0);
196                 info->handle = NULL;
197         }
198 }
199
200 HANDLE
201 mono_threads_core_open_handle (void)
202 {
203         MonoThreadInfo *info;
204
205         info = mono_thread_info_current ();
206         g_assert (info);
207
208         if (!info->handle)
209                 info->handle = wapi_create_thread_handle ();
210         else
211                 wapi_ref_thread_handle (info->handle);
212         return info->handle;
213 }
214
215 int
216 mono_threads_get_max_stack_size (void)
217 {
218         struct rlimit lim;
219
220         /* If getrlimit fails, we don't enforce any limits. */
221         if (getrlimit (RLIMIT_STACK, &lim))
222                 return INT_MAX;
223         /* rlim_t is an unsigned long long on 64bits OSX but we want an int response. */
224         if (lim.rlim_max > (rlim_t)INT_MAX)
225                 return INT_MAX;
226         return (int)lim.rlim_max;
227 }
228
229 HANDLE
230 mono_threads_core_open_thread_handle (HANDLE handle, MonoNativeThreadId tid)
231 {
232         wapi_ref_thread_handle (handle);
233
234         return handle;
235 }
236
237 int
238 mono_threads_pthread_kill (MonoThreadInfo *info, int signum)
239 {
240         THREADS_SUSPEND_DEBUG ("sending signal %d to %p[%p]\n", signum, info, mono_thread_info_get_tid (info));
241 #ifdef USE_TKILL_ON_ANDROID
242         int result, old_errno = errno;
243         result = tkill (info->native_handle, signum);
244         if (result < 0) {
245                 result = errno;
246                 errno = old_errno;
247         }
248         return result;
249 #elif defined(__native_client__)
250         /* Workaround pthread_kill abort() in NaCl glibc. */
251         return 0;
252 #elif !defined(HAVE_PTHREAD_KILL)
253         g_error ("pthread_kill() is not supported by this platform");
254 #else
255         return pthread_kill (mono_thread_info_get_tid (info), signum);
256 #endif
257 }
258
259 MonoNativeThreadId
260 mono_native_thread_id_get (void)
261 {
262         return pthread_self ();
263 }
264
265 gboolean
266 mono_native_thread_id_equals (MonoNativeThreadId id1, MonoNativeThreadId id2)
267 {
268         return pthread_equal (id1, id2);
269 }
270
271 /*
272  * mono_native_thread_create:
273  *
274  *   Low level thread creation function without any GC wrappers.
275  */
276 gboolean
277 mono_native_thread_create (MonoNativeThreadId *tid, gpointer func, gpointer arg)
278 {
279         return pthread_create (tid, NULL, (void *(*)(void *)) func, arg) == 0;
280 }
281
282 void
283 mono_threads_core_set_name (MonoNativeThreadId tid, const char *name)
284 {
285 #if defined (HAVE_PTHREAD_SETNAME_NP) && !defined (__MACH__)
286         if (!name) {
287                 pthread_setname_np (tid, "");
288         } else {
289                 char n [16];
290
291                 strncpy (n, name, 16);
292                 n [15] = '\0';
293                 pthread_setname_np (tid, n);
294         }
295 #endif
296 }
297
298 #endif /* defined(_POSIX_VERSION) || defined(__native_client__) */
299
300 #if defined(USE_POSIX_BACKEND)
301
302 gboolean
303 mono_threads_core_begin_async_suspend (MonoThreadInfo *info, gboolean interrupt_kernel)
304 {
305         int sig = interrupt_kernel ? mono_threads_posix_get_abort_signal () :  mono_threads_posix_get_suspend_signal ();
306
307         if (!mono_threads_pthread_kill (info, sig)) {
308                 mono_threads_add_to_pending_operation_set (info);
309                 return TRUE;
310         }
311         return FALSE;
312 }
313
314 gboolean
315 mono_threads_core_check_suspend_result (MonoThreadInfo *info)
316 {
317         return info->suspend_can_continue;
318 }
319
320 /*
321 This begins async resume. This function must do the following:
322
323 - Install an async target if one was requested.
324 - Notify the target to resume.
325 */
326 gboolean
327 mono_threads_core_begin_async_resume (MonoThreadInfo *info)
328 {
329         mono_threads_add_to_pending_operation_set (info);
330         return mono_threads_pthread_kill (info, mono_threads_posix_get_restart_signal ()) == 0;
331 }
332
333 void
334 mono_threads_platform_register (MonoThreadInfo *info)
335 {
336 #if defined (PLATFORM_ANDROID)
337         info->native_handle = gettid ();
338 #endif
339 }
340
341 void
342 mono_threads_platform_free (MonoThreadInfo *info)
343 {
344 }
345
346 void
347 mono_threads_init_platform (void)
348 {
349         mono_threads_posix_init_signals (MONO_THREADS_POSIX_INIT_SIGNALS_SUSPEND_RESTART);
350 }
351
352 #endif /* defined(USE_POSIX_BACKEND) */