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)
21 #include <sys/types.h>
24 #include <mono/io-layer/wapi.h>
25 #include <mono/io-layer/wapi-private.h>
26 #include <mono/io-layer/handles-private.h>
27 #include <mono/io-layer/misc-private.h>
28 #include <mono/io-layer/thread-private.h>
29 #include <mono/io-layer/mutex-private.h>
31 #include <mono/utils/mono-threads.h>
32 #include <mono/utils/gc_wrapper.h>
33 #include <mono/utils/atomic.h>
34 #include <mono/utils/mono-mutex.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 /* Hash threads with tids. I thought of using TLS for this, but that
53 * would have to set the data in the new thread, which is more hassle
55 static mono_once_t thread_hash_once = MONO_ONCE_INIT;
56 static pthread_key_t thread_hash_key;
58 /* This key is used with attached threads and a destructor to signal
59 * when attached threads exit, as they don't have the thread_exit()
62 static pthread_key_t thread_attached_key;
64 struct _WapiHandleOps _wapi_thread_ops = {
69 NULL, /* special_wait */
73 static mono_once_t thread_ops_once=MONO_ONCE_INIT;
75 static void thread_ops_init (void)
77 _wapi_handle_register_capabilities (WAPI_HANDLE_THREAD,
78 WAPI_HANDLE_CAP_WAIT);
81 void _wapi_thread_cleanup (void)
85 ret = pthread_key_delete (thread_hash_key);
88 ret = pthread_key_delete (thread_attached_key);
92 /* Called by thread_exit(), but maybe indirectly by
93 * mono_thread_manage() via mono_thread_signal_self() too
95 static void _wapi_thread_abandon_mutexes (gpointer handle)
97 struct _WapiHandle_thread *thread_handle;
100 pid_t pid = _wapi_getpid ();
101 pthread_t tid = pthread_self ();
103 DEBUG ("%s: Thread %p abandoning held mutexes", __func__, handle);
105 if (handle == NULL) {
106 handle = _wapi_thread_handle_from_id (pthread_self ());
107 if (handle == NULL) {
108 /* Something gone badly wrong... */
113 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
114 (gpointer *)&thread_handle);
116 g_warning ("%s: error looking up thread handle %p", __func__,
121 if (!pthread_equal (thread_handle->id, tid)) {
125 for (i = 0; i < thread_handle->owned_mutexes->len; i++) {
126 gpointer mutex = g_ptr_array_index (thread_handle->owned_mutexes, i);
128 _wapi_mutex_abandon (mutex, pid, tid);
129 _wapi_thread_disown_mutex (mutex);
133 void _wapi_thread_set_termination_details (gpointer handle,
136 struct _WapiHandle_thread *thread_handle;
140 if (_wapi_handle_issignalled (handle) ||
141 _wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) {
142 /* We must have already deliberately finished with
143 * this thread, so don't do any more now
148 DEBUG ("%s: Thread %p terminating", __func__, handle);
150 _wapi_thread_abandon_mutexes (handle);
152 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
153 (gpointer *)&thread_handle);
155 g_warning ("%s: error looking up thread handle %p", __func__,
161 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
163 thr_ret = _wapi_handle_lock_handle (handle);
164 g_assert (thr_ret == 0);
166 thread_handle->exitstatus = exitstatus;
167 thread_handle->state = THREAD_STATE_EXITED;
168 g_ptr_array_free (thread_handle->owned_mutexes, TRUE);
170 _wapi_handle_set_signal_state (handle, TRUE, TRUE);
172 thr_ret = _wapi_handle_unlock_handle (handle);
173 g_assert (thr_ret == 0);
174 pthread_cleanup_pop (0);
176 DEBUG("%s: Recording thread handle %p id %ld status as %d",
177 __func__, handle, thread_handle->id, exitstatus);
179 /* The thread is no longer active, so unref it */
180 _wapi_handle_unref (handle);
183 void _wapi_thread_signal_self (guint32 exitstatus)
187 handle = _wapi_thread_handle_from_id (pthread_self ());
188 if (handle == NULL) {
189 /* Something gone badly wrong... */
193 _wapi_thread_set_termination_details (handle, exitstatus);
196 /* Called by the thread creation code as a thread is finishing up, and
199 static void thread_exit (guint32 exitstatus, gpointer handle) G_GNUC_NORETURN;
200 #if defined(__native_client__)
201 void nacl_shutdown_gc_thread(void);
203 static void thread_exit (guint32 exitstatus, gpointer handle)
205 #if defined(__native_client__)
206 nacl_shutdown_gc_thread();
208 _wapi_thread_set_termination_details (handle, exitstatus);
210 /* Call pthread_exit() to call destructors and really exit the
213 mono_gc_pthread_exit (NULL);
217 wapi_thread_set_exit_code (guint32 exitstatus, gpointer handle)
219 _wapi_thread_set_termination_details (handle, exitstatus);
222 static void thread_attached_exit (gpointer handle)
224 /* Drop the extra reference we take in thread_attach, now this
228 _wapi_thread_set_termination_details (handle, 0);
231 static void thread_hash_init(void)
235 thr_ret = pthread_key_create (&thread_hash_key, NULL);
236 g_assert (thr_ret == 0);
238 thr_ret = pthread_key_create (&thread_attached_key,
239 thread_attached_exit);
240 g_assert (thr_ret == 0);
244 * wapi_create_thread_handle:
246 * Create a thread handle for the current thread.
249 wapi_create_thread_handle (void)
251 struct _WapiHandle_thread thread_handle = {0}, *thread;
255 mono_once (&thread_hash_once, thread_hash_init);
256 mono_once (&thread_ops_once, thread_ops_init);
258 thread_handle.state = THREAD_STATE_START;
259 thread_handle.owned_mutexes = g_ptr_array_new ();
261 handle = _wapi_handle_new (WAPI_HANDLE_THREAD, &thread_handle);
262 if (handle == _WAPI_HANDLE_INVALID) {
263 g_warning ("%s: error creating thread handle", __func__);
264 SetLastError (ERROR_GEN_FAILURE);
269 res = _wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
270 (gpointer *)&thread);
273 thread->handle = handle;
275 res = pthread_setspecific (thread_hash_key, handle);
277 mono_gc_pthread_exit (NULL);
279 thread->id = pthread_self ();
282 * Hold a reference while the thread is active, because we use
283 * the handle to store thread exit information
285 _wapi_handle_ref (handle);
287 DEBUG ("%s: started thread id %ld", __func__, thread->id);
292 /* The only time this function is called when tid != pthread_self ()
293 * is from OpenThread (), so we can fast-path most cases by just
294 * looking up the handle in TLS. OpenThread () must cope with a NULL
295 * return and do a handle search in that case.
297 gpointer _wapi_thread_handle_from_id (pthread_t tid)
301 if (pthread_equal (tid, pthread_self ()) &&
302 (ret = pthread_getspecific (thread_hash_key)) != NULL) {
303 /* We know the handle */
305 DEBUG ("%s: Returning %p for self thread %ld from TLS",
311 DEBUG ("%s: Returning NULL for unknown or non-self thread %ld",
318 static gboolean find_thread_by_id (gpointer handle, gpointer user_data)
320 pthread_t tid = (pthread_t)user_data;
321 struct _WapiHandle_thread *thread_handle;
324 /* Ignore threads that have already exited (ie they are signalled) */
325 if (_wapi_handle_issignalled (handle) == FALSE) {
326 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
327 (gpointer *)&thread_handle);
329 /* It's possible that the handle has vanished
330 * during the _wapi_search_handle before it
331 * gets here, so don't spam the console with
337 DEBUG ("%s: looking at thread %ld from process %d", __func__, thread_handle->id, 0);
339 if (pthread_equal (thread_handle->id, tid)) {
340 DEBUG ("%s: found the thread we are looking for",
346 DEBUG ("%s: not found %ld, returning FALSE", __func__, tid);
351 /* NB tid is 32bit in MS API, but we need 64bit on amd64 and s390x
352 * (and probably others)
354 gpointer OpenThread (guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, gsize tid)
358 mono_once (&thread_hash_once, thread_hash_init);
359 mono_once (&thread_ops_once, thread_ops_init);
361 DEBUG ("%s: looking up thread %"G_GSIZE_FORMAT, __func__, tid);
363 ret = _wapi_thread_handle_from_id ((pthread_t)tid);
365 /* We need to search for this thread */
366 ret = _wapi_search_handle (WAPI_HANDLE_THREAD, find_thread_by_id, (gpointer)tid, NULL, FALSE/*TRUE*/); /* FIXME: have a proper look at this, me might not need to set search_shared = TRUE */
368 /* if _wapi_search_handle() returns a found handle, it
371 _wapi_handle_ref (ret);
374 DEBUG ("%s: returning thread handle %p", __func__, ret);
381 * @exitcode: Sets the thread's exit code, which can be read from
382 * another thread with GetExitCodeThread().
384 * Terminates the calling thread. A thread can also exit by returning
385 * from its start function. When the last thread in a process
386 * terminates, the process itself terminates.
388 void ExitThread(guint32 exitcode)
390 gpointer thread = _wapi_thread_handle_from_id (pthread_self ());
392 if (thread != NULL) {
393 thread_exit(exitcode, thread);
395 /* Just blow this thread away */
396 mono_gc_pthread_exit (NULL);
402 * @handle: The thread handle to query
403 * @exitcode: The thread @handle exit code is stored here
405 * Finds the exit code of @handle, and stores it in @exitcode. If the
406 * thread @handle is still running, the value stored is %STILL_ACTIVE.
408 * Return value: %TRUE, or %FALSE on error.
410 gboolean GetExitCodeThread(gpointer handle, guint32 *exitcode)
412 struct _WapiHandle_thread *thread_handle;
415 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
416 (gpointer *)&thread_handle);
418 g_warning ("%s: error looking up thread handle %p", __func__,
423 DEBUG ("%s: Finding exit status for thread handle %p id %ld",
424 __func__, handle, thread_handle->id);
426 if (exitcode == NULL) {
427 DEBUG ("%s: Nowhere to store exit code", __func__);
431 if (thread_handle->state != THREAD_STATE_EXITED) {
432 DEBUG ("%s: Thread still active (state %d, exited is %d)",
433 __func__, thread_handle->state,
434 THREAD_STATE_EXITED);
435 *exitcode = STILL_ACTIVE;
439 *exitcode = thread_handle->exitstatus;
445 * GetCurrentThreadId:
447 * Looks up the thread ID of the current thread. This ID can be
448 * passed to OpenThread() to create a new handle on this thread.
450 * Return value: the thread ID. NB this is defined as DWORD (ie 32
451 * bit) in the MS API, but we need to cope with 64 bit IDs for s390x
452 * and amd64. This doesn't really break the API, it just embraces and
453 * extends it on 64bit platforms :)
455 gsize GetCurrentThreadId(void)
457 pthread_t tid = pthread_self();
459 #ifdef PTHREAD_POINTER_ID
460 /* Don't use GPOINTER_TO_UINT here, it can't cope with
461 * sizeof(void *) > sizeof(uint) when a cast to uint would
470 static gpointer thread_attach(gsize *tid)
472 struct _WapiHandle_thread thread_handle = {0}, *thread_handle_p;
477 mono_once (&thread_hash_once, thread_hash_init);
478 mono_once (&thread_ops_once, thread_ops_init);
480 thread_handle.state = THREAD_STATE_START;
481 thread_handle.owned_mutexes = g_ptr_array_new ();
483 handle = _wapi_handle_new (WAPI_HANDLE_THREAD, &thread_handle);
484 if (handle == _WAPI_HANDLE_INVALID) {
485 g_warning ("%s: error creating thread handle", __func__);
487 SetLastError (ERROR_GEN_FAILURE);
491 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
493 thr_ret = _wapi_handle_lock_handle (handle);
494 g_assert (thr_ret == 0);
496 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
497 (gpointer *)&thread_handle_p);
499 g_warning ("%s: error looking up thread handle %p", __func__,
502 SetLastError (ERROR_GEN_FAILURE);
506 /* Hold a reference while the thread is active, because we use
507 * the handle to store thread exit information
509 _wapi_handle_ref (handle);
511 thread_handle_p->handle = handle;
512 thread_handle_p->id = pthread_self ();
514 thr_ret = pthread_setspecific (thread_hash_key, (void *)handle);
515 g_assert (thr_ret == 0);
517 thr_ret = pthread_setspecific (thread_attached_key, (void *)handle);
518 g_assert (thr_ret == 0);
520 DEBUG("%s: Attached thread handle %p ID %ld", __func__, handle,
521 thread_handle_p->id);
524 #ifdef PTHREAD_POINTER_ID
525 /* Don't use GPOINTER_TO_UINT here, it can't cope with
526 * sizeof(void *) > sizeof(uint) when a cast to uint
529 *tid = (gsize)(thread_handle_p->id);
531 *tid = thread_handle_p->id;
536 thr_ret = _wapi_handle_unlock_handle (handle);
537 g_assert (thr_ret == 0);
538 pthread_cleanup_pop (0);
543 gpointer _wapi_thread_duplicate ()
547 mono_once (&thread_hash_once, thread_hash_init);
548 mono_once (&thread_ops_once, thread_ops_init);
550 ret = _wapi_thread_handle_from_id (pthread_self ());
552 ret = thread_attach (NULL);
554 _wapi_handle_ref (ret);
563 * Looks up the handle associated with the current thread. Under
564 * Windows this is a pseudohandle, and must be duplicated with
565 * DuplicateHandle() for some operations.
567 * Return value: The current thread handle, or %NULL on failure.
568 * (Unknown whether Windows has a possible failure here. It may be
569 * necessary to implement the pseudohandle-constant behaviour).
571 gpointer GetCurrentThread(void)
573 mono_once(&thread_hash_once, thread_hash_init);
574 mono_once (&thread_ops_once, thread_ops_init);
576 return(_WAPI_THREAD_CURRENT);
581 * @ms: The time in milliseconds to suspend for
582 * @alertable: if TRUE, the wait can be interrupted by an APC call
584 * Suspends execution of the current thread for @ms milliseconds. A
585 * value of zero causes the thread to relinquish its time slice. A
586 * value of %INFINITE causes an infinite delay.
588 guint32 SleepEx(guint32 ms, gboolean alertable)
590 struct timespec req, rem;
593 gpointer current_thread = NULL;
595 DEBUG("%s: Sleeping for %d ms", __func__, ms);
598 current_thread = _wapi_thread_handle_from_id (pthread_self ());
599 if (current_thread == NULL) {
600 SetLastError (ERROR_INVALID_HANDLE);
604 if (_wapi_thread_apc_pending (current_thread)) {
605 _wapi_thread_dispatch_apc_queue (current_thread);
606 return WAIT_IO_COMPLETION;
615 /* FIXME: check for INFINITE and sleep forever */
620 req.tv_nsec=ms_rem*1000000;
623 memset (&rem, 0, sizeof (rem));
624 ret=nanosleep(&req, &rem);
626 if (alertable && _wapi_thread_apc_pending (current_thread)) {
627 _wapi_thread_dispatch_apc_queue (current_thread);
628 return WAIT_IO_COMPLETION;
632 /* Sleep interrupted with rem time remaining */
634 guint32 rems=rem.tv_sec*1000 + rem.tv_nsec/1000000;
636 g_message("%s: Still got %d ms to go", __func__, rems);
645 void Sleep(guint32 ms)
650 gboolean _wapi_thread_cur_apc_pending (void)
652 gpointer thread = _wapi_thread_handle_from_id (pthread_self ());
654 if (thread == NULL) {
655 SetLastError (ERROR_INVALID_HANDLE);
659 return(_wapi_thread_apc_pending (thread));
662 gboolean _wapi_thread_apc_pending (gpointer handle)
664 struct _WapiHandle_thread *thread;
667 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
668 (gpointer *)&thread);
670 /* This might happen at process shutdown, as all
671 * thread handles are forcibly closed. If a thread
672 * still has an alertable wait the final
673 * _wapi_thread_apc_pending check will probably fail
676 DEBUG ("%s: error looking up thread handle %p", __func__,
681 return(thread->has_apc || thread->wait_handle == INTERRUPTION_REQUESTED_HANDLE);
684 gboolean _wapi_thread_dispatch_apc_queue (gpointer handle)
686 /* We don't support calling APC functions */
687 struct _WapiHandle_thread *thread;
690 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
691 (gpointer *)&thread);
694 thread->has_apc = FALSE;
700 * wapi_interrupt_self:
702 * If this function called from a signal handler, and the thread was waiting when receiving
703 * the signal, the wait will be broken after the signal handler returns.
704 * This function is async-signal-safe.
707 wapi_thread_interrupt_self (void)
710 struct _WapiHandle_thread *thread_handle;
713 handle = _wapi_thread_handle_from_id (pthread_self ());
716 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
717 (gpointer *)&thread_handle);
719 g_warning ("%s: error looking up thread handle %p", __func__,
724 /* No locking/memory barriers are needed here */
725 thread_handle->has_apc = TRUE;
729 * wapi_interrupt_thread:
731 * This is not part of the WIN32 API.
732 * The state of the thread handle HANDLE is set to 'interrupted' which means that
733 * if the thread calls one of the WaitFor functions, the function will return with
734 * WAIT_IO_COMPLETION instead of waiting. Also, if the thread was waiting when
735 * this function was called, the wait will be broken.
736 * It is possible that the wait functions return WAIT_IO_COMPLETION, but the
737 * target thread didn't receive the interrupt signal yet, in this case it should
738 * call the wait function again. This essentially means that the target thread will
739 * busy wait until it is ready to process the interruption.
740 * FIXME: get rid of QueueUserAPC and thread->has_apc, SleepEx seems to require it.
742 void wapi_interrupt_thread (gpointer thread_handle)
744 struct _WapiHandle_thread *thread;
746 gpointer prev_handle, wait_handle;
748 pthread_cond_t *cond;
751 ok = _wapi_lookup_handle (thread_handle, WAPI_HANDLE_THREAD,
752 (gpointer *)&thread);
756 wait_handle = thread->wait_handle;
759 * Atomically obtain the handle the thread is waiting on, and
760 * change it to a flag value.
762 prev_handle = InterlockedCompareExchangePointer (&thread->wait_handle,
763 INTERRUPTION_REQUESTED_HANDLE, wait_handle);
764 if (prev_handle == INTERRUPTION_REQUESTED_HANDLE)
765 /* Already interrupted */
767 if (prev_handle == wait_handle)
773 WAIT_DEBUG (printf ("%p: state -> INTERRUPTED.\n", thread->id););
779 /* If we reach here, then wait_handle is set to the flag value,
780 * which means that the target thread is either
781 * - before the first CAS in timedwait, which means it won't enter the
783 * - it is after the first CAS, so it is already waiting, or it will
784 * enter the wait, and it will be interrupted by the broadcast.
786 idx = GPOINTER_TO_UINT(wait_handle);
787 cond = &_WAPI_PRIVATE_HANDLES(idx).signal_cond;
788 mutex = &_WAPI_PRIVATE_HANDLES(idx).signal_mutex;
790 mono_mutex_lock (mutex);
791 mono_cond_broadcast (cond);
792 mono_mutex_unlock (mutex);
794 /* ref added by set_wait_handle */
795 _wapi_handle_unref (wait_handle);
799 gpointer wapi_prepare_interrupt_thread (gpointer thread_handle)
801 struct _WapiHandle_thread *thread;
803 gpointer prev_handle, wait_handle;
805 ok = _wapi_lookup_handle (thread_handle, WAPI_HANDLE_THREAD,
806 (gpointer *)&thread);
810 wait_handle = thread->wait_handle;
813 * Atomically obtain the handle the thread is waiting on, and
814 * change it to a flag value.
816 prev_handle = InterlockedCompareExchangePointer (&thread->wait_handle,
817 INTERRUPTION_REQUESTED_HANDLE, wait_handle);
818 if (prev_handle == INTERRUPTION_REQUESTED_HANDLE)
819 /* Already interrupted */
821 if (prev_handle == wait_handle)
827 WAIT_DEBUG (printf ("%p: state -> INTERRUPTED.\n", thread->id););
832 void wapi_finish_interrupt_thread (gpointer wait_handle)
834 pthread_cond_t *cond;
842 /* If we reach here, then wait_handle is set to the flag value,
843 * which means that the target thread is either
844 * - before the first CAS in timedwait, which means it won't enter the
846 * - it is after the first CAS, so it is already waiting, or it will
847 * enter the wait, and it will be interrupted by the broadcast.
849 idx = GPOINTER_TO_UINT(wait_handle);
850 cond = &_WAPI_PRIVATE_HANDLES(idx).signal_cond;
851 mutex = &_WAPI_PRIVATE_HANDLES(idx).signal_mutex;
853 mono_mutex_lock (mutex);
854 mono_cond_broadcast (cond);
855 mono_mutex_unlock (mutex);
857 /* ref added by set_wait_handle */
858 _wapi_handle_unref (wait_handle);
863 * wapi_self_interrupt:
865 * This is not part of the WIN32 API.
866 * Set the 'interrupted' state of the calling thread if it's NULL.
868 void wapi_self_interrupt (void)
870 struct _WapiHandle_thread *thread;
872 gpointer prev_handle, wait_handle;
873 gpointer thread_handle;
876 thread_handle = OpenThread (0, 0, GetCurrentThreadId ());
877 ok = _wapi_lookup_handle (thread_handle, WAPI_HANDLE_THREAD,
878 (gpointer *)&thread);
882 wait_handle = thread->wait_handle;
885 * Atomically obtain the handle the thread is waiting on, and
886 * change it to a flag value.
888 prev_handle = InterlockedCompareExchangePointer (&thread->wait_handle,
889 INTERRUPTION_REQUESTED_HANDLE, wait_handle);
890 if (prev_handle == INTERRUPTION_REQUESTED_HANDLE)
891 /* Already interrupted */
893 /*We did not get interrupted*/
894 if (prev_handle == wait_handle)
901 /* ref added by set_wait_handle */
902 _wapi_handle_unref (wait_handle);
906 _wapi_handle_unref (thread_handle);
910 * wapi_clear_interruption:
912 * This is not part of the WIN32 API.
913 * Clear the 'interrupted' state of the calling thread.
914 * This function is signal safe
916 void wapi_clear_interruption (void)
918 struct _WapiHandle_thread *thread;
920 gpointer prev_handle;
921 gpointer thread_handle;
923 thread_handle = OpenThread (0, 0, GetCurrentThreadId ());
924 ok = _wapi_lookup_handle (thread_handle, WAPI_HANDLE_THREAD,
925 (gpointer *)&thread);
928 prev_handle = InterlockedCompareExchangePointer (&thread->wait_handle,
929 NULL, INTERRUPTION_REQUESTED_HANDLE);
930 if (prev_handle == INTERRUPTION_REQUESTED_HANDLE)
931 WAIT_DEBUG (printf ("%p: state -> NORMAL.\n", GetCurrentThreadId ()););
933 _wapi_handle_unref (thread_handle);
936 char* wapi_current_thread_desc ()
938 struct _WapiHandle_thread *thread;
942 gpointer thread_handle;
946 thread_handle = OpenThread (0, 0, GetCurrentThreadId ());
947 ok = _wapi_lookup_handle (thread_handle, WAPI_HANDLE_THREAD,
948 (gpointer *)&thread);
950 return g_strdup_printf ("thread handle %p state : lookup failure", thread_handle);
952 handle = thread->wait_handle;
953 text = g_string_new (0);
954 g_string_append_printf (text, "thread handle %p state : ", thread_handle);
957 g_string_append_printf (text, "not waiting");
958 else if (handle == INTERRUPTION_REQUESTED_HANDLE)
959 g_string_append_printf (text, "interrupted state");
961 g_string_append_printf (text, "waiting on %p : %s ", handle, _wapi_handle_typename[_wapi_handle_type (handle)]);
962 g_string_append_printf (text, " owns (");
963 for (i = 0; i < thread->owned_mutexes->len; i++) {
964 gpointer mutex = g_ptr_array_index (thread->owned_mutexes, i);
966 g_string_append_printf (text, ", %p", mutex);
968 g_string_append_printf (text, "%p", mutex);
970 g_string_append_printf (text, ")");
973 g_string_free (text, FALSE);
978 * wapi_thread_set_wait_handle:
980 * Set the wait handle for the current thread to HANDLE. Return TRUE on success, FALSE
981 * if the thread is in interrupted state, and cannot start waiting.
983 gboolean wapi_thread_set_wait_handle (gpointer handle)
985 struct _WapiHandle_thread *thread;
987 gpointer prev_handle;
988 gpointer thread_handle;
990 thread_handle = OpenThread (0, 0, GetCurrentThreadId ());
991 ok = _wapi_lookup_handle (thread_handle, WAPI_HANDLE_THREAD,
992 (gpointer *)&thread);
995 prev_handle = InterlockedCompareExchangePointer (&thread->wait_handle,
997 _wapi_handle_unref (thread_handle);
999 if (prev_handle == NULL) {
1000 /* thread->wait_handle acts as an additional reference to the handle */
1001 _wapi_handle_ref (handle);
1003 WAIT_DEBUG (printf ("%p: state -> WAITING.\n", GetCurrentThreadId ()););
1005 g_assert (prev_handle == INTERRUPTION_REQUESTED_HANDLE);
1006 WAIT_DEBUG (printf ("%p: unable to set state to WAITING.\n", GetCurrentThreadId ()););
1009 return prev_handle == NULL;
1013 * wapi_thread_clear_wait_handle:
1015 * Clear the wait handle of the current thread.
1017 void wapi_thread_clear_wait_handle (gpointer handle)
1019 struct _WapiHandle_thread *thread;
1021 gpointer prev_handle;
1022 gpointer thread_handle;
1024 thread_handle = OpenThread (0, 0, GetCurrentThreadId ());
1025 ok = _wapi_lookup_handle (thread_handle, WAPI_HANDLE_THREAD,
1026 (gpointer *)&thread);
1029 prev_handle = InterlockedCompareExchangePointer (&thread->wait_handle,
1032 if (prev_handle == handle) {
1033 _wapi_handle_unref (handle);
1034 WAIT_DEBUG (printf ("%p: state -> NORMAL.\n", GetCurrentThreadId ()););
1036 /*It can be NULL if it was asynchronously cleared*/
1037 g_assert (prev_handle == INTERRUPTION_REQUESTED_HANDLE || prev_handle == NULL);
1038 WAIT_DEBUG (printf ("%p: finished waiting.\n", GetCurrentThreadId ()););
1041 _wapi_handle_unref (thread_handle);
1044 void _wapi_thread_own_mutex (gpointer mutex)
1046 struct _WapiHandle_thread *thread_handle;
1050 thread = _wapi_thread_handle_from_id (pthread_self ());
1051 if (thread == NULL) {
1052 g_warning ("%s: error looking up thread by ID", __func__);
1056 ok = _wapi_lookup_handle (thread, WAPI_HANDLE_THREAD,
1057 (gpointer *)&thread_handle);
1059 g_warning ("%s: error looking up thread handle %p", __func__,
1064 _wapi_handle_ref (mutex);
1066 g_ptr_array_add (thread_handle->owned_mutexes, mutex);
1069 void _wapi_thread_disown_mutex (gpointer mutex)
1071 struct _WapiHandle_thread *thread_handle;
1075 thread = _wapi_thread_handle_from_id (pthread_self ());
1076 if (thread == NULL) {
1077 g_warning ("%s: error looking up thread by ID", __func__);
1081 ok = _wapi_lookup_handle (thread, WAPI_HANDLE_THREAD,
1082 (gpointer *)&thread_handle);
1084 g_warning ("%s: error looking up thread handle %p", __func__,
1089 _wapi_handle_unref (mutex);
1091 g_ptr_array_remove (thread_handle->owned_mutexes, mutex);