Merge pull request #866 from linquize/content-type-encoding
[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 <signal.h>
18 #include <sched.h>
19 #include <sys/time.h>
20 #include <errno.h>
21 #include <sys/types.h>
22 #include <unistd.h>
23
24 #include <mono/io-layer/wapi.h>
25 #include <mono/io-layer/wapi-private.h>
26 #include <mono/io-layer/handles-private.h>
27 #include <mono/io-layer/misc-private.h>
28 #include <mono/io-layer/thread-private.h>
29 #include <mono/io-layer/mutex-private.h>
30
31 #include <mono/utils/mono-threads.h>
32 #include <mono/utils/atomic.h>
33 #include <mono/utils/mono-mutex.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 /**
202  * GetCurrentThreadId:
203  *
204  * Looks up the thread ID of the current thread.  This ID can be
205  * passed to OpenThread() to create a new handle on this thread.
206  *
207  * Return value: the thread ID.  NB this is defined as DWORD (ie 32
208  * bit) in the MS API, but we need to cope with 64 bit IDs for s390x
209  * and amd64.  This doesn't really break the API, it just embraces and
210  * extends it on 64bit platforms :)
211  */
212 gsize
213 GetCurrentThreadId (void)
214 {
215         MonoNativeThreadId id;
216
217         id = mono_native_thread_id_get ();
218         return MONO_NATIVE_THREAD_ID_TO_UINT (id);
219 }
220
221 /**
222  * SleepEx:
223  * @ms: The time in milliseconds to suspend for
224  * @alertable: if TRUE, the wait can be interrupted by an APC call
225  *
226  * Suspends execution of the current thread for @ms milliseconds.  A
227  * value of zero causes the thread to relinquish its time slice.  A
228  * value of %INFINITE causes an infinite delay.
229  */
230 guint32
231 SleepEx (guint32 ms, gboolean alertable)
232 {
233         struct timespec req;
234         int ms_quot, ms_rem;
235         int ret;
236         gpointer current_thread = NULL;
237 #ifdef __linux__
238         struct timespec start, target;
239 #else
240         struct timespec rem;
241 #endif
242         
243         DEBUG("%s: Sleeping for %d ms", __func__, ms);
244
245         if (alertable) {
246                 current_thread = get_current_thread_handle ();
247                 
248                 if (_wapi_thread_apc_pending (current_thread))
249                         return WAIT_IO_COMPLETION;
250         }
251         
252         if(ms==0) {
253                 sched_yield();
254                 return 0;
255         }
256         
257         /* FIXME: check for INFINITE and sleep forever */
258         ms_quot = ms / 1000;
259         ms_rem = ms % 1000;
260         
261         req.tv_sec=ms_quot;
262         req.tv_nsec=ms_rem*1000000;
263
264 #ifdef __linux__
265         /* Use clock_nanosleep () to prevent time drifting problems when nanosleep () is interrupted by signals */
266         ret = clock_gettime (CLOCK_MONOTONIC, &start);
267         g_assert (ret == 0);
268         target = start;
269         target.tv_sec += ms_quot;
270         target.tv_nsec += ms_rem * 1000000;
271         if (target.tv_nsec > 999999999) {
272                 target.tv_nsec -= 999999999;
273                 target.tv_sec ++;
274         }
275
276         while (TRUE) {
277                 ret = clock_nanosleep (CLOCK_MONOTONIC, TIMER_ABSTIME, &target, NULL);
278
279                 if (alertable && _wapi_thread_apc_pending (current_thread))
280                         return WAIT_IO_COMPLETION;
281
282                 if (ret == 0)
283                         break;
284         }
285
286 #else
287
288 again:
289         memset (&rem, 0, sizeof (rem));
290         ret=nanosleep(&req, &rem);
291
292         if (alertable && _wapi_thread_apc_pending (current_thread))
293                 return WAIT_IO_COMPLETION;
294         
295         if(ret==-1) {
296                 /* Sleep interrupted with rem time remaining */
297 #ifdef DEBUG_ENABLED
298                 guint32 rems=rem.tv_sec*1000 + rem.tv_nsec/1000000;
299                 
300                 g_message("%s: Still got %d ms to go", __func__, rems);
301 #endif
302                 req=rem;
303                 goto again;
304         }
305
306 #endif /* __linux__ */
307
308         return 0;
309 }
310
311 void
312 Sleep(guint32 ms)
313 {
314         SleepEx(ms, FALSE);
315 }
316
317 gboolean
318 _wapi_thread_cur_apc_pending (void)
319 {
320         return _wapi_thread_apc_pending (get_current_thread_handle ());
321 }
322
323 gboolean
324 _wapi_thread_apc_pending (gpointer handle)
325 {
326         WapiHandle_thread *thread;
327
328         thread = lookup_thread (handle);
329         
330         return thread->wait_handle == INTERRUPTION_REQUESTED_HANDLE;
331 }
332
333 /*
334  * wapi_interrupt_thread:
335  *
336  * The state of the thread handle HANDLE is set to 'interrupted' which means that
337  * if the thread calls one of the WaitFor functions, the function will return with 
338  * WAIT_IO_COMPLETION instead of waiting. Also, if the thread was waiting when
339  * this function was called, the wait will be broken.
340  * It is possible that the wait functions return WAIT_IO_COMPLETION, but the
341  * target thread didn't receive the interrupt signal yet, in this case it should
342  * call the wait function again. This essentially means that the target thread will
343  * busy wait until it is ready to process the interruption.
344  */
345 void
346 wapi_interrupt_thread (gpointer thread_handle)
347 {
348         gpointer wait_handle;
349
350         wait_handle = wapi_prepare_interrupt_thread (thread_handle);
351         wapi_finish_interrupt_thread (wait_handle);
352 }
353
354 gpointer
355 wapi_prepare_interrupt_thread (gpointer thread_handle)
356 {
357         WapiHandle_thread *thread;
358         gpointer prev_handle, wait_handle;
359
360         thread = lookup_thread (thread_handle);
361
362         while (TRUE) {
363                 wait_handle = thread->wait_handle;
364
365                 /* 
366                  * Atomically obtain the handle the thread is waiting on, and
367                  * change it to a flag value.
368                  */
369                 prev_handle = InterlockedCompareExchangePointer (&thread->wait_handle,
370                                                                                                                  INTERRUPTION_REQUESTED_HANDLE, wait_handle);
371                 if (prev_handle == INTERRUPTION_REQUESTED_HANDLE)
372                         /* Already interrupted */
373                         return 0;
374                 if (prev_handle == wait_handle)
375                         break;
376
377                 /* Try again */
378         }
379
380         WAIT_DEBUG (printf ("%p: state -> INTERRUPTED.\n", thread->id););
381
382         return wait_handle;
383 }
384
385 void
386 wapi_finish_interrupt_thread (gpointer wait_handle)
387 {
388         pthread_cond_t *cond;
389         mono_mutex_t *mutex;
390         guint32 idx;
391
392         if (!wait_handle)
393                 /* Not waiting */
394                 return;
395
396         /* If we reach here, then wait_handle is set to the flag value, 
397          * which means that the target thread is either
398          * - before the first CAS in timedwait, which means it won't enter the
399          * wait.
400          * - it is after the first CAS, so it is already waiting, or it will 
401          * enter the wait, and it will be interrupted by the broadcast.
402          */
403         idx = GPOINTER_TO_UINT(wait_handle);
404         cond = &_WAPI_PRIVATE_HANDLES(idx).signal_cond;
405         mutex = &_WAPI_PRIVATE_HANDLES(idx).signal_mutex;
406
407         mono_mutex_lock (mutex);
408         mono_cond_broadcast (cond);
409         mono_mutex_unlock (mutex);
410
411         /* ref added by set_wait_handle */
412         _wapi_handle_unref (wait_handle);
413 }
414
415 /*
416  * wapi_self_interrupt:
417  *
418  *   This is not part of the WIN32 API.
419  * Set the 'interrupted' state of the calling thread if it's NULL.
420  */
421 void
422 wapi_self_interrupt (void)
423 {
424         gpointer wait_handle;
425
426         wait_handle = wapi_prepare_interrupt_thread (get_current_thread_handle ());
427         if (wait_handle)
428                 /* ref added by set_wait_handle */
429                 _wapi_handle_unref (wait_handle);
430 }
431
432 /*
433  * wapi_clear_interruption:
434  *
435  *   This is not part of the WIN32 API. 
436  * Clear the 'interrupted' state of the calling thread.
437  * This function is signal safe
438  */
439 void
440 wapi_clear_interruption (void)
441 {
442         WapiHandle_thread *thread;
443         gpointer prev_handle;
444
445         thread = get_current_thread ();
446
447         prev_handle = InterlockedCompareExchangePointer (&thread->wait_handle,
448                                                                                                          NULL, INTERRUPTION_REQUESTED_HANDLE);
449         if (prev_handle == INTERRUPTION_REQUESTED_HANDLE)
450                 WAIT_DEBUG (printf ("%p: state -> NORMAL.\n", GetCurrentThreadId ()););
451 }
452
453 /**
454  * wapi_thread_set_wait_handle:
455  *
456  *   Set the wait handle for the current thread to HANDLE. Return TRUE on success, FALSE
457  * if the thread is in interrupted state, and cannot start waiting.
458  */
459 gboolean
460 wapi_thread_set_wait_handle (gpointer handle)
461 {
462         WapiHandle_thread *thread;
463         gpointer prev_handle;
464
465         thread = get_current_thread ();
466
467         prev_handle = InterlockedCompareExchangePointer (&thread->wait_handle,
468                                                                                                          handle, NULL);
469         if (prev_handle == NULL) {
470                 /* thread->wait_handle acts as an additional reference to the handle */
471                 _wapi_handle_ref (handle);
472
473                 WAIT_DEBUG (printf ("%p: state -> WAITING.\n", GetCurrentThreadId ()););
474         } else {
475                 g_assert (prev_handle == INTERRUPTION_REQUESTED_HANDLE);
476                 WAIT_DEBUG (printf ("%p: unable to set state to WAITING.\n", GetCurrentThreadId ()););
477         }
478
479         return prev_handle == NULL;
480 }
481
482 /**
483  * wapi_thread_clear_wait_handle:
484  *
485  *   Clear the wait handle of the current thread.
486  */
487 void
488 wapi_thread_clear_wait_handle (gpointer handle)
489 {
490         WapiHandle_thread *thread;
491         gpointer prev_handle;
492
493         thread = get_current_thread ();
494
495         prev_handle = InterlockedCompareExchangePointer (&thread->wait_handle,
496                                                                                                          NULL, handle);
497         if (prev_handle == handle) {
498                 _wapi_handle_unref (handle);
499                 WAIT_DEBUG (printf ("%p: state -> NORMAL.\n", GetCurrentThreadId ()););
500         } else {
501                 /*It can be NULL if it was asynchronously cleared*/
502                 g_assert (prev_handle == INTERRUPTION_REQUESTED_HANDLE || prev_handle == NULL);
503                 WAIT_DEBUG (printf ("%p: finished waiting.\n", GetCurrentThreadId ()););
504         }
505 }
506
507 void
508 _wapi_thread_own_mutex (gpointer mutex)
509 {
510         WapiHandle_thread *thread;
511         
512         thread = get_current_thread ();
513
514         _wapi_handle_ref (mutex);
515         
516         g_ptr_array_add (thread->owned_mutexes, mutex);
517 }
518
519 void
520 _wapi_thread_disown_mutex (gpointer mutex)
521 {
522         WapiHandle_thread *thread;
523
524         thread = get_current_thread ();
525
526         _wapi_handle_unref (mutex);
527         
528         g_ptr_array_remove (thread->owned_mutexes, mutex);
529 }
530
531 char*
532 wapi_current_thread_desc (void)
533 {
534         WapiHandle_thread *thread;
535         gpointer thread_handle;
536         int i;
537         gpointer handle;
538         GString* text;
539         char *res;
540
541         thread_handle = get_current_thread_handle ();
542         thread = lookup_thread (thread_handle);
543
544         handle = thread->wait_handle;
545         text = g_string_new (0);
546         g_string_append_printf (text, "thread handle %p state : ", thread_handle);
547
548         if (!handle)
549                 g_string_append_printf (text, "not waiting");
550         else if (handle == INTERRUPTION_REQUESTED_HANDLE)
551                 g_string_append_printf (text, "interrupted state");
552         else
553                 g_string_append_printf (text, "waiting on %p : %s ", handle, _wapi_handle_typename[_wapi_handle_type (handle)]);
554         g_string_append_printf (text, " owns (");
555         for (i = 0; i < thread->owned_mutexes->len; i++) {
556                 gpointer mutex = g_ptr_array_index (thread->owned_mutexes, i);
557                 if (i > 0)
558                         g_string_append_printf (text, ", %p", mutex);
559                 else
560                         g_string_append_printf (text, "%p", mutex);
561         }
562         g_string_append_printf (text, ")");
563
564         res = text->str;
565         g_string_free (text, FALSE);
566         return res;
567 }