Fixups for nacl at head revision.
[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/metadata/threads-types.h>
17
18 #include <errno.h>
19
20 #if defined(_POSIX_VERSION) || defined(__native_client__)
21 #include <signal.h>
22
23 typedef struct {
24         void *(*start_routine)(void*);
25         void *arg;
26         int flags;
27         MonoSemType registered;
28 } ThreadStartInfo;
29
30
31 static void*
32 inner_start_thread (void *arg)
33 {
34         ThreadStartInfo *start_info = arg;
35         void *t_arg = start_info->arg;
36         int post_result;
37         void *(*start_func)(void*) = start_info->start_routine;
38         void *result;
39
40         mono_thread_info_attach (&result);
41
42         post_result = MONO_SEM_POST (&(start_info->registered));
43         g_assert (!post_result);
44
45         result = start_func (t_arg);
46         g_assert (!mono_domain_get ());
47
48
49         return result;
50 }
51
52 int
53 mono_threads_pthread_create (pthread_t *new_thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg)
54 {
55         ThreadStartInfo *start_info;
56         int result;
57
58         start_info = g_malloc0 (sizeof (ThreadStartInfo));
59         if (!start_info)
60                 return ENOMEM;
61         MONO_SEM_INIT (&(start_info->registered), 0);
62         start_info->arg = arg;
63         start_info->start_routine = start_routine;
64
65         result = mono_threads_get_callbacks ()->mono_gc_pthread_create (new_thread, attr, inner_start_thread, start_info);
66         if (result == 0) {
67                 while (MONO_SEM_WAIT (&(start_info->registered)) != 0) {
68                         /*if (EINTR != errno) ABORT("sem_wait failed"); */
69                 }
70         }
71         MONO_SEM_DESTROY (&(start_info->registered));
72         g_free (start_info);
73         return result;
74 }
75
76 #if !defined (__MACH__)
77
78 #if !defined(__native_client__)
79 static void
80 suspend_signal_handler (int _dummy, siginfo_t *info, void *context)
81 {
82         MonoThreadInfo *current = mono_thread_info_current ();
83         gboolean ret = mono_threads_get_runtime_callbacks ()->thread_state_init_from_sigctx (&current->suspend_state, context);
84
85         g_assert (ret);
86
87         if (current->self_suspend)
88                 LeaveCriticalSection (&current->suspend_lock);
89         else
90                 MONO_SEM_POST (&current->suspend_semaphore);
91                 
92         while (MONO_SEM_WAIT (&current->resume_semaphore) != 0) {
93                 /*if (EINTR != errno) ABORT("sem_wait failed"); */
94         }
95
96         if (current->async_target) {
97 #if MONO_ARCH_HAS_MONO_CONTEXT
98                 MonoContext tmp = current->suspend_state.ctx;
99                 mono_threads_get_runtime_callbacks ()->setup_async_callback (&tmp, current->async_target, current->user_data);
100                 current->async_target = current->user_data = NULL;
101                 mono_monoctx_to_sigctx (&tmp, context);
102 #else
103                 g_error ("The new interruption machinery requires a working mono-context");
104 #endif
105         }
106
107         MONO_SEM_POST (&current->finish_resume_semaphore);
108 }
109 #endif
110
111 static void
112 mono_posix_add_signal_handler (int signo, gpointer handler)
113 {
114 #if !defined(__native_client__)
115         /*FIXME, move the code from mini to utils and do the right thing!*/
116         struct sigaction sa;
117         struct sigaction previous_sa;
118         int ret;
119
120         sa.sa_sigaction = handler;
121         sigemptyset (&sa.sa_mask);
122         sa.sa_flags = SA_SIGINFO;
123         ret = sigaction (signo, &sa, &previous_sa);
124
125         g_assert (ret != -1);
126 #endif
127 }
128
129 void
130 mono_threads_init_platform (void)
131 {
132 #if !defined(__native_client__)
133         /*
134         FIXME we should use all macros from mini to make this more portable
135         FIXME it would be very sweet if sgen could end up using this too.
136         */
137         if (mono_thread_info_new_interrupt_enabled ())
138                 mono_posix_add_signal_handler (mono_thread_get_abort_signal (), suspend_signal_handler);
139 #endif
140 }
141
142 /*nothing to be done here since suspend always abort syscalls due using signals*/
143 void
144 mono_threads_core_interrupt (MonoThreadInfo *info)
145 {
146 }
147
148 /*
149 We self suspend using signals since thread_state_init_from_sigctx only supports
150 a null context on a few targets.
151 */
152 void
153 mono_threads_core_self_suspend (MonoThreadInfo *info)
154 {
155         /*FIXME, check return value*/
156         info->self_suspend = TRUE;
157         pthread_kill (mono_thread_info_get_tid (info), mono_thread_get_abort_signal ());
158 }
159
160 gboolean
161 mono_threads_core_suspend (MonoThreadInfo *info)
162 {
163         /*FIXME, check return value*/
164         info->self_suspend = FALSE;
165         pthread_kill (mono_thread_info_get_tid (info), mono_thread_get_abort_signal ());
166         while (MONO_SEM_WAIT (&info->suspend_semaphore) != 0) {
167                 /* g_assert (errno == EINTR); */
168         }
169         return TRUE;
170 }
171
172 gboolean
173 mono_threads_core_resume (MonoThreadInfo *info)
174 {
175         MONO_SEM_POST (&info->resume_semaphore);
176         while (MONO_SEM_WAIT (&info->finish_resume_semaphore) != 0) {
177                 /* g_assert (errno == EINTR); */
178         }
179
180         return TRUE;
181 }
182
183 void
184 mono_threads_platform_register (MonoThreadInfo *info)
185 {
186         MONO_SEM_INIT (&info->suspend_semaphore, 0);
187         MONO_SEM_INIT (&info->resume_semaphore, 0);
188         MONO_SEM_INIT (&info->finish_resume_semaphore, 0);
189 }
190
191 void
192 mono_threads_platform_free (MonoThreadInfo *info)
193 {
194         MONO_SEM_DESTROY (&info->suspend_semaphore);
195         MONO_SEM_DESTROY (&info->resume_semaphore);
196         MONO_SEM_DESTROY (&info->finish_resume_semaphore);
197 }
198
199 #endif /*!defined (__MACH__)*/
200
201 #endif