Merge pull request #2084 from joelmartinez/mdoc-deletetestfix
[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-lazy-init.h>
34 #include <mono/utils/mono-time.h>
35
36 #ifdef HAVE_VALGRIND_MEMCHECK_H
37 #include <valgrind/memcheck.h>
38 #endif
39
40 #if 0
41 #define DEBUG(...) g_message(__VA_ARGS__)
42 #else
43 #define DEBUG(...)
44 #endif
45
46 #if 0
47 #define WAIT_DEBUG(code) do { code } while (0)
48 #else
49 #define WAIT_DEBUG(code) do { } while (0)
50 #endif
51
52 struct _WapiHandleOps _wapi_thread_ops = {
53         NULL,                           /* close */
54         NULL,                           /* signal */
55         NULL,                           /* own */
56         NULL,                           /* is_owned */
57         NULL,                           /* special_wait */
58         NULL                            /* prewait */
59 };
60
61 static mono_once_t thread_ops_once = MONO_ONCE_INIT;
62
63 static void
64 thread_ops_init (void)
65 {
66         _wapi_handle_register_capabilities (WAPI_HANDLE_THREAD,
67                                             WAPI_HANDLE_CAP_WAIT);
68 }
69
70 void
71 _wapi_thread_cleanup (void)
72 {
73 }
74
75 static gpointer
76 get_current_thread_handle (void)
77 {
78         MonoThreadInfo *info;
79
80         info = mono_thread_info_current ();
81         g_assert (info);
82         g_assert (info->handle);
83         return info->handle;
84 }
85
86 static WapiHandle_thread*
87 lookup_thread (HANDLE handle)
88 {
89         WapiHandle_thread *thread;
90         gboolean ok;
91
92         ok = _wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
93                                                           (gpointer *)&thread);
94         g_assert (ok);
95         return thread;
96 }
97
98 static WapiHandle_thread*
99 get_current_thread (void)
100 {
101         gpointer handle;
102
103         handle = get_current_thread_handle ();
104         return lookup_thread (handle);
105 }
106
107 void
108 wapi_thread_handle_set_exited (gpointer handle, guint32 exitstatus)
109 {
110         WapiHandle_thread *thread_handle;
111         int i, thr_ret;
112         pid_t pid = _wapi_getpid ();
113         pthread_t tid = pthread_self ();
114         
115         if (_wapi_handle_issignalled (handle) ||
116             _wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) {
117                 /* We must have already deliberately finished with
118                  * this thread, so don't do any more now
119                  */
120                 return;
121         }
122
123         DEBUG ("%s: Thread %p terminating", __func__, handle);
124
125         thread_handle = lookup_thread (handle);
126
127         DEBUG ("%s: Thread %p abandoning held mutexes", __func__, handle);
128
129         for (i = 0; i < thread_handle->owned_mutexes->len; i++) {
130                 gpointer mutex = g_ptr_array_index (thread_handle->owned_mutexes, i);
131
132                 _wapi_mutex_abandon (mutex, pid, tid);
133                 _wapi_thread_disown_mutex (mutex);
134         }
135         g_ptr_array_free (thread_handle->owned_mutexes, TRUE);
136         
137         thr_ret = _wapi_handle_lock_handle (handle);
138         g_assert (thr_ret == 0);
139
140         _wapi_handle_set_signal_state (handle, TRUE, TRUE);
141
142         thr_ret = _wapi_handle_unlock_handle (handle);
143         g_assert (thr_ret == 0);
144         
145         DEBUG("%s: Recording thread handle %p id %ld status as %d",
146                   __func__, handle, thread_handle->id, exitstatus);
147         
148         /* The thread is no longer active, so unref it */
149         _wapi_handle_unref (handle);
150 }
151
152 /*
153  * wapi_create_thread_handle:
154  *
155  *   Create a thread handle for the current thread.
156  */
157 gpointer
158 wapi_create_thread_handle (void)
159 {
160         WapiHandle_thread thread_handle = {0}, *thread;
161         gpointer handle;
162
163         mono_once (&thread_ops_once, thread_ops_init);
164
165         thread_handle.owned_mutexes = g_ptr_array_new ();
166
167         handle = _wapi_handle_new (WAPI_HANDLE_THREAD, &thread_handle);
168         if (handle == _WAPI_HANDLE_INVALID) {
169                 g_warning ("%s: error creating thread handle", __func__);
170                 SetLastError (ERROR_GEN_FAILURE);
171                 
172                 return NULL;
173         }
174
175         thread = lookup_thread (handle);
176
177         thread->id = pthread_self ();
178
179         /*
180          * Hold a reference while the thread is active, because we use
181          * the handle to store thread exit information
182          */
183         _wapi_handle_ref (handle);
184
185         DEBUG ("%s: started thread id %ld", __func__, thread->id);
186         
187         return handle;
188 }
189
190 void
191 wapi_ref_thread_handle (gpointer handle)
192 {
193         _wapi_handle_ref (handle);
194 }
195
196 gpointer
197 wapi_get_current_thread_handle (void)
198 {
199         return get_current_thread_handle ();
200 }
201
202 /**
203  * GetCurrentThreadId:
204  *
205  * Looks up the thread ID of the current thread.  This ID can be
206  * passed to OpenThread() to create a new handle on this thread.
207  *
208  * Return value: the thread ID.  NB this is defined as DWORD (ie 32
209  * bit) in the MS API, but we need to cope with 64 bit IDs for s390x
210  * and amd64.  This doesn't really break the API, it just embraces and
211  * extends it on 64bit platforms :)
212  */
213 gsize
214 GetCurrentThreadId (void)
215 {
216         MonoNativeThreadId id;
217
218         id = mono_native_thread_id_get ();
219         return MONO_NATIVE_THREAD_ID_TO_UINT (id);
220 }
221
222 static mono_lazy_init_t sleepex_init = MONO_LAZY_INIT_STATUS_NOT_INITIALIZED;
223 static mono_mutex_t sleepex_mutex;
224 static mono_cond_t sleepex_cond;
225
226 static void
227 sleepex_initialize (void)
228 {
229         mono_mutex_init (&sleepex_mutex);
230         mono_cond_init (&sleepex_cond, NULL);
231 }
232
233 static void
234 sleepex_interrupt (gpointer data)
235 {
236         mono_mutex_lock (&sleepex_mutex);
237         mono_cond_broadcast (&sleepex_cond);
238         mono_mutex_unlock (&sleepex_mutex);
239 }
240
241 static inline guint32
242 sleepex_interruptable (guint32 ms)
243 {
244         gboolean interrupted;
245         guint32 start, now, end;
246
247         g_assert (INFINITE == G_MAXUINT32);
248
249         start = mono_msec_ticks ();
250
251         if (start < G_MAXUINT32 - ms) {
252                 end = start + ms;
253         } else {
254                 /* start + ms would overflow guint32 */
255                 end = G_MAXUINT32;
256         }
257
258         mono_lazy_initialize (&sleepex_init, sleepex_initialize);
259
260         mono_mutex_lock (&sleepex_mutex);
261
262         for (now = mono_msec_ticks (); ms == INFINITE || now - start < ms; now = mono_msec_ticks ()) {
263                 mono_thread_info_install_interrupt (sleepex_interrupt, NULL, &interrupted);
264                 if (interrupted) {
265                         mono_mutex_unlock (&sleepex_mutex);
266                         return WAIT_IO_COMPLETION;
267                 }
268
269                 if (ms < INFINITE)
270                         mono_cond_timedwait_ms (&sleepex_cond, &sleepex_mutex, end - now);
271                 else
272                         mono_cond_wait (&sleepex_cond, &sleepex_mutex);
273
274                 mono_thread_info_uninstall_interrupt (&interrupted);
275                 if (interrupted) {
276                         mono_mutex_unlock (&sleepex_mutex);
277                         return WAIT_IO_COMPLETION;
278                 }
279         }
280
281         mono_mutex_unlock (&sleepex_mutex);
282
283         return 0;
284 }
285
286 /**
287  * SleepEx:
288  * @ms: The time in milliseconds to suspend for
289  * @alertable: if TRUE, the wait can be interrupted by an APC call
290  *
291  * Suspends execution of the current thread for @ms milliseconds.  A
292  * value of zero causes the thread to relinquish its time slice.  A
293  * value of %INFINITE causes an infinite delay.
294  */
295 guint32
296 SleepEx (guint32 ms, gboolean alertable)
297 {
298         if (ms == 0) {
299                 MonoThreadInfo *info;
300
301                 mono_thread_info_yield ();
302
303                 info = mono_thread_info_current ();
304                 if (info && mono_thread_info_is_interrupt_state (info))
305                         return WAIT_IO_COMPLETION;
306
307                 return 0;
308         }
309
310         if (alertable)
311                 return sleepex_interruptable (ms);
312
313         DEBUG("%s: Sleeping for %d ms", __func__, ms);
314
315         if (ms == INFINITE) {
316                 do {
317                         sleep (G_MAXUINT32);
318                 } while (1);
319         } else {
320                 int ret;
321 #if defined (__linux__) && !defined(PLATFORM_ANDROID)
322                 struct timespec start, target;
323
324                 /* Use clock_nanosleep () to prevent time drifting problems when nanosleep () is interrupted by signals */
325                 ret = clock_gettime (CLOCK_MONOTONIC, &start);
326                 g_assert (ret == 0);
327
328                 target = start;
329                 target.tv_sec += ms / 1000;
330                 target.tv_nsec += (ms % 1000) * 1000000;
331                 if (target.tv_nsec > 999999999) {
332                         target.tv_nsec -= 999999999;
333                         target.tv_sec ++;
334                 }
335
336                 do {
337                         ret = clock_nanosleep (CLOCK_MONOTONIC, TIMER_ABSTIME, &target, NULL);
338                 } while (ret != 0);
339 #else
340                 struct timespec req, rem;
341
342                 req.tv_sec = ms / 1000;
343                 req.tv_nsec = (ms % 1000) * 1000000;
344
345                 do {
346                         memset (&rem, 0, sizeof (rem));
347                         ret = nanosleep (&req, &rem);
348                 } while (ret != 0);
349 #endif /* __linux__ */
350         }
351
352         return 0;
353 }
354
355 void
356 Sleep(guint32 ms)
357 {
358         SleepEx(ms, FALSE);
359 }
360
361 gboolean
362 _wapi_thread_cur_apc_pending (void)
363 {
364         return mono_thread_info_is_interrupt_state (mono_thread_info_current ());
365 }
366
367 void
368 _wapi_thread_own_mutex (gpointer mutex)
369 {
370         WapiHandle_thread *thread;
371         
372         thread = get_current_thread ();
373
374         _wapi_handle_ref (mutex);
375         
376         g_ptr_array_add (thread->owned_mutexes, mutex);
377 }
378
379 void
380 _wapi_thread_disown_mutex (gpointer mutex)
381 {
382         WapiHandle_thread *thread;
383
384         thread = get_current_thread ();
385
386         _wapi_handle_unref (mutex);
387         
388         g_ptr_array_remove (thread->owned_mutexes, mutex);
389 }
390
391 char*
392 wapi_current_thread_desc (void)
393 {
394         WapiHandle_thread *thread;
395         gpointer thread_handle;
396         int i;
397         GString* text;
398         char *res;
399
400         thread_handle = get_current_thread_handle ();
401         thread = lookup_thread (thread_handle);
402
403         text = g_string_new (0);
404         g_string_append_printf (text, "thread handle %p state : ", thread_handle);
405
406         mono_thread_info_describe_interrupt_token (mono_thread_info_current (), text);
407
408         g_string_append_printf (text, " owns (");
409         for (i = 0; i < thread->owned_mutexes->len; i++)
410                 g_string_append_printf (text, i > 0 ? ", %p" : "%p", g_ptr_array_index (thread->owned_mutexes, i));
411         g_string_append_printf (text, ")");
412
413         res = text->str;
414         g_string_free (text, FALSE);
415         return res;
416 }