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)
234 gpointer current_thread = NULL;
235 #if defined (__linux__) && !defined(PLATFORM_ANDROID)
236 struct timespec start, target;
241 DEBUG("%s: Sleeping for %d ms", __func__, ms);
244 current_thread = get_current_thread_handle ();
246 if (_wapi_thread_cur_apc_pending ())
247 return WAIT_IO_COMPLETION;
255 /* FIXME: check for INFINITE and sleep forever */
259 #if defined (__linux__) && !defined(PLATFORM_ANDROID)
260 /* Use clock_nanosleep () to prevent time drifting problems when nanosleep () is interrupted by signals */
261 ret = clock_gettime (CLOCK_MONOTONIC, &start);
264 target.tv_sec += ms_quot;
265 target.tv_nsec += ms_rem * 1000000;
266 if (target.tv_nsec > 999999999) {
267 target.tv_nsec -= 999999999;
272 ret = clock_nanosleep (CLOCK_MONOTONIC, TIMER_ABSTIME, &target, NULL);
274 if (alertable && _wapi_thread_cur_apc_pending ())
275 return WAIT_IO_COMPLETION;
285 req.tv_nsec=ms_rem*1000000;
288 memset (&rem, 0, sizeof (rem));
289 ret=nanosleep(&req, &rem);
291 if (alertable && _wapi_thread_cur_apc_pending ())
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 mono_thread_info_is_interrupt_state (mono_thread_info_current ());
323 _wapi_thread_own_mutex (gpointer mutex)
325 WapiHandle_thread *thread;
327 thread = get_current_thread ();
329 _wapi_handle_ref (mutex);
331 g_ptr_array_add (thread->owned_mutexes, mutex);
335 _wapi_thread_disown_mutex (gpointer mutex)
337 WapiHandle_thread *thread;
339 thread = get_current_thread ();
341 _wapi_handle_unref (mutex);
343 g_ptr_array_remove (thread->owned_mutexes, mutex);
347 wapi_current_thread_desc (void)
349 WapiHandle_thread *thread;
350 gpointer thread_handle;
355 thread_handle = get_current_thread_handle ();
356 thread = lookup_thread (thread_handle);
358 text = g_string_new (0);
359 g_string_append_printf (text, "thread handle %p state : ", thread_handle);
361 mono_thread_info_describe_interrupt_token (mono_thread_info_current (), text);
363 g_string_append_printf (text, " owns (");
364 for (i = 0; i < thread->owned_mutexes->len; i++)
365 g_string_append_printf (text, i > 0 ? ", %p" : "%p", g_ptr_array_index (thread->owned_mutexes, i));
366 g_string_append_printf (text, ")");
369 g_string_free (text, FALSE);