[xbuild] Pick the correct base path for target frameworks.
[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(PLATFORM_ANDROID)
21 extern int tkill (pid_t tid, int signal);
22 #endif
23
24 #if defined(_POSIX_VERSION) || defined(__native_client__)
25 #include <signal.h>
26
27 typedef struct {
28         void *(*start_routine)(void*);
29         void *arg;
30         int flags;
31         MonoSemType registered;
32 } ThreadStartInfo;
33
34
35 static void*
36 inner_start_thread (void *arg)
37 {
38         ThreadStartInfo *start_info = arg;
39         void *t_arg = start_info->arg;
40         int post_result;
41         void *(*start_func)(void*) = start_info->start_routine;
42         void *result;
43
44         mono_thread_info_attach (&result);
45
46         post_result = MONO_SEM_POST (&(start_info->registered));
47         g_assert (!post_result);
48
49         result = start_func (t_arg);
50         g_assert (!mono_domain_get ());
51
52
53         return result;
54 }
55
56 int
57 mono_threads_pthread_create (pthread_t *new_thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg)
58 {
59         ThreadStartInfo *start_info;
60         int result;
61
62         start_info = g_malloc0 (sizeof (ThreadStartInfo));
63         if (!start_info)
64                 return ENOMEM;
65         MONO_SEM_INIT (&(start_info->registered), 0);
66         start_info->arg = arg;
67         start_info->start_routine = start_routine;
68
69         result = mono_threads_get_callbacks ()->mono_gc_pthread_create (new_thread, attr, inner_start_thread, start_info);
70         if (result == 0) {
71                 while (MONO_SEM_WAIT (&(start_info->registered)) != 0) {
72                         /*if (EINTR != errno) ABORT("sem_wait failed"); */
73                 }
74         }
75         MONO_SEM_DESTROY (&(start_info->registered));
76         g_free (start_info);
77         return result;
78 }
79
80 #if !defined (__MACH__)
81
82 #if !defined(__native_client__)
83 static void
84 suspend_signal_handler (int _dummy, siginfo_t *info, void *context)
85 {
86         MonoThreadInfo *current = mono_thread_info_current ();
87         gboolean ret = mono_threads_get_runtime_callbacks ()->thread_state_init_from_sigctx (&current->suspend_state, context);
88
89         g_assert (ret);
90
91         MONO_SEM_POST (&current->suspend_semaphore);
92                 
93         while (MONO_SEM_WAIT (&current->resume_semaphore) != 0) {
94                 /*if (EINTR != errno) ABORT("sem_wait failed"); */
95         }
96
97         if (current->async_target) {
98 #if MONO_ARCH_HAS_MONO_CONTEXT
99                 MonoContext tmp = current->suspend_state.ctx;
100                 mono_threads_get_runtime_callbacks ()->setup_async_callback (&tmp, current->async_target, current->user_data);
101                 current->async_target = current->user_data = NULL;
102                 mono_monoctx_to_sigctx (&tmp, context);
103 #else
104                 g_error ("The new interruption machinery requires a working mono-context");
105 #endif
106         }
107
108         MONO_SEM_POST (&current->finish_resume_semaphore);
109 }
110 #endif
111
112 static void
113 mono_posix_add_signal_handler (int signo, gpointer handler)
114 {
115 #if !defined(__native_client__)
116         /*FIXME, move the code from mini to utils and do the right thing!*/
117         struct sigaction sa;
118         struct sigaction previous_sa;
119         int ret;
120
121         sa.sa_sigaction = handler;
122         sigemptyset (&sa.sa_mask);
123         sa.sa_flags = SA_SIGINFO;
124         ret = sigaction (signo, &sa, &previous_sa);
125
126         g_assert (ret != -1);
127 #endif
128 }
129
130 void
131 mono_threads_init_platform (void)
132 {
133 #if !defined(__native_client__)
134         /*
135         FIXME we should use all macros from mini to make this more portable
136         FIXME it would be very sweet if sgen could end up using this too.
137         */
138         if (mono_thread_info_new_interrupt_enabled ())
139                 mono_posix_add_signal_handler (mono_thread_get_abort_signal (), suspend_signal_handler);
140 #endif
141 }
142
143 /*nothing to be done here since suspend always abort syscalls due using signals*/
144 void
145 mono_threads_core_interrupt (MonoThreadInfo *info)
146 {
147 }
148
149 int
150 mono_threads_pthread_kill (MonoThreadInfo *info, int signum)
151 {
152 #if defined (PLATFORM_ANDROID)
153         int result, old_errno = errno;
154         result = tkill (info->native_handle, signum);
155         if (result < 0) {
156                 result = errno;
157                 errno = old_errno;
158         }
159         return result;
160 #else
161         return pthread_kill (mono_thread_info_get_tid (info), signum);
162 #endif
163
164 }
165
166 gboolean
167 mono_threads_core_suspend (MonoThreadInfo *info)
168 {
169         /*FIXME, check return value*/
170         mono_threads_pthread_kill (info, mono_thread_get_abort_signal ());
171         while (MONO_SEM_WAIT (&info->suspend_semaphore) != 0) {
172                 /* g_assert (errno == EINTR); */
173         }
174         return TRUE;
175 }
176
177 gboolean
178 mono_threads_core_resume (MonoThreadInfo *info)
179 {
180         MONO_SEM_POST (&info->resume_semaphore);
181         while (MONO_SEM_WAIT (&info->finish_resume_semaphore) != 0) {
182                 /* g_assert (errno == EINTR); */
183         }
184
185         return TRUE;
186 }
187
188 void
189 mono_threads_platform_register (MonoThreadInfo *info)
190 {
191         MONO_SEM_INIT (&info->suspend_semaphore, 0);
192
193 #if defined (PLATFORM_ANDROID)
194         info->native_handle = (gpointer) gettid ();
195 #endif
196 }
197
198 void
199 mono_threads_platform_free (MonoThreadInfo *info)
200 {
201         MONO_SEM_DESTROY (&info->suspend_semaphore);
202 }
203
204 MonoNativeThreadId
205 mono_native_thread_id_get (void)
206 {
207         return pthread_self ();
208 }
209
210 gboolean
211 mono_native_thread_id_equals (MonoNativeThreadId id1, MonoNativeThreadId id2)
212 {
213         return pthread_equal (id1, id2);
214 }
215
216 /*
217  * mono_native_thread_create:
218  *
219  *   Low level thread creation function without any GC wrappers.
220  */
221 gboolean
222 mono_native_thread_create (MonoNativeThreadId *tid, gpointer func, gpointer arg)
223 {
224         return pthread_create (tid, NULL, func, arg) == 0;
225 }
226
227 #endif /*!defined (__MACH__)*/
228
229 #endif