Convert MonoGenericContainer/Param accessor macros to inline functions
[mono.git] / mono / io-layer / wthreads.c
1 /*
2  * threads.c:  Thread handles
3  *
4  * Author:
5  *      Dick Porter (dick@ximian.com)
6  *
7  * (C) 2002-2006 Ximian, Inc.
8  * Copyright 2003-2011 Novell, Inc (http://www.novell.com)
9  * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
10  */
11
12 #include <config.h>
13 #include <stdio.h>
14 #include <glib.h>
15 #include <string.h>
16 #include <pthread.h>
17 #include <sched.h>
18 #include <sys/time.h>
19 #include <errno.h>
20 #include <sys/types.h>
21 #include <unistd.h>
22
23 #include <mono/io-layer/wapi.h>
24 #include <mono/io-layer/wapi-private.h>
25 #include <mono/io-layer/handles-private.h>
26 #include <mono/io-layer/misc-private.h>
27 #include <mono/io-layer/thread-private.h>
28 #include <mono/io-layer/mutex-private.h>
29
30 #include <mono/utils/mono-threads.h>
31 #include <mono/utils/atomic.h>
32 #include <mono/utils/mono-mutex.h>
33 #include <mono/utils/mono-time.h>
34
35 #ifdef HAVE_VALGRIND_MEMCHECK_H
36 #include <valgrind/memcheck.h>
37 #endif
38
39 #if 0
40 #define DEBUG(...) g_message(__VA_ARGS__)
41 #else
42 #define DEBUG(...)
43 #endif
44
45 #if 0
46 #define WAIT_DEBUG(code) do { code } while (0)
47 #else
48 #define WAIT_DEBUG(code) do { } while (0)
49 #endif
50
51 struct _WapiHandleOps _wapi_thread_ops = {
52         NULL,                           /* close */
53         NULL,                           /* signal */
54         NULL,                           /* own */
55         NULL,                           /* is_owned */
56         NULL,                           /* special_wait */
57         NULL                            /* prewait */
58 };
59
60 static mono_once_t thread_ops_once = MONO_ONCE_INIT;
61
62 static void
63 thread_ops_init (void)
64 {
65         _wapi_handle_register_capabilities (WAPI_HANDLE_THREAD,
66                                             WAPI_HANDLE_CAP_WAIT);
67 }
68
69 void
70 _wapi_thread_cleanup (void)
71 {
72 }
73
74 static gpointer
75 get_current_thread_handle (void)
76 {
77         MonoThreadInfo *info;
78
79         info = mono_thread_info_current ();
80         g_assert (info);
81         g_assert (info->handle);
82         return info->handle;
83 }
84
85 static WapiHandle_thread*
86 lookup_thread (HANDLE handle)
87 {
88         WapiHandle_thread *thread;
89         gboolean ok;
90
91         ok = _wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
92                                                           (gpointer *)&thread);
93         g_assert (ok);
94         return thread;
95 }
96
97 static WapiHandle_thread*
98 get_current_thread (void)
99 {
100         gpointer handle;
101
102         handle = get_current_thread_handle ();
103         return lookup_thread (handle);
104 }
105
106 void
107 wapi_thread_handle_set_exited (gpointer handle, guint32 exitstatus)
108 {
109         WapiHandle_thread *thread_handle;
110         int i, thr_ret;
111         pid_t pid = _wapi_getpid ();
112         pthread_t tid = pthread_self ();
113         
114         if (_wapi_handle_issignalled (handle) ||
115             _wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) {
116                 /* We must have already deliberately finished with
117                  * this thread, so don't do any more now
118                  */
119                 return;
120         }
121
122         DEBUG ("%s: Thread %p terminating", __func__, handle);
123
124         thread_handle = lookup_thread (handle);
125
126         DEBUG ("%s: Thread %p abandoning held mutexes", __func__, handle);
127
128         for (i = 0; i < thread_handle->owned_mutexes->len; i++) {
129                 gpointer mutex = g_ptr_array_index (thread_handle->owned_mutexes, i);
130
131                 _wapi_mutex_abandon (mutex, pid, tid);
132                 _wapi_thread_disown_mutex (mutex);
133         }
134         g_ptr_array_free (thread_handle->owned_mutexes, TRUE);
135         
136         thr_ret = _wapi_handle_lock_handle (handle);
137         g_assert (thr_ret == 0);
138
139         _wapi_handle_set_signal_state (handle, TRUE, TRUE);
140
141         thr_ret = _wapi_handle_unlock_handle (handle);
142         g_assert (thr_ret == 0);
143         
144         DEBUG("%s: Recording thread handle %p id %ld status as %d",
145                   __func__, handle, thread_handle->id, exitstatus);
146         
147         /* The thread is no longer active, so unref it */
148         _wapi_handle_unref (handle);
149 }
150
151 /*
152  * wapi_create_thread_handle:
153  *
154  *   Create a thread handle for the current thread.
155  */
156 gpointer
157 wapi_create_thread_handle (void)
158 {
159         WapiHandle_thread thread_handle = {0}, *thread;
160         gpointer handle;
161
162         mono_once (&thread_ops_once, thread_ops_init);
163
164         thread_handle.owned_mutexes = g_ptr_array_new ();
165
166         handle = _wapi_handle_new (WAPI_HANDLE_THREAD, &thread_handle);
167         if (handle == _WAPI_HANDLE_INVALID) {
168                 g_warning ("%s: error creating thread handle", __func__);
169                 SetLastError (ERROR_GEN_FAILURE);
170                 
171                 return NULL;
172         }
173
174         thread = lookup_thread (handle);
175
176         thread->id = pthread_self ();
177
178         /*
179          * Hold a reference while the thread is active, because we use
180          * the handle to store thread exit information
181          */
182         _wapi_handle_ref (handle);
183
184         DEBUG ("%s: started thread id %ld", __func__, thread->id);
185         
186         return handle;
187 }
188
189 void
190 wapi_ref_thread_handle (gpointer handle)
191 {
192         _wapi_handle_ref (handle);
193 }
194
195 gpointer
196 wapi_get_current_thread_handle (void)
197 {
198         return get_current_thread_handle ();
199 }
200
201 gboolean
202 _wapi_thread_cur_apc_pending (void)
203 {
204         return mono_thread_info_is_interrupt_state (mono_thread_info_current ());
205 }
206
207 void
208 _wapi_thread_own_mutex (gpointer mutex)
209 {
210         WapiHandle_thread *thread;
211         
212         thread = get_current_thread ();
213
214         _wapi_handle_ref (mutex);
215         
216         g_ptr_array_add (thread->owned_mutexes, mutex);
217 }
218
219 void
220 _wapi_thread_disown_mutex (gpointer mutex)
221 {
222         WapiHandle_thread *thread;
223
224         thread = get_current_thread ();
225
226         _wapi_handle_unref (mutex);
227         
228         g_ptr_array_remove (thread->owned_mutexes, mutex);
229 }
230
231 char*
232 wapi_current_thread_desc (void)
233 {
234         WapiHandle_thread *thread;
235         gpointer thread_handle;
236         int i;
237         GString* text;
238         char *res;
239
240         thread_handle = get_current_thread_handle ();
241         thread = lookup_thread (thread_handle);
242
243         text = g_string_new (0);
244         g_string_append_printf (text, "thread handle %p state : ", thread_handle);
245
246         mono_thread_info_describe_interrupt_token (mono_thread_info_current (), text);
247
248         g_string_append_printf (text, " owns (");
249         for (i = 0; i < thread->owned_mutexes->len; i++)
250                 g_string_append_printf (text, i > 0 ? ", %p" : "%p", g_ptr_array_index (thread->owned_mutexes, i));
251         g_string_append_printf (text, ")");
252
253         res = text->str;
254         g_string_free (text, FALSE);
255         return res;
256 }