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-time.h>
35 #ifdef HAVE_VALGRIND_MEMCHECK_H
36 #include <valgrind/memcheck.h>
40 #define DEBUG(...) g_message(__VA_ARGS__)
46 #define WAIT_DEBUG(code) do { code } while (0)
48 #define WAIT_DEBUG(code) do { } while (0)
51 struct _WapiHandleOps _wapi_thread_ops = {
56 NULL, /* special_wait */
60 static mono_once_t thread_ops_once = MONO_ONCE_INIT;
63 thread_ops_init (void)
65 _wapi_handle_register_capabilities (WAPI_HANDLE_THREAD,
66 WAPI_HANDLE_CAP_WAIT);
70 _wapi_thread_cleanup (void)
75 get_current_thread_handle (void)
79 info = mono_thread_info_current ();
81 g_assert (info->handle);
85 static WapiHandle_thread*
86 lookup_thread (HANDLE handle)
88 WapiHandle_thread *thread;
91 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
97 static WapiHandle_thread*
98 get_current_thread (void)
102 handle = get_current_thread_handle ();
103 return lookup_thread (handle);
107 wapi_thread_handle_set_exited (gpointer handle, guint32 exitstatus)
109 WapiHandle_thread *thread_handle;
111 pid_t pid = _wapi_getpid ();
112 pthread_t tid = pthread_self ();
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
122 DEBUG ("%s: Thread %p terminating", __func__, handle);
124 thread_handle = lookup_thread (handle);
126 DEBUG ("%s: Thread %p abandoning held mutexes", __func__, handle);
128 for (i = 0; i < thread_handle->owned_mutexes->len; i++) {
129 gpointer mutex = g_ptr_array_index (thread_handle->owned_mutexes, i);
131 _wapi_mutex_abandon (mutex, pid, tid);
132 _wapi_thread_disown_mutex (mutex);
134 g_ptr_array_free (thread_handle->owned_mutexes, TRUE);
136 thr_ret = _wapi_handle_lock_handle (handle);
137 g_assert (thr_ret == 0);
139 _wapi_handle_set_signal_state (handle, TRUE, TRUE);
141 thr_ret = _wapi_handle_unlock_handle (handle);
142 g_assert (thr_ret == 0);
144 DEBUG("%s: Recording thread handle %p id %ld status as %d",
145 __func__, handle, thread_handle->id, exitstatus);
147 /* The thread is no longer active, so unref it */
148 _wapi_handle_unref (handle);
152 * wapi_create_thread_handle:
154 * Create a thread handle for the current thread.
157 wapi_create_thread_handle (void)
159 WapiHandle_thread thread_handle = {0}, *thread;
162 mono_once (&thread_ops_once, thread_ops_init);
164 thread_handle.owned_mutexes = g_ptr_array_new ();
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);
174 thread = lookup_thread (handle);
176 thread->id = pthread_self ();
179 * Hold a reference while the thread is active, because we use
180 * the handle to store thread exit information
182 _wapi_handle_ref (handle);
184 DEBUG ("%s: started thread id %ld", __func__, thread->id);
190 wapi_ref_thread_handle (gpointer handle)
192 _wapi_handle_ref (handle);
196 wapi_get_current_thread_handle (void)
198 return get_current_thread_handle ();
202 _wapi_thread_cur_apc_pending (void)
204 return mono_thread_info_is_interrupt_state (mono_thread_info_current ());
208 _wapi_thread_own_mutex (gpointer mutex)
210 WapiHandle_thread *thread;
212 thread = get_current_thread ();
214 _wapi_handle_ref (mutex);
216 g_ptr_array_add (thread->owned_mutexes, mutex);
220 _wapi_thread_disown_mutex (gpointer mutex)
222 WapiHandle_thread *thread;
224 thread = get_current_thread ();
226 _wapi_handle_unref (mutex);
228 g_ptr_array_remove (thread->owned_mutexes, mutex);
232 wapi_current_thread_desc (void)
234 WapiHandle_thread *thread;
235 gpointer thread_handle;
240 thread_handle = get_current_thread_handle ();
241 thread = lookup_thread (thread_handle);
243 text = g_string_new (0);
244 g_string_append_printf (text, "thread handle %p state : ", thread_handle);
246 mono_thread_info_describe_interrupt_token (mono_thread_info_current (), text);
248 g_string_append_printf (text, " owns (");
249 for (i = 0; i < thread->owned_mutexes->len; i++)
250 g_string_append_printf (text, i > 0 ? ", %p" : "%p", g_ptr_array_index (thread->owned_mutexes, i));
251 g_string_append_printf (text, ")");
254 g_string_free (text, FALSE);