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