2 * threads.c: Thread handles
5 * Dick Porter (dick@ximian.com)
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)
20 #include <sys/types.h>
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>
30 #include <mono/utils/mono-threads.h>
31 #include <mono/utils/atomic.h>
32 #include <mono/utils/mono-mutex.h>
34 #ifdef HAVE_VALGRIND_MEMCHECK_H
35 #include <valgrind/memcheck.h>
39 #define DEBUG(...) g_message(__VA_ARGS__)
45 #define WAIT_DEBUG(code) do { code } while (0)
47 #define WAIT_DEBUG(code) do { } while (0)
50 struct _WapiHandleOps _wapi_thread_ops
= {
55 NULL
, /* special_wait */
59 static mono_once_t thread_ops_once
= MONO_ONCE_INIT
;
62 thread_ops_init (void)
64 _wapi_handle_register_capabilities (WAPI_HANDLE_THREAD
,
65 WAPI_HANDLE_CAP_WAIT
);
69 _wapi_thread_cleanup (void)
74 get_current_thread_handle (void)
78 info
= mono_thread_info_current ();
80 g_assert (info
->handle
);
84 static WapiHandle_thread
*
85 lookup_thread (HANDLE handle
)
87 WapiHandle_thread
*thread
;
90 ok
= _wapi_lookup_handle (handle
, WAPI_HANDLE_THREAD
,
96 static WapiHandle_thread
*
97 get_current_thread (void)
101 handle
= get_current_thread_handle ();
102 return lookup_thread (handle
);
106 wapi_thread_handle_set_exited (gpointer handle
, guint32 exitstatus
)
108 WapiHandle_thread
*thread_handle
;
110 pid_t pid
= _wapi_getpid ();
111 pthread_t tid
= pthread_self ();
113 if (_wapi_handle_issignalled (handle
) ||
114 _wapi_handle_type (handle
) == WAPI_HANDLE_UNUSED
) {
115 /* We must have already deliberately finished with
116 * this thread, so don't do any more now
121 DEBUG ("%s: Thread %p terminating", __func__
, handle
);
123 thread_handle
= lookup_thread (handle
);
125 DEBUG ("%s: Thread %p abandoning held mutexes", __func__
, handle
);
127 for (i
= 0; i
< thread_handle
->owned_mutexes
->len
; i
++) {
128 gpointer mutex
= g_ptr_array_index (thread_handle
->owned_mutexes
, i
);
130 _wapi_mutex_abandon (mutex
, pid
, tid
);
131 _wapi_thread_disown_mutex (mutex
);
133 g_ptr_array_free (thread_handle
->owned_mutexes
, TRUE
);
135 thr_ret
= _wapi_handle_lock_handle (handle
);
136 g_assert (thr_ret
== 0);
138 _wapi_handle_set_signal_state (handle
, TRUE
, TRUE
);
140 thr_ret
= _wapi_handle_unlock_handle (handle
);
141 g_assert (thr_ret
== 0);
143 DEBUG("%s: Recording thread handle %p id %ld status as %d",
144 __func__
, handle
, thread_handle
->id
, exitstatus
);
146 /* The thread is no longer active, so unref it */
147 _wapi_handle_unref (handle
);
151 * wapi_create_thread_handle:
153 * Create a thread handle for the current thread.
156 wapi_create_thread_handle (void)
158 WapiHandle_thread thread_handle
= {0}, *thread
;
161 mono_once (&thread_ops_once
, thread_ops_init
);
163 thread_handle
.owned_mutexes
= g_ptr_array_new ();
165 handle
= _wapi_handle_new (WAPI_HANDLE_THREAD
, &thread_handle
);
166 if (handle
== _WAPI_HANDLE_INVALID
) {
167 g_warning ("%s: error creating thread handle", __func__
);
168 SetLastError (ERROR_GEN_FAILURE
);
173 thread
= lookup_thread (handle
);
175 thread
->id
= pthread_self ();
178 * Hold a reference while the thread is active, because we use
179 * the handle to store thread exit information
181 _wapi_handle_ref (handle
);
183 DEBUG ("%s: started thread id %ld", __func__
, thread
->id
);
189 wapi_ref_thread_handle (gpointer handle
)
191 _wapi_handle_ref (handle
);
195 wapi_get_current_thread_handle (void)
197 return get_current_thread_handle ();
201 * GetCurrentThreadId:
203 * Looks up the thread ID of the current thread. This ID can be
204 * passed to OpenThread() to create a new handle on this thread.
206 * Return value: the thread ID. NB this is defined as DWORD (ie 32
207 * bit) in the MS API, but we need to cope with 64 bit IDs for s390x
208 * and amd64. This doesn't really break the API, it just embraces and
209 * extends it on 64bit platforms :)
212 GetCurrentThreadId (void)
214 MonoNativeThreadId id
;
216 id
= mono_native_thread_id_get ();
217 return MONO_NATIVE_THREAD_ID_TO_UINT (id
);
222 * @ms: The time in milliseconds to suspend for
223 * @alertable: if TRUE, the wait can be interrupted by an APC call
225 * Suspends execution of the current thread for @ms milliseconds. A
226 * value of zero causes the thread to relinquish its time slice. A
227 * value of %INFINITE causes an infinite delay.
230 SleepEx (guint32 ms
, gboolean alertable
)
235 gpointer current_thread
= NULL
;
236 #if defined (__linux__) && !defined(PLATFORM_ANDROID)
237 struct timespec start
, target
;
242 DEBUG("%s: Sleeping for %d ms", __func__
, ms
);
245 current_thread
= get_current_thread_handle ();
247 if (_wapi_thread_apc_pending (current_thread
))
248 return WAIT_IO_COMPLETION
;
256 /* FIXME: check for INFINITE and sleep forever */
261 req
.tv_nsec
=ms_rem
*1000000;
263 #if defined (__linux__) && !defined(PLATFORM_ANDROID)
264 /* Use clock_nanosleep () to prevent time drifting problems when nanosleep () is interrupted by signals */
265 ret
= clock_gettime (CLOCK_MONOTONIC
, &start
);
268 target
.tv_sec
+= ms_quot
;
269 target
.tv_nsec
+= ms_rem
* 1000000;
270 if (target
.tv_nsec
> 999999999) {
271 target
.tv_nsec
-= 999999999;
276 ret
= clock_nanosleep (CLOCK_MONOTONIC
, TIMER_ABSTIME
, &target
, NULL
);
278 if (alertable
&& _wapi_thread_apc_pending (current_thread
))
279 return WAIT_IO_COMPLETION
;
288 memset (&rem
, 0, sizeof (rem
));
289 ret
=nanosleep(&req
, &rem
);
291 if (alertable
&& _wapi_thread_apc_pending (current_thread
))
292 return WAIT_IO_COMPLETION
;
295 /* Sleep interrupted with rem time remaining */
297 guint32 rems
=rem
.tv_sec
*1000 + rem
.tv_nsec
/1000000;
299 g_message("%s: Still got %d ms to go", __func__
, rems
);
305 #endif /* __linux__ */
317 _wapi_thread_cur_apc_pending (void)
319 return _wapi_thread_apc_pending (get_current_thread_handle ());
323 _wapi_thread_apc_pending (gpointer handle
)
325 WapiHandle_thread
*thread
;
327 thread
= lookup_thread (handle
);
329 return thread
->wait_handle
== INTERRUPTION_REQUESTED_HANDLE
;
333 * wapi_interrupt_thread:
335 * The state of the thread handle HANDLE is set to 'interrupted' which means that
336 * if the thread calls one of the WaitFor functions, the function will return with
337 * WAIT_IO_COMPLETION instead of waiting. Also, if the thread was waiting when
338 * this function was called, the wait will be broken.
339 * It is possible that the wait functions return WAIT_IO_COMPLETION, but the
340 * target thread didn't receive the interrupt signal yet, in this case it should
341 * call the wait function again. This essentially means that the target thread will
342 * busy wait until it is ready to process the interruption.
345 wapi_interrupt_thread (gpointer thread_handle
)
347 gpointer wait_handle
;
349 wait_handle
= wapi_prepare_interrupt_thread (thread_handle
);
350 wapi_finish_interrupt_thread (wait_handle
);
354 wapi_prepare_interrupt_thread (gpointer thread_handle
)
356 WapiHandle_thread
*thread
;
357 gpointer prev_handle
, wait_handle
;
359 thread
= lookup_thread (thread_handle
);
362 wait_handle
= thread
->wait_handle
;
365 * Atomically obtain the handle the thread is waiting on, and
366 * change it to a flag value.
368 prev_handle
= InterlockedCompareExchangePointer (&thread
->wait_handle
,
369 INTERRUPTION_REQUESTED_HANDLE
, wait_handle
);
370 if (prev_handle
== INTERRUPTION_REQUESTED_HANDLE
)
371 /* Already interrupted */
373 if (prev_handle
== wait_handle
)
379 WAIT_DEBUG (printf ("%p: state -> INTERRUPTED.\n", thread
->id
););
385 wapi_finish_interrupt_thread (gpointer wait_handle
)
387 pthread_cond_t
*cond
;
395 /* If we reach here, then wait_handle is set to the flag value,
396 * which means that the target thread is either
397 * - before the first CAS in timedwait, which means it won't enter the
399 * - it is after the first CAS, so it is already waiting, or it will
400 * enter the wait, and it will be interrupted by the broadcast.
402 idx
= GPOINTER_TO_UINT(wait_handle
);
403 cond
= &_WAPI_PRIVATE_HANDLES(idx
).signal_cond
;
404 mutex
= &_WAPI_PRIVATE_HANDLES(idx
).signal_mutex
;
406 mono_mutex_lock (mutex
);
407 mono_cond_broadcast (cond
);
408 mono_mutex_unlock (mutex
);
410 /* ref added by set_wait_handle */
411 _wapi_handle_unref (wait_handle
);
415 * wapi_self_interrupt:
417 * This is not part of the WIN32 API.
418 * Set the 'interrupted' state of the calling thread if it's NULL.
421 wapi_self_interrupt (void)
423 gpointer wait_handle
;
425 wait_handle
= wapi_prepare_interrupt_thread (get_current_thread_handle ());
427 /* ref added by set_wait_handle */
428 _wapi_handle_unref (wait_handle
);
432 * wapi_clear_interruption:
434 * This is not part of the WIN32 API.
435 * Clear the 'interrupted' state of the calling thread.
436 * This function is signal safe
439 wapi_clear_interruption (void)
441 WapiHandle_thread
*thread
;
442 gpointer prev_handle
;
444 thread
= get_current_thread ();
446 prev_handle
= InterlockedCompareExchangePointer (&thread
->wait_handle
,
447 NULL
, INTERRUPTION_REQUESTED_HANDLE
);
448 if (prev_handle
== INTERRUPTION_REQUESTED_HANDLE
)
449 WAIT_DEBUG (printf ("%p: state -> NORMAL.\n", GetCurrentThreadId ()););
453 * wapi_thread_set_wait_handle:
455 * Set the wait handle for the current thread to HANDLE. Return TRUE on success, FALSE
456 * if the thread is in interrupted state, and cannot start waiting.
459 wapi_thread_set_wait_handle (gpointer handle
)
461 WapiHandle_thread
*thread
;
462 gpointer prev_handle
;
464 thread
= get_current_thread ();
466 prev_handle
= InterlockedCompareExchangePointer (&thread
->wait_handle
,
468 if (prev_handle
== NULL
) {
469 /* thread->wait_handle acts as an additional reference to the handle */
470 _wapi_handle_ref (handle
);
472 WAIT_DEBUG (printf ("%p: state -> WAITING.\n", GetCurrentThreadId ()););
474 g_assert (prev_handle
== INTERRUPTION_REQUESTED_HANDLE
);
475 WAIT_DEBUG (printf ("%p: unable to set state to WAITING.\n", GetCurrentThreadId ()););
478 return prev_handle
== NULL
;
482 * wapi_thread_clear_wait_handle:
484 * Clear the wait handle of the current thread.
487 wapi_thread_clear_wait_handle (gpointer handle
)
489 WapiHandle_thread
*thread
;
490 gpointer prev_handle
;
492 thread
= get_current_thread ();
494 prev_handle
= InterlockedCompareExchangePointer (&thread
->wait_handle
,
496 if (prev_handle
== handle
) {
497 _wapi_handle_unref (handle
);
498 WAIT_DEBUG (printf ("%p: state -> NORMAL.\n", GetCurrentThreadId ()););
500 /*It can be NULL if it was asynchronously cleared*/
501 g_assert (prev_handle
== INTERRUPTION_REQUESTED_HANDLE
|| prev_handle
== NULL
);
502 WAIT_DEBUG (printf ("%p: finished waiting.\n", GetCurrentThreadId ()););
507 _wapi_thread_own_mutex (gpointer mutex
)
509 WapiHandle_thread
*thread
;
511 thread
= get_current_thread ();
513 _wapi_handle_ref (mutex
);
515 g_ptr_array_add (thread
->owned_mutexes
, mutex
);
519 _wapi_thread_disown_mutex (gpointer mutex
)
521 WapiHandle_thread
*thread
;
523 thread
= get_current_thread ();
525 _wapi_handle_unref (mutex
);
527 g_ptr_array_remove (thread
->owned_mutexes
, mutex
);
531 wapi_current_thread_desc (void)
533 WapiHandle_thread
*thread
;
534 gpointer thread_handle
;
540 thread_handle
= get_current_thread_handle ();
541 thread
= lookup_thread (thread_handle
);
543 handle
= thread
->wait_handle
;
544 text
= g_string_new (0);
545 g_string_append_printf (text
, "thread handle %p state : ", thread_handle
);
548 g_string_append_printf (text
, "not waiting");
549 else if (handle
== INTERRUPTION_REQUESTED_HANDLE
)
550 g_string_append_printf (text
, "interrupted state");
552 g_string_append_printf (text
, "waiting on %p : %s ", handle
, _wapi_handle_typename
[_wapi_handle_type (handle
)]);
553 g_string_append_printf (text
, " owns (");
554 for (i
= 0; i
< thread
->owned_mutexes
->len
; i
++) {
555 gpointer mutex
= g_ptr_array_index (thread
->owned_mutexes
, i
);
557 g_string_append_printf (text
, ", %p", mutex
);
559 g_string_append_printf (text
, "%p", mutex
);
561 g_string_append_printf (text
, ")");
564 g_string_free (text
, FALSE
);