Revert "[runtime] Get rid of ResumeThread(), use mono_thread_info_resume () instead."
[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         g_assert (!mono_domain_get ());
81         mono_thread_info_dettach ();
82
83 #if defined(__native_client__)
84         nacl_shutdown_gc_thread();
85 #endif
86
87         wapi_thread_set_exit_code (GPOINTER_TO_UINT (result), handle);
88
89         // FIXME: Why is this needed ?
90         mono_gc_pthread_exit (NULL);
91
92         g_assert_not_reached ();
93         return result;
94 }
95
96 HANDLE
97 mono_threads_core_create_thread (LPTHREAD_START_ROUTINE start_routine, gpointer arg, guint32 stack_size, guint32 creation_flags, MonoNativeThreadId *out_tid)
98 {
99         pthread_attr_t attr;
100         int res;
101         pthread_t thread;
102         StartInfo start_info;
103
104         res = pthread_attr_init (&attr);
105         g_assert (!res);
106
107         if (stack_size == 0) {
108 #if HAVE_VALGRIND_MEMCHECK_H
109                 if (RUNNING_ON_VALGRIND)
110                         stack_size = 1 << 20;
111                 else
112                         stack_size = (SIZEOF_VOID_P / 4) * 1024 * 1024;
113 #else
114                 stack_size = (SIZEOF_VOID_P / 4) * 1024 * 1024;
115 #endif
116         }
117
118 #ifdef PTHREAD_STACK_MIN
119         if (stack_size < PTHREAD_STACK_MIN)
120                 stack_size = PTHREAD_STACK_MIN;
121 #endif
122
123 #ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE
124         res = pthread_attr_setstacksize (&attr, stack_size);
125         g_assert (!res);
126 #endif
127
128         memset (&start_info, 0, sizeof (StartInfo));
129         start_info.start_routine = (gpointer)start_routine;
130         start_info.arg = arg;
131         start_info.flags = creation_flags;
132         MONO_SEM_INIT (&(start_info.registered), 0);
133
134         /* Actually start the thread */
135         res = mono_threads_get_callbacks ()->mono_gc_pthread_create (&thread, &attr, inner_start_thread, &start_info);
136         if (res) {
137                 // FIXME:
138                 g_assert_not_reached ();
139         }
140
141         /* Wait until the thread register itself in various places */
142         while (MONO_SEM_WAIT (&(start_info.registered)) != 0) {
143                 /*if (EINTR != errno) ABORT("sem_wait failed"); */
144         }
145         MONO_SEM_DESTROY (&(start_info.registered));
146
147         if (out_tid)
148                 *out_tid = thread;
149
150         return start_info.handle;
151 }
152
153 #if !defined (__MACH__)
154
155 #if !defined(__native_client__)
156 static void
157 suspend_signal_handler (int _dummy, siginfo_t *info, void *context)
158 {
159         MonoThreadInfo *current = mono_thread_info_current ();
160         gboolean ret;
161         
162         if (current->syscall_break_signal) {
163                 current->syscall_break_signal = FALSE;
164                 return;
165         }
166
167         ret = mono_threads_get_runtime_callbacks ()->thread_state_init_from_sigctx (&current->suspend_state, context);
168
169         /* thread_state_init_from_sigctx return FALSE if the current thread is detaching and suspend can't continue. */
170         current->suspend_can_continue = ret;
171
172         MONO_SEM_POST (&current->begin_suspend_semaphore);
173
174         /* This thread is doomed, all we can do is give up and let the suspender recover. */
175         if (!ret)
176                 return;
177
178         while (MONO_SEM_WAIT (&current->resume_semaphore) != 0) {
179                 /*if (EINTR != errno) ABORT("sem_wait failed"); */
180         }
181
182         if (current->async_target) {
183 #if MONO_ARCH_HAS_MONO_CONTEXT
184                 MonoContext tmp = current->suspend_state.ctx;
185                 mono_threads_get_runtime_callbacks ()->setup_async_callback (&tmp, current->async_target, current->user_data);
186                 current->async_target = current->user_data = NULL;
187                 mono_monoctx_to_sigctx (&tmp, context);
188 #else
189                 g_error ("The new interruption machinery requires a working mono-context");
190 #endif
191         }
192
193         MONO_SEM_POST (&current->finish_resume_semaphore);
194 }
195 #endif
196
197 static void
198 mono_posix_add_signal_handler (int signo, gpointer handler)
199 {
200 #if !defined(__native_client__)
201         /*FIXME, move the code from mini to utils and do the right thing!*/
202         struct sigaction sa;
203         struct sigaction previous_sa;
204         int ret;
205
206         sa.sa_sigaction = handler;
207         sigemptyset (&sa.sa_mask);
208         sa.sa_flags = SA_SIGINFO;
209         ret = sigaction (signo, &sa, &previous_sa);
210
211         g_assert (ret != -1);
212 #endif
213 }
214
215 void
216 mono_threads_init_platform (void)
217 {
218 #if !defined(__native_client__)
219         /*
220         FIXME we should use all macros from mini to make this more portable
221         FIXME it would be very sweet if sgen could end up using this too.
222         */
223         if (mono_thread_info_new_interrupt_enabled ())
224                 mono_posix_add_signal_handler (mono_thread_get_abort_signal (), suspend_signal_handler);
225 #endif
226 }
227
228 /*nothing to be done here since suspend always abort syscalls due using signals*/
229 void
230 mono_threads_core_interrupt (MonoThreadInfo *info)
231 {
232 }
233
234 int
235 mono_threads_pthread_kill (MonoThreadInfo *info, int signum)
236 {
237 #if defined (PLATFORM_ANDROID)
238         int result, old_errno = errno;
239         result = tkill (info->native_handle, signum);
240         if (result < 0) {
241                 result = errno;
242                 errno = old_errno;
243         }
244         return result;
245 #elif defined(__native_client__)
246         /* Workaround pthread_kill abort() in NaCl glibc. */
247         return 0;
248 #else
249         return pthread_kill (mono_thread_info_get_tid (info), signum);
250 #endif
251
252 }
253
254 void
255 mono_threads_core_abort_syscall (MonoThreadInfo *info)
256 {
257         /*
258         We signal a thread to break it from the urrent syscall.
259         This signal should not be interpreted as a suspend request.
260         */
261         info->syscall_break_signal = TRUE;
262         mono_threads_pthread_kill (info, mono_thread_get_abort_signal ());
263 }
264
265 gboolean
266 mono_threads_core_needs_abort_syscall (void)
267 {
268         return TRUE;
269 }
270
271 gboolean
272 mono_threads_core_suspend (MonoThreadInfo *info)
273 {
274         /*FIXME, check return value*/
275         mono_threads_pthread_kill (info, mono_thread_get_abort_signal ());
276         while (MONO_SEM_WAIT (&info->begin_suspend_semaphore) != 0) {
277                 /* g_assert (errno == EINTR); */
278         }
279         return info->suspend_can_continue;
280 }
281
282 gboolean
283 mono_threads_core_resume (MonoThreadInfo *info)
284 {
285         MONO_SEM_POST (&info->resume_semaphore);
286         while (MONO_SEM_WAIT (&info->finish_resume_semaphore) != 0) {
287                 /* g_assert (errno == EINTR); */
288         }
289
290         return TRUE;
291 }
292
293 void
294 mono_threads_platform_register (MonoThreadInfo *info)
295 {
296         MONO_SEM_INIT (&info->begin_suspend_semaphore, 0);
297
298 #if defined (PLATFORM_ANDROID)
299         info->native_handle = (gpointer) gettid ();
300 #endif
301 }
302
303 void
304 mono_threads_platform_free (MonoThreadInfo *info)
305 {
306         MONO_SEM_DESTROY (&info->begin_suspend_semaphore);
307 }
308
309 MonoNativeThreadId
310 mono_native_thread_id_get (void)
311 {
312         return pthread_self ();
313 }
314
315 gboolean
316 mono_native_thread_id_equals (MonoNativeThreadId id1, MonoNativeThreadId id2)
317 {
318         return pthread_equal (id1, id2);
319 }
320
321 /*
322  * mono_native_thread_create:
323  *
324  *   Low level thread creation function without any GC wrappers.
325  */
326 gboolean
327 mono_native_thread_create (MonoNativeThreadId *tid, gpointer func, gpointer arg)
328 {
329         return pthread_create (tid, NULL, func, arg) == 0;
330 }
331
332 #endif /*!defined (__MACH__)*/
333
334 #endif