[semaphore] Cleanup
[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-internals.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                 res = mono_sem_wait (&info->create_suspended_sem, MONO_SEM_FLAGS_NONE);
86                 g_assert (res != -1);
87
88                 mono_sem_destroy (&info->create_suspended_sem);
89         }
90
91         MONO_FINISH_BLOCKING;
92         /* Run the actual main function of the thread */
93         result = start_func (t_arg);
94
95         mono_threads_core_exit (GPOINTER_TO_UINT (result));
96         g_assert_not_reached ();
97 }
98
99 HANDLE
100 mono_threads_core_create_thread (LPTHREAD_START_ROUTINE start_routine, gpointer arg, guint32 stack_size, guint32 creation_flags, MonoNativeThreadId *out_tid)
101 {
102         pthread_attr_t attr;
103         int res;
104         pthread_t thread;
105         StartInfo start_info;
106
107         res = pthread_attr_init (&attr);
108         g_assert (!res);
109
110         if (stack_size == 0) {
111 #if HAVE_VALGRIND_MEMCHECK_H
112                 if (RUNNING_ON_VALGRIND)
113                         stack_size = 1 << 20;
114                 else
115                         stack_size = (SIZEOF_VOID_P / 4) * 1024 * 1024;
116 #else
117                 stack_size = (SIZEOF_VOID_P / 4) * 1024 * 1024;
118 #endif
119         }
120
121 #ifdef PTHREAD_STACK_MIN
122         if (stack_size < PTHREAD_STACK_MIN)
123                 stack_size = PTHREAD_STACK_MIN;
124 #endif
125
126 #ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE
127         res = pthread_attr_setstacksize (&attr, stack_size);
128         g_assert (!res);
129 #endif
130
131         memset (&start_info, 0, sizeof (StartInfo));
132         start_info.start_routine = (void *(*)(void *)) start_routine;
133         start_info.arg = arg;
134         start_info.flags = creation_flags;
135         mono_sem_init (&(start_info.registered), 0);
136
137         /* Actually start the thread */
138         res = mono_gc_pthread_create (&thread, &attr, inner_start_thread, &start_info);
139         if (res) {
140                 mono_sem_destroy (&(start_info.registered));
141                 return NULL;
142         }
143
144         MONO_TRY_BLOCKING;
145         /* Wait until the thread register itself in various places */
146         res = mono_sem_wait (&start_info.registered, MONO_SEM_FLAGS_NONE);
147         g_assert (res != -1);
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) */