[runtime] Fix regressions caused by 9e5b23eee3a38cf03059542666c6762cc4885697.
[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 #include <mono/utils/mono-compiler.h>
13 #include <mono/utils/mono-semaphore.h>
14 #include <mono/utils/mono-threads.h>
15 #include <mono/utils/mono-tls.h>
16 #include <mono/utils/gc_wrapper.h>
17 #include <mono/metadata/threads-types.h>
18
19 #include <errno.h>
20
21 #if defined(PLATFORM_ANDROID)
22 extern int tkill (pid_t tid, int signal);
23 #endif
24
25 #if defined(_POSIX_VERSION) || defined(__native_client__)
26 #include <signal.h>
27
28 #if defined(__native_client__)
29 void nacl_shutdown_gc_thread(void);
30 #endif
31
32 typedef struct {
33         void *(*start_routine)(void*);
34         void *arg;
35         int flags;
36         MonoSemType registered;
37         HANDLE handle;
38 } StartInfo;
39
40 static void*
41 inner_start_thread (void *arg)
42 {
43         StartInfo *start_info = arg;
44         void *t_arg = start_info->arg;
45         int res;
46         void *(*start_func)(void*) = start_info->start_routine;
47         guint32 flags = start_info->flags;
48         void *result;
49         HANDLE handle;
50         MonoThreadInfo *info;
51
52         /* Register the thread with the io-layer */
53         handle = wapi_create_thread_handle ();
54         if (!handle) {
55                 res = MONO_SEM_POST (&(start_info->registered));
56                 g_assert (!res);
57                 return NULL;
58         }
59         start_info->handle = handle;
60
61         if (!(flags & CREATE_NO_DETACH)) {
62                 res = mono_gc_pthread_detach (pthread_self ());
63                 g_assert (!res);
64         }
65
66         info = mono_thread_info_attach (&result);
67         info->runtime_thread = TRUE;
68
69         /* start_info is not valid after this */
70         res = MONO_SEM_POST (&(start_info->registered));
71         g_assert (!res);
72         start_info = NULL;
73
74         if (flags & CREATE_SUSPENDED)
75                 wapi_thread_suspend (handle);
76
77         /* Run the actual main function of the thread */
78         result = start_func (t_arg);
79
80         /*
81         g_assert (!mono_domain_get ());
82         mono_thread_info_dettach ();
83         */
84
85 #if defined(__native_client__)
86         nacl_shutdown_gc_thread();
87 #endif
88
89         wapi_thread_set_exit_code (GPOINTER_TO_UINT (result), handle);
90
91         // FIXME: Why is this needed ?
92         mono_gc_pthread_exit (NULL);
93
94         g_assert_not_reached ();
95         return result;
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 = (gpointer)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_threads_get_callbacks ()->mono_gc_pthread_create (&thread, &attr, inner_start_thread, &start_info);
138         if (res) {
139                 // FIXME:
140                 g_assert_not_reached ();
141         }
142
143         /* Wait until the thread register itself in various places */
144         while (MONO_SEM_WAIT (&(start_info.registered)) != 0) {
145                 /*if (EINTR != errno) ABORT("sem_wait failed"); */
146         }
147         MONO_SEM_DESTROY (&(start_info.registered));
148
149         if (out_tid)
150                 *out_tid = thread;
151
152         return start_info.handle;
153 }
154
155 #if !defined (__MACH__)
156
157 #if !defined(__native_client__)
158 static void
159 suspend_signal_handler (int _dummy, siginfo_t *info, void *context)
160 {
161         MonoThreadInfo *current = mono_thread_info_current ();
162         gboolean ret;
163         
164         if (current->syscall_break_signal) {
165                 current->syscall_break_signal = FALSE;
166                 return;
167         }
168
169         ret = mono_threads_get_runtime_callbacks ()->thread_state_init_from_sigctx (&current->suspend_state, context);
170
171         /* thread_state_init_from_sigctx return FALSE if the current thread is detaching and suspend can't continue. */
172         current->suspend_can_continue = ret;
173
174         MONO_SEM_POST (&current->begin_suspend_semaphore);
175
176         /* This thread is doomed, all we can do is give up and let the suspender recover. */
177         if (!ret)
178                 return;
179
180         while (MONO_SEM_WAIT (&current->resume_semaphore) != 0) {
181                 /*if (EINTR != errno) ABORT("sem_wait failed"); */
182         }
183
184         if (current->async_target) {
185 #if MONO_ARCH_HAS_MONO_CONTEXT
186                 MonoContext tmp = current->suspend_state.ctx;
187                 mono_threads_get_runtime_callbacks ()->setup_async_callback (&tmp, current->async_target, current->user_data);
188                 current->async_target = current->user_data = NULL;
189                 mono_monoctx_to_sigctx (&tmp, context);
190 #else
191                 g_error ("The new interruption machinery requires a working mono-context");
192 #endif
193         }
194
195         MONO_SEM_POST (&current->finish_resume_semaphore);
196 }
197 #endif
198
199 static void
200 mono_posix_add_signal_handler (int signo, gpointer handler)
201 {
202 #if !defined(__native_client__)
203         /*FIXME, move the code from mini to utils and do the right thing!*/
204         struct sigaction sa;
205         struct sigaction previous_sa;
206         int ret;
207
208         sa.sa_sigaction = handler;
209         sigemptyset (&sa.sa_mask);
210         sa.sa_flags = SA_SIGINFO;
211         ret = sigaction (signo, &sa, &previous_sa);
212
213         g_assert (ret != -1);
214 #endif
215 }
216
217 void
218 mono_threads_init_platform (void)
219 {
220 #if !defined(__native_client__)
221         /*
222         FIXME we should use all macros from mini to make this more portable
223         FIXME it would be very sweet if sgen could end up using this too.
224         */
225         if (mono_thread_info_new_interrupt_enabled ())
226                 mono_posix_add_signal_handler (mono_thread_get_abort_signal (), suspend_signal_handler);
227 #endif
228 }
229
230 /*nothing to be done here since suspend always abort syscalls due using signals*/
231 void
232 mono_threads_core_interrupt (MonoThreadInfo *info)
233 {
234 }
235
236 int
237 mono_threads_pthread_kill (MonoThreadInfo *info, int signum)
238 {
239 #if defined (PLATFORM_ANDROID)
240         int result, old_errno = errno;
241         result = tkill (info->native_handle, signum);
242         if (result < 0) {
243                 result = errno;
244                 errno = old_errno;
245         }
246         return result;
247 #elif defined(__native_client__)
248         /* Workaround pthread_kill abort() in NaCl glibc. */
249         return 0;
250 #else
251         return pthread_kill (mono_thread_info_get_tid (info), signum);
252 #endif
253
254 }
255
256 void
257 mono_threads_core_abort_syscall (MonoThreadInfo *info)
258 {
259         /*
260         We signal a thread to break it from the urrent syscall.
261         This signal should not be interpreted as a suspend request.
262         */
263         info->syscall_break_signal = TRUE;
264         mono_threads_pthread_kill (info, mono_thread_get_abort_signal ());
265 }
266
267 gboolean
268 mono_threads_core_needs_abort_syscall (void)
269 {
270         return TRUE;
271 }
272
273 gboolean
274 mono_threads_core_suspend (MonoThreadInfo *info)
275 {
276         /*FIXME, check return value*/
277         mono_threads_pthread_kill (info, mono_thread_get_abort_signal ());
278         while (MONO_SEM_WAIT (&info->begin_suspend_semaphore) != 0) {
279                 /* g_assert (errno == EINTR); */
280         }
281         return info->suspend_can_continue;
282 }
283
284 gboolean
285 mono_threads_core_resume (MonoThreadInfo *info)
286 {
287         MONO_SEM_POST (&info->resume_semaphore);
288         while (MONO_SEM_WAIT (&info->finish_resume_semaphore) != 0) {
289                 /* g_assert (errno == EINTR); */
290         }
291
292         return TRUE;
293 }
294
295 void
296 mono_threads_platform_register (MonoThreadInfo *info)
297 {
298         MONO_SEM_INIT (&info->begin_suspend_semaphore, 0);
299
300 #if defined (PLATFORM_ANDROID)
301         info->native_handle = (gpointer) gettid ();
302 #endif
303 }
304
305 void
306 mono_threads_platform_free (MonoThreadInfo *info)
307 {
308         MONO_SEM_DESTROY (&info->begin_suspend_semaphore);
309 }
310
311 MonoNativeThreadId
312 mono_native_thread_id_get (void)
313 {
314         return pthread_self ();
315 }
316
317 gboolean
318 mono_native_thread_id_equals (MonoNativeThreadId id1, MonoNativeThreadId id2)
319 {
320         return pthread_equal (id1, id2);
321 }
322
323 /*
324  * mono_native_thread_create:
325  *
326  *   Low level thread creation function without any GC wrappers.
327  */
328 gboolean
329 mono_native_thread_create (MonoNativeThreadId *tid, gpointer func, gpointer arg)
330 {
331         return pthread_create (tid, NULL, func, arg) == 0;
332 }
333
334 #endif /*!defined (__MACH__)*/
335
336 #endif