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/mono-mutex.h>
29 #include <mono/io-layer/thread-private.h>
30 #include <mono/io-layer/mutex-private.h>
31 #include <mono/io-layer/atomic.h>
33 #include <mono/utils/mono-threads.h>
34 #include <mono/utils/gc_wrapper.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 MONO_SEM_DESTROY (&thread_handle->suspend_sem);
169 g_ptr_array_free (thread_handle->owned_mutexes, TRUE);
171 _wapi_handle_set_signal_state (handle, TRUE, TRUE);
173 thr_ret = _wapi_handle_unlock_handle (handle);
174 g_assert (thr_ret == 0);
175 pthread_cleanup_pop (0);
177 DEBUG("%s: Recording thread handle %p id %ld status as %d",
178 __func__, handle, thread_handle->id, exitstatus);
180 /* The thread is no longer active, so unref it */
181 _wapi_handle_unref (handle);
184 void _wapi_thread_signal_self (guint32 exitstatus)
188 handle = _wapi_thread_handle_from_id (pthread_self ());
189 if (handle == NULL) {
190 /* Something gone badly wrong... */
194 _wapi_thread_set_termination_details (handle, exitstatus);
197 /* Called by the thread creation code as a thread is finishing up, and
200 static void thread_exit (guint32 exitstatus, gpointer handle) G_GNUC_NORETURN;
201 static void thread_exit (guint32 exitstatus, gpointer handle)
203 _wapi_thread_set_termination_details (handle, exitstatus);
205 /* Call pthread_exit() to call destructors and really exit the
208 mono_gc_pthread_exit (NULL);
211 static void thread_attached_exit (gpointer handle)
213 /* Drop the extra reference we take in thread_attach, now this
217 _wapi_thread_set_termination_details (handle, 0);
220 static void thread_hash_init(void)
224 thr_ret = pthread_key_create (&thread_hash_key, NULL);
225 g_assert (thr_ret == 0);
227 thr_ret = pthread_key_create (&thread_attached_key,
228 thread_attached_exit);
229 g_assert (thr_ret == 0);
232 static void _wapi_thread_suspend (struct _WapiHandle_thread *thread)
234 g_assert (pthread_equal (thread->id, pthread_self ()));
236 while (MONO_SEM_WAIT (&thread->suspend_sem) != 0 &&
240 static void _wapi_thread_resume (struct _WapiHandle_thread *thread)
242 MONO_SEM_POST (&thread->suspend_sem);
245 static void *thread_start_routine (gpointer args) G_GNUC_NORETURN;
246 static void *thread_start_routine (gpointer args)
248 struct _WapiHandle_thread *thread = (struct _WapiHandle_thread *)args;
251 thr_ret = mono_gc_pthread_detach (pthread_self ());
252 g_assert (thr_ret == 0);
254 thr_ret = pthread_setspecific (thread_hash_key,
255 (void *)thread->handle);
257 /* This is only supposed to happen when Mono is
258 shutting down. We cannot assert on it, though,
259 because we must not depend on metadata, which is
260 where the shutdown code is.
262 This is a race condition which arises because
263 pthreads don't allow creation of suspended threads.
264 Once Mono is set to shut down no new thread is
265 allowed to start, even though threads may still be
266 created. We emulate suspended threads in this
267 function by calling _wapi_thread_suspend() below.
269 So it can happen that even though Mono is already
270 shutting down we still end up here, and at this
271 point the thread_hash_key might already be
273 mono_gc_pthread_exit (NULL);
276 DEBUG ("%s: started thread id %ld", __func__, thread->id);
278 /* We set it again here since passing &thread->id to pthread_create is racy
279 as the thread can start running before the value is set.*/
280 thread->id = pthread_self ();
282 if (thread->create_flags & CREATE_SUSPENDED) {
283 _wapi_thread_suspend (thread);
286 thread_exit (thread->start_routine (thread->start_arg),
290 /* Even though we tell gcc that this function doesn't return,
291 * other compilers won't see that.
299 * @security: Ignored for now.
300 * @stacksize: the size in bytes of the new thread's stack. Use 0 to
301 * default to the normal stack size. (Ignored for now).
302 * @start: The function that the new thread should start with
303 * @param: The parameter to give to @start.
304 * @create: If 0, the new thread is ready to run immediately. If
305 * %CREATE_SUSPENDED, the new thread will be in the suspended state,
306 * requiring a ResumeThread() call to continue running.
307 * @tid: If non-NULL, the ID of the new thread is stored here. NB
308 * this is defined as a DWORD (ie 32bit) in the MS API, but we need to
309 * cope with 64 bit IDs for s390x and amd64.
311 * Creates a new threading handle.
313 * Return value: a new handle, or NULL
315 gpointer CreateThread(WapiSecurityAttributes *security G_GNUC_UNUSED, guint32 stacksize,
316 WapiThreadStart start, gpointer param, guint32 create,
319 struct _WapiHandle_thread thread_handle = {0}, *thread_handle_p;
326 gpointer ct_ret = NULL;
328 mono_once (&thread_hash_once, thread_hash_init);
329 mono_once (&thread_ops_once, thread_ops_init);
335 thread_handle.state = THREAD_STATE_START;
336 thread_handle.owned_mutexes = g_ptr_array_new ();
337 thread_handle.create_flags = create;
338 thread_handle.start_routine = start;
339 thread_handle.start_arg = param;
341 handle = _wapi_handle_new (WAPI_HANDLE_THREAD, &thread_handle);
342 if (handle == _WAPI_HANDLE_INVALID) {
343 g_warning ("%s: error creating thread handle", __func__);
344 SetLastError (ERROR_GEN_FAILURE);
349 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
351 thr_ret = _wapi_handle_lock_handle (handle);
352 g_assert (thr_ret == 0);
354 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
355 (gpointer *)&thread_handle_p);
357 g_warning ("%s: error looking up thread handle %p", __func__,
359 SetLastError (ERROR_GEN_FAILURE);
364 /* Hold a reference while the thread is active, because we use
365 * the handle to store thread exit information
367 _wapi_handle_ref (handle);
369 /* Set a 2M stack size. This is the default on Linux, but BSD
370 * needs it. (The original bug report from Martin Dvorak <md@9ll.cz>
371 * set the size to 2M-4k. I don't know why it's short by 4k, so
372 * I'm leaving it as 2M until I'm told differently.)
374 thr_ret = pthread_attr_init(&attr);
375 g_assert (thr_ret == 0);
377 /* defaults of 2Mb for 32bits and 4Mb for 64bits */
378 /* temporarily changed to use 1 MB: this allows more threads
379 * to be used, as well as using less virtual memory and so
380 * more is available for the GC heap.
383 #if HAVE_VALGRIND_MEMCHECK_H
384 if (RUNNING_ON_VALGRIND) {
387 stacksize = (SIZEOF_VOID_P / 4) * 1024 * 1024;
390 stacksize = (SIZEOF_VOID_P / 4) * 1024 * 1024;
394 #ifdef PTHREAD_STACK_MIN
395 if (stacksize < PTHREAD_STACK_MIN)
396 stacksize = PTHREAD_STACK_MIN;
399 #ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE
400 thr_ret = pthread_attr_setstacksize(&attr, stacksize);
401 g_assert (thr_ret == 0);
404 MONO_SEM_INIT (&thread_handle_p->suspend_sem, 0);
405 thread_handle_p->handle = handle;
408 ret = mono_threads_pthread_create (&thread_handle_p->id, &attr,
409 thread_start_routine, (void *)thread_handle_p);
412 g_warning ("%s: Error creating native thread handle %s (%d)", __func__,
413 strerror (ret), ret);
414 SetLastError (ERROR_GEN_FAILURE);
416 /* Two, because of the reference we took above */
423 DEBUG("%s: Started thread handle %p ID %ld", __func__, handle,
424 thread_handle_p->id);
427 #ifdef PTHREAD_POINTER_ID
428 /* Don't use GPOINTER_TO_UINT here, it can't cope with
429 * sizeof(void *) > sizeof(uint) when a cast to uint
432 *tid = (gsize)(thread_handle_p->id);
434 *tid = thread_handle_p->id;
439 thr_ret = _wapi_handle_unlock_handle (handle);
440 g_assert (thr_ret == 0);
441 pthread_cleanup_pop (0);
443 /* Must not call _wapi_handle_unref() with the shared handles
446 for (i = 0; i < unrefs; i++) {
447 _wapi_handle_unref (handle);
453 /* The only time this function is called when tid != pthread_self ()
454 * is from OpenThread (), so we can fast-path most cases by just
455 * looking up the handle in TLS. OpenThread () must cope with a NULL
456 * return and do a handle search in that case.
458 gpointer _wapi_thread_handle_from_id (pthread_t tid)
462 if (pthread_equal (tid, pthread_self ()) &&
463 (ret = pthread_getspecific (thread_hash_key)) != NULL) {
464 /* We know the handle */
466 DEBUG ("%s: Returning %p for self thread %ld from TLS",
472 DEBUG ("%s: Returning NULL for unknown or non-self thread %ld",
479 static gboolean find_thread_by_id (gpointer handle, gpointer user_data)
481 pthread_t tid = (pthread_t)user_data;
482 struct _WapiHandle_thread *thread_handle;
485 /* Ignore threads that have already exited (ie they are signalled) */
486 if (_wapi_handle_issignalled (handle) == FALSE) {
487 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
488 (gpointer *)&thread_handle);
490 /* It's possible that the handle has vanished
491 * during the _wapi_search_handle before it
492 * gets here, so don't spam the console with
498 DEBUG ("%s: looking at thread %ld from process %d", __func__, thread_handle->id, 0);
500 if (pthread_equal (thread_handle->id, tid)) {
501 DEBUG ("%s: found the thread we are looking for",
507 DEBUG ("%s: not found %ld, returning FALSE", __func__, tid);
512 /* NB tid is 32bit in MS API, but we need 64bit on amd64 and s390x
513 * (and probably others)
515 gpointer OpenThread (guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, gsize tid)
519 mono_once (&thread_hash_once, thread_hash_init);
520 mono_once (&thread_ops_once, thread_ops_init);
522 DEBUG ("%s: looking up thread %"G_GSIZE_FORMAT, __func__, tid);
524 ret = _wapi_thread_handle_from_id ((pthread_t)tid);
526 /* We need to search for this thread */
527 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 */
529 /* if _wapi_search_handle() returns a found handle, it
532 _wapi_handle_ref (ret);
535 DEBUG ("%s: returning thread handle %p", __func__, ret);
542 * @exitcode: Sets the thread's exit code, which can be read from
543 * another thread with GetExitCodeThread().
545 * Terminates the calling thread. A thread can also exit by returning
546 * from its start function. When the last thread in a process
547 * terminates, the process itself terminates.
549 void ExitThread(guint32 exitcode)
551 gpointer thread = _wapi_thread_handle_from_id (pthread_self ());
553 if (thread != NULL) {
554 thread_exit(exitcode, thread);
556 /* Just blow this thread away */
557 mono_gc_pthread_exit (NULL);
563 * @handle: The thread handle to query
564 * @exitcode: The thread @handle exit code is stored here
566 * Finds the exit code of @handle, and stores it in @exitcode. If the
567 * thread @handle is still running, the value stored is %STILL_ACTIVE.
569 * Return value: %TRUE, or %FALSE on error.
571 gboolean GetExitCodeThread(gpointer handle, guint32 *exitcode)
573 struct _WapiHandle_thread *thread_handle;
576 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
577 (gpointer *)&thread_handle);
579 g_warning ("%s: error looking up thread handle %p", __func__,
584 DEBUG ("%s: Finding exit status for thread handle %p id %ld",
585 __func__, handle, thread_handle->id);
587 if (exitcode == NULL) {
588 DEBUG ("%s: Nowhere to store exit code", __func__);
592 if (thread_handle->state != THREAD_STATE_EXITED) {
593 DEBUG ("%s: Thread still active (state %d, exited is %d)",
594 __func__, thread_handle->state,
595 THREAD_STATE_EXITED);
596 *exitcode = STILL_ACTIVE;
600 *exitcode = thread_handle->exitstatus;
606 * GetCurrentThreadId:
608 * Looks up the thread ID of the current thread. This ID can be
609 * passed to OpenThread() to create a new handle on this thread.
611 * Return value: the thread ID. NB this is defined as DWORD (ie 32
612 * bit) in the MS API, but we need to cope with 64 bit IDs for s390x
613 * and amd64. This doesn't really break the API, it just embraces and
614 * extends it on 64bit platforms :)
616 gsize GetCurrentThreadId(void)
618 pthread_t tid = pthread_self();
620 #ifdef PTHREAD_POINTER_ID
621 /* Don't use GPOINTER_TO_UINT here, it can't cope with
622 * sizeof(void *) > sizeof(uint) when a cast to uint would
631 static gpointer thread_attach(gsize *tid)
633 struct _WapiHandle_thread thread_handle = {0}, *thread_handle_p;
638 mono_once (&thread_hash_once, thread_hash_init);
639 mono_once (&thread_ops_once, thread_ops_init);
641 thread_handle.state = THREAD_STATE_START;
642 thread_handle.owned_mutexes = g_ptr_array_new ();
644 handle = _wapi_handle_new (WAPI_HANDLE_THREAD, &thread_handle);
645 if (handle == _WAPI_HANDLE_INVALID) {
646 g_warning ("%s: error creating thread handle", __func__);
648 SetLastError (ERROR_GEN_FAILURE);
652 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
654 thr_ret = _wapi_handle_lock_handle (handle);
655 g_assert (thr_ret == 0);
657 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
658 (gpointer *)&thread_handle_p);
660 g_warning ("%s: error looking up thread handle %p", __func__,
663 SetLastError (ERROR_GEN_FAILURE);
667 /* Hold a reference while the thread is active, because we use
668 * the handle to store thread exit information
670 _wapi_handle_ref (handle);
672 /* suspend_sem is not used for attached threads, but
673 * thread_exit() might try to destroy it
675 MONO_SEM_INIT (&thread_handle_p->suspend_sem, 0);
676 thread_handle_p->handle = handle;
677 thread_handle_p->id = pthread_self ();
679 thr_ret = pthread_setspecific (thread_hash_key, (void *)handle);
680 g_assert (thr_ret == 0);
682 thr_ret = pthread_setspecific (thread_attached_key, (void *)handle);
683 g_assert (thr_ret == 0);
685 DEBUG("%s: Attached thread handle %p ID %ld", __func__, handle,
686 thread_handle_p->id);
689 #ifdef PTHREAD_POINTER_ID
690 /* Don't use GPOINTER_TO_UINT here, it can't cope with
691 * sizeof(void *) > sizeof(uint) when a cast to uint
694 *tid = (gsize)(thread_handle_p->id);
696 *tid = thread_handle_p->id;
701 thr_ret = _wapi_handle_unlock_handle (handle);
702 g_assert (thr_ret == 0);
703 pthread_cleanup_pop (0);
708 gpointer _wapi_thread_duplicate ()
712 mono_once (&thread_hash_once, thread_hash_init);
713 mono_once (&thread_ops_once, thread_ops_init);
715 ret = _wapi_thread_handle_from_id (pthread_self ());
717 ret = thread_attach (NULL);
719 _wapi_handle_ref (ret);
728 * Looks up the handle associated with the current thread. Under
729 * Windows this is a pseudohandle, and must be duplicated with
730 * DuplicateHandle() for some operations.
732 * Return value: The current thread handle, or %NULL on failure.
733 * (Unknown whether Windows has a possible failure here. It may be
734 * necessary to implement the pseudohandle-constant behaviour).
736 gpointer GetCurrentThread(void)
738 mono_once(&thread_hash_once, thread_hash_init);
739 mono_once (&thread_ops_once, thread_ops_init);
741 return(_WAPI_THREAD_CURRENT);
746 * @handle: the thread handle to resume
748 * Decrements the suspend count of thread @handle. A thread can only
749 * run if its suspend count is zero.
751 * Return value: the previous suspend count, or 0xFFFFFFFF on error.
753 guint32 ResumeThread(gpointer handle)
755 struct _WapiHandle_thread *thread_handle;
758 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
759 (gpointer *)&thread_handle);
761 g_warning ("%s: error looking up thread handle %p", __func__,
767 /* This is still a kludge that only copes with starting a
768 * thread that was suspended on create, so don't bother with
769 * the suspend count crap yet
771 _wapi_thread_resume (thread_handle);
777 * @handle: the thread handle to suspend
779 * Increments the suspend count of thread @handle. A thread can only
780 * run if its suspend count is zero.
782 * Return value: the previous suspend count, or 0xFFFFFFFF on error.
784 guint32 SuspendThread(gpointer handle)
791 * @ms: The time in milliseconds to suspend for
792 * @alertable: if TRUE, the wait can be interrupted by an APC call
794 * Suspends execution of the current thread for @ms milliseconds. A
795 * value of zero causes the thread to relinquish its time slice. A
796 * value of %INFINITE causes an infinite delay.
798 guint32 SleepEx(guint32 ms, gboolean alertable)
800 struct timespec req, rem;
803 gpointer current_thread = NULL;
805 DEBUG("%s: Sleeping for %d ms", __func__, ms);
808 current_thread = _wapi_thread_handle_from_id (pthread_self ());
809 if (current_thread == NULL) {
810 SetLastError (ERROR_INVALID_HANDLE);
814 if (_wapi_thread_apc_pending (current_thread)) {
815 _wapi_thread_dispatch_apc_queue (current_thread);
816 return WAIT_IO_COMPLETION;
825 /* FIXME: check for INFINITE and sleep forever */
830 req.tv_nsec=ms_rem*1000000;
833 memset (&rem, 0, sizeof (rem));
834 ret=nanosleep(&req, &rem);
836 if (alertable && _wapi_thread_apc_pending (current_thread)) {
837 _wapi_thread_dispatch_apc_queue (current_thread);
838 return WAIT_IO_COMPLETION;
842 /* Sleep interrupted with rem time remaining */
844 guint32 rems=rem.tv_sec*1000 + rem.tv_nsec/1000000;
846 g_message("%s: Still got %d ms to go", __func__, rems);
855 void Sleep(guint32 ms)
860 gboolean _wapi_thread_cur_apc_pending (void)
862 gpointer thread = _wapi_thread_handle_from_id (pthread_self ());
864 if (thread == NULL) {
865 SetLastError (ERROR_INVALID_HANDLE);
869 return(_wapi_thread_apc_pending (thread));
872 gboolean _wapi_thread_apc_pending (gpointer handle)
874 struct _WapiHandle_thread *thread;
877 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
878 (gpointer *)&thread);
880 /* This might happen at process shutdown, as all
881 * thread handles are forcibly closed. If a thread
882 * still has an alertable wait the final
883 * _wapi_thread_apc_pending check will probably fail
886 DEBUG ("%s: error looking up thread handle %p", __func__,
891 return(thread->has_apc || thread->wait_handle == INTERRUPTION_REQUESTED_HANDLE);
894 gboolean _wapi_thread_dispatch_apc_queue (gpointer handle)
896 /* We don't support calling APC functions */
897 struct _WapiHandle_thread *thread;
900 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
901 (gpointer *)&thread);
904 thread->has_apc = FALSE;
910 * In this implementation, APC_CALLBACK is ignored.
911 * if HANDLE refers to the current thread, the only effect this function has
912 * that if called from a signal handler, and the thread was waiting when receiving
913 * the signal, the wait will be broken after the signal handler returns.
914 * In this case, this function is async-signal-safe.
916 guint32 QueueUserAPC (WapiApcProc apc_callback, gpointer handle,
919 struct _WapiHandle_thread *thread_handle;
922 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
923 (gpointer *)&thread_handle);
925 g_warning ("%s: error looking up thread handle %p", __func__,
930 g_assert (thread_handle->id == GetCurrentThreadId ());
931 /* No locking/memory barriers are needed here */
932 thread_handle->has_apc = TRUE;
937 * wapi_interrupt_thread:
939 * This is not part of the WIN32 API.
940 * The state of the thread handle HANDLE is set to 'interrupted' which means that
941 * if the thread calls one of the WaitFor functions, the function will return with
942 * WAIT_IO_COMPLETION instead of waiting. Also, if the thread was waiting when
943 * this function was called, the wait will be broken.
944 * It is possible that the wait functions return WAIT_IO_COMPLETION, but the
945 * target thread didn't receive the interrupt signal yet, in this case it should
946 * call the wait function again. This essentially means that the target thread will
947 * busy wait until it is ready to process the interruption.
948 * FIXME: get rid of QueueUserAPC and thread->has_apc, SleepEx seems to require it.
950 void wapi_interrupt_thread (gpointer thread_handle)
952 struct _WapiHandle_thread *thread;
954 gpointer prev_handle, wait_handle;
956 pthread_cond_t *cond;
959 ok = _wapi_lookup_handle (thread_handle, WAPI_HANDLE_THREAD,
960 (gpointer *)&thread);
964 wait_handle = thread->wait_handle;
967 * Atomically obtain the handle the thread is waiting on, and
968 * change it to a flag value.
970 prev_handle = InterlockedCompareExchangePointer (&thread->wait_handle,
971 INTERRUPTION_REQUESTED_HANDLE, wait_handle);
972 if (prev_handle == INTERRUPTION_REQUESTED_HANDLE)
973 /* Already interrupted */
975 if (prev_handle == wait_handle)
981 WAIT_DEBUG (printf ("%p: state -> INTERRUPTED.\n", thread_handle->id););
987 /* If we reach here, then wait_handle is set to the flag value,
988 * which means that the target thread is either
989 * - before the first CAS in timedwait, which means it won't enter the
991 * - it is after the first CAS, so it is already waiting, or it will
992 * enter the wait, and it will be interrupted by the broadcast.
994 idx = GPOINTER_TO_UINT(wait_handle);
995 cond = &_WAPI_PRIVATE_HANDLES(idx).signal_cond;
996 mutex = &_WAPI_PRIVATE_HANDLES(idx).signal_mutex;
998 mono_mutex_lock (mutex);
999 mono_cond_broadcast (cond);
1000 mono_mutex_unlock (mutex);
1002 /* ref added by set_wait_handle */
1003 _wapi_handle_unref (wait_handle);
1007 gpointer wapi_prepare_interrupt_thread (gpointer thread_handle)
1009 struct _WapiHandle_thread *thread;
1011 gpointer prev_handle, wait_handle;
1013 ok = _wapi_lookup_handle (thread_handle, WAPI_HANDLE_THREAD,
1014 (gpointer *)&thread);
1018 wait_handle = thread->wait_handle;
1021 * Atomically obtain the handle the thread is waiting on, and
1022 * change it to a flag value.
1024 prev_handle = InterlockedCompareExchangePointer (&thread->wait_handle,
1025 INTERRUPTION_REQUESTED_HANDLE, wait_handle);
1026 if (prev_handle == INTERRUPTION_REQUESTED_HANDLE)
1027 /* Already interrupted */
1029 if (prev_handle == wait_handle)
1035 WAIT_DEBUG (printf ("%p: state -> INTERRUPTED.\n", thread_handle->id););
1040 void wapi_finish_interrupt_thread (gpointer wait_handle)
1042 pthread_cond_t *cond;
1043 mono_mutex_t *mutex;
1050 /* If we reach here, then wait_handle is set to the flag value,
1051 * which means that the target thread is either
1052 * - before the first CAS in timedwait, which means it won't enter the
1054 * - it is after the first CAS, so it is already waiting, or it will
1055 * enter the wait, and it will be interrupted by the broadcast.
1057 idx = GPOINTER_TO_UINT(wait_handle);
1058 cond = &_WAPI_PRIVATE_HANDLES(idx).signal_cond;
1059 mutex = &_WAPI_PRIVATE_HANDLES(idx).signal_mutex;
1061 mono_mutex_lock (mutex);
1062 mono_cond_broadcast (cond);
1063 mono_mutex_unlock (mutex);
1065 /* ref added by set_wait_handle */
1066 _wapi_handle_unref (wait_handle);
1071 * wapi_self_interrupt:
1073 * This is not part of the WIN32 API.
1074 * Set the 'interrupted' state of the calling thread if it's NULL.
1076 void wapi_self_interrupt (void)
1078 struct _WapiHandle_thread *thread;
1080 gpointer prev_handle, wait_handle;
1081 gpointer thread_handle;
1084 thread_handle = OpenThread (0, 0, GetCurrentThreadId ());
1085 ok = _wapi_lookup_handle (thread_handle, WAPI_HANDLE_THREAD,
1086 (gpointer *)&thread);
1090 wait_handle = thread->wait_handle;
1093 * Atomically obtain the handle the thread is waiting on, and
1094 * change it to a flag value.
1096 prev_handle = InterlockedCompareExchangePointer (&thread->wait_handle,
1097 INTERRUPTION_REQUESTED_HANDLE, wait_handle);
1098 if (prev_handle == INTERRUPTION_REQUESTED_HANDLE)
1099 /* Already interrupted */
1101 /*We did not get interrupted*/
1102 if (prev_handle == wait_handle)
1109 /* ref added by set_wait_handle */
1110 _wapi_handle_unref (wait_handle);
1114 _wapi_handle_unref (thread_handle);
1118 * wapi_clear_interruption:
1120 * This is not part of the WIN32 API.
1121 * Clear the 'interrupted' state of the calling thread.
1122 * This function is signal safe
1124 void wapi_clear_interruption (void)
1126 struct _WapiHandle_thread *thread;
1128 gpointer prev_handle;
1129 gpointer thread_handle;
1131 thread_handle = OpenThread (0, 0, GetCurrentThreadId ());
1132 ok = _wapi_lookup_handle (thread_handle, WAPI_HANDLE_THREAD,
1133 (gpointer *)&thread);
1136 prev_handle = InterlockedCompareExchangePointer (&thread->wait_handle,
1137 NULL, INTERRUPTION_REQUESTED_HANDLE);
1138 if (prev_handle == INTERRUPTION_REQUESTED_HANDLE)
1139 WAIT_DEBUG (printf ("%p: state -> NORMAL.\n", GetCurrentThreadId ()););
1141 _wapi_handle_unref (thread_handle);
1144 char* wapi_current_thread_desc ()
1146 struct _WapiHandle_thread *thread;
1150 gpointer thread_handle;
1154 thread_handle = OpenThread (0, 0, GetCurrentThreadId ());
1155 ok = _wapi_lookup_handle (thread_handle, WAPI_HANDLE_THREAD,
1156 (gpointer *)&thread);
1158 return g_strdup_printf ("thread handle %p state : lookup failure", thread_handle);
1160 handle = thread->wait_handle;
1161 text = g_string_new (0);
1162 g_string_append_printf (text, "thread handle %p state : ", thread_handle);
1165 g_string_append_printf (text, "not waiting");
1166 else if (handle == INTERRUPTION_REQUESTED_HANDLE)
1167 g_string_append_printf (text, "interrupted state");
1169 g_string_append_printf (text, "waiting on %p : %s ", handle, _wapi_handle_typename[_wapi_handle_type (handle)]);
1170 g_string_append_printf (text, " owns (");
1171 for (i = 0; i < thread->owned_mutexes->len; i++) {
1172 gpointer mutex = g_ptr_array_index (thread->owned_mutexes, i);
1174 g_string_append_printf (text, ", %p", mutex);
1176 g_string_append_printf (text, "%p", mutex);
1178 g_string_append_printf (text, ")");
1181 g_string_free (text, FALSE);
1186 * wapi_thread_set_wait_handle:
1188 * Set the wait handle for the current thread to HANDLE. Return TRUE on success, FALSE
1189 * if the thread is in interrupted state, and cannot start waiting.
1191 gboolean wapi_thread_set_wait_handle (gpointer handle)
1193 struct _WapiHandle_thread *thread;
1195 gpointer prev_handle;
1196 gpointer thread_handle;
1198 thread_handle = OpenThread (0, 0, GetCurrentThreadId ());
1199 ok = _wapi_lookup_handle (thread_handle, WAPI_HANDLE_THREAD,
1200 (gpointer *)&thread);
1203 prev_handle = InterlockedCompareExchangePointer (&thread->wait_handle,
1205 _wapi_handle_unref (thread_handle);
1207 if (prev_handle == NULL) {
1208 /* thread->wait_handle acts as an additional reference to the handle */
1209 _wapi_handle_ref (handle);
1211 WAIT_DEBUG (printf ("%p: state -> WAITING.\n", GetCurrentThreadId ()););
1213 g_assert (prev_handle == INTERRUPTION_REQUESTED_HANDLE);
1214 WAIT_DEBUG (printf ("%p: unable to set state to WAITING.\n", GetCurrentThreadId ()););
1217 return prev_handle == NULL;
1221 * wapi_thread_clear_wait_handle:
1223 * Clear the wait handle of the current thread.
1225 void wapi_thread_clear_wait_handle (gpointer handle)
1227 struct _WapiHandle_thread *thread;
1229 gpointer prev_handle;
1230 gpointer thread_handle;
1232 thread_handle = OpenThread (0, 0, GetCurrentThreadId ());
1233 ok = _wapi_lookup_handle (thread_handle, WAPI_HANDLE_THREAD,
1234 (gpointer *)&thread);
1237 prev_handle = InterlockedCompareExchangePointer (&thread->wait_handle,
1240 if (prev_handle == handle) {
1241 _wapi_handle_unref (handle);
1242 WAIT_DEBUG (printf ("%p: state -> NORMAL.\n", GetCurrentThreadId ()););
1244 /*It can be NULL if it was asynchronously cleared*/
1245 g_assert (prev_handle == INTERRUPTION_REQUESTED_HANDLE || prev_handle == NULL);
1246 WAIT_DEBUG (printf ("%p: finished waiting.\n", GetCurrentThreadId ()););
1249 _wapi_handle_unref (thread_handle);
1252 void _wapi_thread_own_mutex (gpointer mutex)
1254 struct _WapiHandle_thread *thread_handle;
1258 thread = _wapi_thread_handle_from_id (pthread_self ());
1259 if (thread == NULL) {
1260 g_warning ("%s: error looking up thread by ID", __func__);
1264 ok = _wapi_lookup_handle (thread, WAPI_HANDLE_THREAD,
1265 (gpointer *)&thread_handle);
1267 g_warning ("%s: error looking up thread handle %p", __func__,
1272 _wapi_handle_ref (mutex);
1274 g_ptr_array_add (thread_handle->owned_mutexes, mutex);
1277 void _wapi_thread_disown_mutex (gpointer mutex)
1279 struct _WapiHandle_thread *thread_handle;
1283 thread = _wapi_thread_handle_from_id (pthread_self ());
1284 if (thread == NULL) {
1285 g_warning ("%s: error looking up thread by ID", __func__);
1289 ok = _wapi_lookup_handle (thread, WAPI_HANDLE_THREAD,
1290 (gpointer *)&thread_handle);
1292 g_warning ("%s: error looking up thread handle %p", __func__,
1297 _wapi_handle_unref (mutex);
1299 g_ptr_array_remove (thread_handle->owned_mutexes, mutex);