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>
33 #include <mono/utils/mono-lazy-init.h>
34 #include <mono/utils/mono-time.h>
36 #ifdef HAVE_VALGRIND_MEMCHECK_H
37 #include <valgrind/memcheck.h>
41 #define DEBUG(...) g_message(__VA_ARGS__)
47 #define WAIT_DEBUG(code) do { code } while (0)
49 #define WAIT_DEBUG(code) do { } while (0)
52 struct _WapiHandleOps _wapi_thread_ops = {
57 NULL, /* special_wait */
61 static mono_once_t thread_ops_once = MONO_ONCE_INIT;
64 thread_ops_init (void)
66 _wapi_handle_register_capabilities (WAPI_HANDLE_THREAD,
67 WAPI_HANDLE_CAP_WAIT);
71 _wapi_thread_cleanup (void)
76 get_current_thread_handle (void)
80 info = mono_thread_info_current ();
82 g_assert (info->handle);
86 static WapiHandle_thread*
87 lookup_thread (HANDLE handle)
89 WapiHandle_thread *thread;
92 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
98 static WapiHandle_thread*
99 get_current_thread (void)
103 handle = get_current_thread_handle ();
104 return lookup_thread (handle);
108 wapi_thread_handle_set_exited (gpointer handle, guint32 exitstatus)
110 WapiHandle_thread *thread_handle;
112 pid_t pid = _wapi_getpid ();
113 pthread_t tid = pthread_self ();
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
123 DEBUG ("%s: Thread %p terminating", __func__, handle);
125 thread_handle = lookup_thread (handle);
127 DEBUG ("%s: Thread %p abandoning held mutexes", __func__, handle);
129 for (i = 0; i < thread_handle->owned_mutexes->len; i++) {
130 gpointer mutex = g_ptr_array_index (thread_handle->owned_mutexes, i);
132 _wapi_mutex_abandon (mutex, pid, tid);
133 _wapi_thread_disown_mutex (mutex);
135 g_ptr_array_free (thread_handle->owned_mutexes, TRUE);
137 thr_ret = _wapi_handle_lock_handle (handle);
138 g_assert (thr_ret == 0);
140 _wapi_handle_set_signal_state (handle, TRUE, TRUE);
142 thr_ret = _wapi_handle_unlock_handle (handle);
143 g_assert (thr_ret == 0);
145 DEBUG("%s: Recording thread handle %p id %ld status as %d",
146 __func__, handle, thread_handle->id, exitstatus);
148 /* The thread is no longer active, so unref it */
149 _wapi_handle_unref (handle);
153 * wapi_create_thread_handle:
155 * Create a thread handle for the current thread.
158 wapi_create_thread_handle (void)
160 WapiHandle_thread thread_handle = {0}, *thread;
163 mono_once (&thread_ops_once, thread_ops_init);
165 thread_handle.owned_mutexes = g_ptr_array_new ();
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);
175 thread = lookup_thread (handle);
177 thread->id = pthread_self ();
180 * Hold a reference while the thread is active, because we use
181 * the handle to store thread exit information
183 _wapi_handle_ref (handle);
185 DEBUG ("%s: started thread id %ld", __func__, thread->id);
191 wapi_ref_thread_handle (gpointer handle)
193 _wapi_handle_ref (handle);
197 wapi_get_current_thread_handle (void)
199 return get_current_thread_handle ();
203 * GetCurrentThreadId:
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.
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 :)
214 GetCurrentThreadId (void)
216 MonoNativeThreadId id;
218 id = mono_native_thread_id_get ();
219 return MONO_NATIVE_THREAD_ID_TO_UINT (id);
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;
227 sleepex_initialize (void)
229 mono_mutex_init (&sleepex_mutex);
230 mono_cond_init (&sleepex_cond, NULL);
234 sleepex_interrupt (gpointer data)
236 mono_mutex_lock (&sleepex_mutex);
237 mono_cond_broadcast (&sleepex_cond);
238 mono_mutex_unlock (&sleepex_mutex);
241 static inline guint32
242 sleepex_interruptable (guint32 ms)
244 gboolean interrupted;
245 guint32 start, now, end;
247 g_assert (INFINITE == G_MAXUINT32);
249 start = mono_msec_ticks ();
251 if (start < G_MAXUINT32 - ms) {
254 /* start + ms would overflow guint32 */
258 mono_lazy_initialize (&sleepex_init, sleepex_initialize);
260 mono_mutex_lock (&sleepex_mutex);
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);
265 mono_mutex_unlock (&sleepex_mutex);
266 return WAIT_IO_COMPLETION;
270 mono_cond_timedwait_ms (&sleepex_cond, &sleepex_mutex, end - now);
272 mono_cond_wait (&sleepex_cond, &sleepex_mutex);
274 mono_thread_info_uninstall_interrupt (&interrupted);
276 mono_mutex_unlock (&sleepex_mutex);
277 return WAIT_IO_COMPLETION;
281 mono_mutex_unlock (&sleepex_mutex);
288 * @ms: The time in milliseconds to suspend for
289 * @alertable: if TRUE, the wait can be interrupted by an APC call
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.
296 SleepEx (guint32 ms, gboolean alertable)
299 MonoThreadInfo *info;
301 mono_thread_info_yield ();
303 info = mono_thread_info_current ();
304 if (info && mono_thread_info_is_interrupt_state (info))
305 return WAIT_IO_COMPLETION;
311 return sleepex_interruptable (ms);
313 DEBUG("%s: Sleeping for %d ms", __func__, ms);
315 if (ms == INFINITE) {
321 #if defined (__linux__) && !defined(PLATFORM_ANDROID)
322 struct timespec start, target;
324 /* Use clock_nanosleep () to prevent time drifting problems when nanosleep () is interrupted by signals */
325 ret = clock_gettime (CLOCK_MONOTONIC, &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;
337 ret = clock_nanosleep (CLOCK_MONOTONIC, TIMER_ABSTIME, &target, NULL);
340 struct timespec req, rem;
342 req.tv_sec = ms / 1000;
343 req.tv_nsec = (ms % 1000) * 1000000;
346 memset (&rem, 0, sizeof (rem));
347 ret = nanosleep (&req, &rem);
349 #endif /* __linux__ */
362 _wapi_thread_cur_apc_pending (void)
364 return mono_thread_info_is_interrupt_state (mono_thread_info_current ());
368 _wapi_thread_own_mutex (gpointer mutex)
370 WapiHandle_thread *thread;
372 thread = get_current_thread ();
374 _wapi_handle_ref (mutex);
376 g_ptr_array_add (thread->owned_mutexes, mutex);
380 _wapi_thread_disown_mutex (gpointer mutex)
382 WapiHandle_thread *thread;
384 thread = get_current_thread ();
386 _wapi_handle_unref (mutex);
388 g_ptr_array_remove (thread->owned_mutexes, mutex);
392 wapi_current_thread_desc (void)
394 WapiHandle_thread *thread;
395 gpointer thread_handle;
400 thread_handle = get_current_thread_handle ();
401 thread = lookup_thread (thread_handle);
403 text = g_string_new (0);
404 g_string_append_printf (text, "thread handle %p state : ", thread_handle);
406 mono_thread_info_describe_interrupt_token (mono_thread_info_current (), text);
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, ")");
414 g_string_free (text, FALSE);