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/thread-private.h>
27 #include <mono/io-layer/mutex-private.h>
29 #include <mono/utils/mono-threads.h>
30 #include <mono/utils/atomic.h>
31 #include <mono/utils/mono-time.h>
32 #include <mono/utils/mono-once.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 */
60 THREAD_PRIORITY_LOWEST = -2,
61 THREAD_PRIORITY_BELOW_NORMAL = -1,
62 THREAD_PRIORITY_NORMAL = 0,
63 THREAD_PRIORITY_ABOVE_NORMAL = 1,
64 THREAD_PRIORITY_HIGHEST = 2
67 static mono_once_t thread_ops_once = MONO_ONCE_INIT;
70 thread_ops_init (void)
72 _wapi_handle_register_capabilities (WAPI_HANDLE_THREAD,
73 WAPI_HANDLE_CAP_WAIT);
77 _wapi_thread_cleanup (void)
82 get_current_thread_handle (void)
86 info = mono_thread_info_current ();
88 g_assert (info->handle);
92 static WapiHandle_thread*
93 lookup_thread (HANDLE handle)
95 WapiHandle_thread *thread;
98 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
104 static WapiHandle_thread*
105 get_current_thread (void)
109 handle = get_current_thread_handle ();
110 return lookup_thread (handle);
114 wapi_thread_handle_set_exited (gpointer handle, guint32 exitstatus)
116 WapiHandle_thread *thread_handle;
118 pid_t pid = _wapi_getpid ();
119 pthread_t tid = pthread_self ();
121 if (_wapi_handle_issignalled (handle) ||
122 _wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) {
123 /* We must have already deliberately finished with
124 * this thread, so don't do any more now
129 DEBUG ("%s: Thread %p terminating", __func__, handle);
131 thread_handle = lookup_thread (handle);
133 DEBUG ("%s: Thread %p abandoning held mutexes", __func__, handle);
135 for (i = 0; i < thread_handle->owned_mutexes->len; i++) {
136 gpointer mutex = g_ptr_array_index (thread_handle->owned_mutexes, i);
138 _wapi_mutex_abandon (mutex, pid, tid);
139 _wapi_thread_disown_mutex (mutex);
141 g_ptr_array_free (thread_handle->owned_mutexes, TRUE);
143 thr_ret = _wapi_handle_lock_handle (handle);
144 g_assert (thr_ret == 0);
146 _wapi_handle_set_signal_state (handle, TRUE, TRUE);
148 thr_ret = _wapi_handle_unlock_handle (handle);
149 g_assert (thr_ret == 0);
151 DEBUG("%s: Recording thread handle %p id %ld status as %d",
152 __func__, handle, thread_handle->id, exitstatus);
154 /* The thread is no longer active, so unref it */
155 _wapi_handle_unref (handle);
159 * wapi_create_thread_handle:
161 * Create a thread handle for the current thread.
164 wapi_create_thread_handle (void)
166 WapiHandle_thread thread_handle = {0}, *thread;
169 mono_once (&thread_ops_once, thread_ops_init);
171 thread_handle.owned_mutexes = g_ptr_array_new ();
173 handle = _wapi_handle_new (WAPI_HANDLE_THREAD, &thread_handle);
174 if (handle == _WAPI_HANDLE_INVALID) {
175 g_warning ("%s: error creating thread handle", __func__);
176 SetLastError (ERROR_GEN_FAILURE);
181 thread = lookup_thread (handle);
183 thread->id = pthread_self ();
186 * Hold a reference while the thread is active, because we use
187 * the handle to store thread exit information
189 _wapi_handle_ref (handle);
191 DEBUG ("%s: started thread id %ld", __func__, thread->id);
197 wapi_ref_thread_handle (gpointer handle)
199 _wapi_handle_ref (handle);
203 wapi_get_current_thread_handle (void)
205 return get_current_thread_handle ();
209 _wapi_thread_cur_apc_pending (void)
211 return mono_thread_info_is_interrupt_state (mono_thread_info_current ());
215 _wapi_thread_own_mutex (gpointer mutex)
217 WapiHandle_thread *thread;
219 thread = get_current_thread ();
221 _wapi_handle_ref (mutex);
223 g_ptr_array_add (thread->owned_mutexes, mutex);
227 _wapi_thread_disown_mutex (gpointer mutex)
229 WapiHandle_thread *thread;
231 thread = get_current_thread ();
233 _wapi_handle_unref (mutex);
235 g_ptr_array_remove (thread->owned_mutexes, mutex);
239 * _wapi_thread_posix_priority_to_priority:
241 * Convert a POSIX priority to a WapiThreadPriority.
242 * sched_priority is a POSIX priority,
243 * policy is the current scheduling policy
245 static WapiThreadPriority
246 _wapi_thread_posix_priority_to_priority (int sched_priority, int policy)
248 /* Necessary to get valid priority range */
249 #ifdef _POSIX_PRIORITY_SCHEDULING
255 WapiThreadPriority priorities[] = {
256 THREAD_PRIORITY_LOWEST,
257 THREAD_PRIORITY_LOWEST,
258 THREAD_PRIORITY_BELOW_NORMAL,
259 THREAD_PRIORITY_NORMAL,
260 THREAD_PRIORITY_ABOVE_NORMAL,
261 THREAD_PRIORITY_HIGHEST,
262 THREAD_PRIORITY_HIGHEST
265 max = sched_get_priority_max (policy);
266 min = sched_get_priority_min (policy);
268 /* Partition priority range linearly,
269 assign each partition a thread priority */
270 if (max != min && 0 <= max && 0 <= min) {
271 for (i=1, priority=min, chunk=(max-min)/7;
272 i<6 && sched_priority > priority;
279 return (THREAD_PRIORITY_HIGHEST);
283 return (priorities[i-1]);
288 return (THREAD_PRIORITY_NORMAL);
292 * _wapi_thread_priority_to_posix_priority:
294 * Convert a WapiThreadPriority to a POSIX priority.
295 * priority is a WapiThreadPriority,
296 * policy is the current scheduling policy
299 _wapi_thread_priority_to_posix_priority (WapiThreadPriority priority, int policy)
301 /* Necessary to get valid priority range */
302 #ifdef _POSIX_PRIORITY_SCHEDULING
307 WapiThreadPriority priorities[] = {
308 THREAD_PRIORITY_LOWEST,
309 THREAD_PRIORITY_LOWEST,
310 THREAD_PRIORITY_BELOW_NORMAL,
311 THREAD_PRIORITY_NORMAL,
312 THREAD_PRIORITY_ABOVE_NORMAL,
313 THREAD_PRIORITY_HIGHEST,
314 THREAD_PRIORITY_HIGHEST
317 max = sched_get_priority_max (policy);
318 min = sched_get_priority_min (policy);
320 /* Partition priority range linearly,
321 numerically approximate matching ThreadPriority */
322 if (max != min && 0 <= max && 0 <= min) {
323 for (i=0; i<7; ++i) {
324 if (priorities[i] == priority) {
325 posix_priority = min + ((max-min)/7) * i;
326 if (max < posix_priority)
331 return posix_priority;
354 * @param handle: The thread handle to query.
356 * Gets the priority of the given thread.
357 * @return: A MonoThreadPriority approximating the current POSIX
358 * thread priority, or THREAD_PRIORITY_NORMAL on error.
361 GetThreadPriority (gpointer handle)
363 struct _WapiHandle_thread *thread_handle;
365 struct sched_param param;
366 gboolean ok = _wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
367 (gpointer *)&thread_handle);
370 return (THREAD_PRIORITY_NORMAL);
373 switch (pthread_getschedparam (thread_handle->id, &policy, ¶m)) {
375 return (_wapi_thread_posix_priority_to_priority (param.sched_priority, policy));
377 g_warning ("pthread_getschedparam: error looking up thread id %x", (gsize)thread_handle->id);
380 return (THREAD_PRIORITY_NORMAL);
385 * @param handle: The thread handle to query.
386 * @param priority: The priority to give to the thread.
388 * Sets the priority of the given thread.
389 * @return: TRUE on success, FALSE on failure or error.
392 SetThreadPriority (gpointer handle, gint32 priority)
394 struct _WapiHandle_thread *thread_handle;
398 struct sched_param param;
399 gboolean ok = _wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
400 (gpointer *)&thread_handle);
406 rv = pthread_getschedparam (thread_handle->id, &policy, ¶m);
409 g_warning ("pthread_getschedparam: error looking up thread id %x", (gsize)thread_handle->id);
413 posix_priority = _wapi_thread_priority_to_posix_priority (priority, policy);
414 if (0 > posix_priority)
417 param.sched_priority = posix_priority;
418 switch (pthread_setschedparam (thread_handle->id, policy, ¶m)) {
422 g_warning ("pthread_setschedparam: error looking up thread id %x", (gsize)thread_handle->id);
425 g_warning ("%s: priority %d not supported", __func__, priority);
428 g_warning ("%s: permission denied", __func__);
436 wapi_current_thread_desc (void)
438 WapiHandle_thread *thread;
439 gpointer thread_handle;
444 thread_handle = get_current_thread_handle ();
445 thread = lookup_thread (thread_handle);
447 text = g_string_new (0);
448 g_string_append_printf (text, "thread handle %p state : ", thread_handle);
450 mono_thread_info_describe_interrupt_token (mono_thread_info_current (), text);
452 g_string_append_printf (text, " owns (");
453 for (i = 0; i < thread->owned_mutexes->len; i++)
454 g_string_append_printf (text, i > 0 ? ", %p" : "%p", g_ptr_array_index (thread->owned_mutexes, i));
455 g_string_append_printf (text, ")");
458 g_string_free (text, FALSE);