2 * threads.c: Thread handles
5 * Dick Porter (dick@ximian.com)
7 * (C) 2002-2006 Ximian, Inc.
14 #include <mono/os/gc_wrapper.h>
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/mono-mutex.h>
28 #include <mono/io-layer/thread-private.h>
29 #include <mono/io-layer/mono-spinlock.h>
30 #include <mono/io-layer/mutex-private.h>
32 #if HAVE_VALGRIND_MEMCHECK_H
33 #include <valgrind/memcheck.h>
39 /* Hash threads with tids. I thought of using TLS for this, but that
40 * would have to set the data in the new thread, which is more hassle
42 static mono_once_t thread_hash_once = MONO_ONCE_INIT;
43 static pthread_key_t thread_hash_key;
45 /* This key is used with attached threads and a destructor to signal
46 * when attached threads exit, as they don't have the thread_exit()
49 static pthread_key_t thread_attached_key;
51 struct _WapiHandleOps _wapi_thread_ops = {
56 NULL, /* special_wait */
60 static mono_once_t thread_ops_once=MONO_ONCE_INIT;
62 static void thread_ops_init (void)
64 _wapi_handle_register_capabilities (WAPI_HANDLE_THREAD,
65 WAPI_HANDLE_CAP_WAIT);
68 /* Called by thread_exit(), but maybe indirectly by
69 * mono_thread_manage() via mono_thread_signal_self() too
71 static void _wapi_thread_abandon_mutexes (gpointer handle)
73 struct _WapiHandle_thread *thread_handle;
76 pid_t pid = _wapi_getpid ();
77 pthread_t tid = pthread_self ();
80 g_message ("%s: Thread %p abandoning held mutexes", __func__, handle);
84 handle = _wapi_thread_handle_from_id (pthread_self ());
86 /* Something gone badly wrong... */
91 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
92 (gpointer *)&thread_handle);
94 g_warning ("%s: error looking up thread handle %p", __func__,
99 if (thread_handle->owner_pid != pid ||
100 !pthread_equal (thread_handle->id, tid)) {
104 for (i = 0; i < thread_handle->owned_mutexes->len; i++) {
105 gpointer mutex = g_ptr_array_index (thread_handle->owned_mutexes, i);
107 _wapi_mutex_abandon (mutex, pid, tid);
108 _wapi_thread_disown_mutex (mutex);
112 void _wapi_thread_set_termination_details (gpointer handle,
115 struct _WapiHandle_thread *thread_handle;
119 if (_wapi_handle_issignalled (handle) ||
120 _wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) {
121 /* We must have already deliberately finished with
122 * this thread, so don't do any more now
128 g_message ("%s: Thread %p terminating", __func__, handle);
131 thr_ret = _wapi_handle_lock_shared_handles ();
132 g_assert (thr_ret == 0);
134 _wapi_thread_abandon_mutexes (handle);
136 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
137 (gpointer *)&thread_handle);
139 g_warning ("%s: error looking up thread handle %p", __func__,
142 _wapi_handle_unlock_shared_handles ();
146 thread_handle->exitstatus = exitstatus;
147 thread_handle->state = THREAD_STATE_EXITED;
148 MONO_SEM_DESTROY (&thread_handle->suspend_sem);
149 g_ptr_array_free (thread_handle->owned_mutexes, TRUE);
151 _wapi_shared_handle_set_signal_state (handle, TRUE);
153 _wapi_handle_unlock_shared_handles ();
156 g_message("%s: Recording thread handle %p id %ld status as %d",
157 __func__, handle, thread_handle->id, exitstatus);
160 /* The thread is no longer active, so unref it */
161 _wapi_handle_unref (handle);
164 void _wapi_thread_signal_self (guint32 exitstatus)
168 handle = _wapi_thread_handle_from_id (pthread_self ());
169 if (handle == NULL) {
170 /* Something gone badly wrong... */
174 _wapi_thread_set_termination_details (handle, exitstatus);
177 /* Called by the thread creation code as a thread is finishing up, and
180 static void thread_exit (guint32 exitstatus, gpointer handle) G_GNUC_NORETURN;
181 static void thread_exit (guint32 exitstatus, gpointer handle)
183 _wapi_thread_set_termination_details (handle, exitstatus);
185 /* Call pthread_exit() to call destructors and really exit the
191 static void thread_attached_exit (gpointer handle)
193 /* Drop the extra reference we take in thread_attach, now this
197 _wapi_thread_set_termination_details (handle, 0);
200 static void thread_hash_init(void)
204 thr_ret = pthread_key_create (&thread_hash_key, NULL);
205 g_assert (thr_ret == 0);
207 thr_ret = pthread_key_create (&thread_attached_key,
208 thread_attached_exit);
209 g_assert (thr_ret == 0);
212 static void _wapi_thread_suspend (struct _WapiHandle_thread *thread)
214 g_assert (thread->owner_pid == _wapi_getpid ());
215 g_assert (pthread_equal (thread->id, pthread_self ()));
217 while (MONO_SEM_WAIT (&thread->suspend_sem) != 0 &&
221 static void _wapi_thread_resume (struct _WapiHandle_thread *thread)
223 if (thread->owner_pid != _wapi_getpid ()) {
227 MONO_SEM_POST (&thread->suspend_sem);
230 static void *thread_start_routine (gpointer args) G_GNUC_NORETURN;
231 static void *thread_start_routine (gpointer args)
233 struct _WapiHandle_thread *thread = (struct _WapiHandle_thread *)args;
236 thr_ret = pthread_detach (pthread_self ());
237 g_assert (thr_ret == 0);
239 thr_ret = pthread_setspecific (thread_hash_key,
240 (void *)thread->handle);
241 g_assert (thr_ret == 0);
243 thread->id = pthread_self();
246 g_message ("%s: started thread id %ld", __func__, thread->id);
249 if (thread->create_flags & CREATE_SUSPENDED) {
250 _wapi_thread_suspend (thread);
253 thread_exit (thread->start_routine (thread->start_arg),
257 /* Even though we tell gcc that this function doesn't return,
258 * other compilers won't see that.
266 * @security: Ignored for now.
267 * @stacksize: the size in bytes of the new thread's stack. Use 0 to
268 * default to the normal stack size. (Ignored for now).
269 * @start: The function that the new thread should start with
270 * @param: The parameter to give to @start.
271 * @create: If 0, the new thread is ready to run immediately. If
272 * %CREATE_SUSPENDED, the new thread will be in the suspended state,
273 * requiring a ResumeThread() call to continue running.
274 * @tid: If non-NULL, the ID of the new thread is stored here. NB
275 * this is defined as a DWORD (ie 32bit) in the MS API, but we need to
276 * cope with 64 bit IDs for s390x and amd64.
278 * Creates a new threading handle.
280 * Return value: a new handle, or NULL
282 gpointer CreateThread(WapiSecurityAttributes *security G_GNUC_UNUSED, guint32 stacksize,
283 WapiThreadStart start, gpointer param, guint32 create,
286 struct _WapiHandle_thread thread_handle = {0}, *thread_handle_p;
293 gpointer ct_ret = NULL;
295 mono_once (&thread_hash_once, thread_hash_init);
296 mono_once (&thread_ops_once, thread_ops_init);
302 thread_handle.state = THREAD_STATE_START;
303 thread_handle.owner_pid = _wapi_getpid ();
304 thread_handle.owned_mutexes = g_ptr_array_new ();
305 thread_handle.create_flags = create;
306 thread_handle.start_routine = start;
307 thread_handle.start_arg = param;
309 handle = _wapi_handle_new (WAPI_HANDLE_THREAD, &thread_handle);
310 if (handle == _WAPI_HANDLE_INVALID) {
311 g_warning ("%s: error creating thread handle", __func__);
312 SetLastError (ERROR_GEN_FAILURE);
317 thr_ret = _wapi_handle_lock_shared_handles ();
318 g_assert (thr_ret == 0);
320 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
321 (gpointer *)&thread_handle_p);
323 g_warning ("%s: error looking up thread handle %p", __func__,
325 SetLastError (ERROR_GEN_FAILURE);
330 /* Hold a reference while the thread is active, because we use
331 * the handle to store thread exit information
333 _wapi_handle_ref (handle);
335 /* Set a 2M stack size. This is the default on Linux, but BSD
336 * needs it. (The original bug report from Martin Dvorak <md@9ll.cz>
337 * set the size to 2M-4k. I don't know why it's short by 4k, so
338 * I'm leaving it as 2M until I'm told differently.)
340 thr_ret = pthread_attr_init(&attr);
341 g_assert (thr_ret == 0);
343 /* defaults of 2Mb for 32bits and 4Mb for 64bits */
344 /* temporarily changed to use 1 MB: this allows more threads
345 * to be used, as well as using less virtual memory and so
346 * more is available for the GC heap.
349 #if HAVE_VALGRIND_MEMCHECK_H
350 if (RUNNING_ON_VALGRIND) {
353 stacksize = (SIZEOF_VOID_P / 4) * 1024 * 1024;
356 stacksize = (SIZEOF_VOID_P / 4) * 1024 * 1024;
360 #ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE
361 thr_ret = pthread_attr_setstacksize(&attr, stacksize);
362 g_assert (thr_ret == 0);
365 MONO_SEM_INIT (&thread_handle_p->suspend_sem, 0);
366 thread_handle_p->handle = handle;
368 ret = pthread_create (&thread_handle_p->id, &attr,
369 thread_start_routine, (void *)thread_handle_p);
372 g_message ("%s: Thread create error: %s", __func__,
376 /* Two, because of the reference we took above */
384 g_message("%s: Started thread handle %p ID %ld", __func__, handle,
385 thread_handle_p->id);
389 #ifdef PTHREAD_POINTER_ID
390 /* Don't use GPOINTER_TO_UINT here, it can't cope with
391 * sizeof(void *) > sizeof(uint) when a cast to uint
394 *tid = (gsize)(thread_handle_p->id);
396 *tid = thread_handle_p->id;
401 _wapi_handle_unlock_shared_handles ();
403 /* Must not call _wapi_handle_unref() with the shared handles
406 for (i = 0; i < unrefs; i++) {
407 _wapi_handle_unref (handle);
413 /* The only time this function is called when tid != pthread_self ()
414 * is from OpenThread (), so we can fast-path most cases by just
415 * looking up the handle in TLS. OpenThread () must cope with a NULL
416 * return and do a handle search in that case.
418 gpointer _wapi_thread_handle_from_id (pthread_t tid)
422 if (pthread_equal (tid, pthread_self ()) &&
423 (ret = pthread_getspecific (thread_hash_key)) != NULL) {
424 /* We know the handle */
427 g_message ("%s: Returning %p for self thread %ld from TLS",
435 g_message ("%s: Returning NULL for unknown or non-self thread %ld",
443 static gboolean find_thread_by_id (gpointer handle, gpointer user_data)
445 pthread_t tid = (pthread_t)user_data;
446 struct _WapiHandle_thread *thread_handle;
449 /* Ignore threads that have already exited (ie they are signalled) */
450 if (_wapi_handle_issignalled (handle) == FALSE) {
451 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
452 (gpointer *)&thread_handle);
454 /* It's possible that the handle has vanished
455 * during the _wapi_search_handle before it
456 * gets here, so don't spam the console with
463 g_message ("%s: looking at thread %ld from process %d", __func__, thread_handle->id, thread_handle->owner_pid);
466 if (thread_handle->owner_pid != _wapi_getpid ()) {
467 /* Not sure if ms has this limitation with
468 * OpenThread(), but pthreads IDs are not
469 * unique across processes
472 g_message ("%s: not this process", __func__);
477 if (pthread_equal (thread_handle->id, tid)) {
479 g_message ("%s: found the thread we are looking for",
487 g_message ("%s: not found %ld, returning FALSE", __func__, tid);
493 /* NB tid is 32bit in MS API, but we need 64bit on amd64 and s390x
494 * (and probably others)
496 gpointer OpenThread (guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, gsize tid)
500 mono_once (&thread_hash_once, thread_hash_init);
501 mono_once (&thread_ops_once, thread_ops_init);
504 g_message ("%s: looking up thread %"G_GSIZE_FORMAT, __func__, tid);
507 ret = _wapi_thread_handle_from_id ((pthread_t)tid);
509 /* We need to search for this thread */
510 ret = _wapi_search_handle (WAPI_HANDLE_THREAD, find_thread_by_id, (gpointer)tid, NULL, TRUE); /* FIXME: have a proper look at this, me might not need to set search_shared = TRUE */
512 /* if _wapi_search_handle() returns a found handle, it
515 _wapi_handle_ref (ret);
519 g_message ("%s: returning thread handle %p", __func__, ret);
527 * @exitcode: Sets the thread's exit code, which can be read from
528 * another thread with GetExitCodeThread().
530 * Terminates the calling thread. A thread can also exit by returning
531 * from its start function. When the last thread in a process
532 * terminates, the process itself terminates.
534 void ExitThread(guint32 exitcode)
536 gpointer thread = _wapi_thread_handle_from_id (pthread_self ());
538 if (thread != NULL) {
539 thread_exit(exitcode, thread);
541 /* Just blow this thread away */
548 * @handle: The thread handle to query
549 * @exitcode: The thread @handle exit code is stored here
551 * Finds the exit code of @handle, and stores it in @exitcode. If the
552 * thread @handle is still running, the value stored is %STILL_ACTIVE.
554 * Return value: %TRUE, or %FALSE on error.
556 gboolean GetExitCodeThread(gpointer handle, guint32 *exitcode)
558 struct _WapiHandle_thread *thread_handle;
561 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
562 (gpointer *)&thread_handle);
564 g_warning ("%s: error looking up thread handle %p", __func__,
570 g_message ("%s: Finding exit status for thread handle %p id %ld",
571 __func__, handle, thread_handle->id);
574 if (exitcode == NULL) {
576 g_message ("%s: Nowhere to store exit code", __func__);
581 if (thread_handle->state != THREAD_STATE_EXITED) {
583 g_message ("%s: Thread still active (state %d, exited is %d)",
584 __func__, thread_handle->state,
585 THREAD_STATE_EXITED);
587 *exitcode = STILL_ACTIVE;
591 *exitcode = thread_handle->exitstatus;
597 * GetCurrentThreadId:
599 * Looks up the thread ID of the current thread. This ID can be
600 * passed to OpenThread() to create a new handle on this thread.
602 * Return value: the thread ID. NB this is defined as DWORD (ie 32
603 * bit) in the MS API, but we need to cope with 64 bit IDs for s390x
604 * and amd64. This doesn't really break the API, it just embraces and
605 * extends it on 64bit platforms :)
607 gsize GetCurrentThreadId(void)
609 pthread_t tid = pthread_self();
611 #ifdef PTHREAD_POINTER_ID
612 /* Don't use GPOINTER_TO_UINT here, it can't cope with
613 * sizeof(void *) > sizeof(uint) when a cast to uint would
622 static gpointer thread_attach(gsize *tid)
624 struct _WapiHandle_thread thread_handle = {0}, *thread_handle_p;
629 mono_once (&thread_hash_once, thread_hash_init);
630 mono_once (&thread_ops_once, thread_ops_init);
632 thread_handle.state = THREAD_STATE_START;
633 thread_handle.owner_pid = _wapi_getpid ();
634 thread_handle.owned_mutexes = g_ptr_array_new ();
636 handle = _wapi_handle_new (WAPI_HANDLE_THREAD, &thread_handle);
637 if (handle == _WAPI_HANDLE_INVALID) {
638 g_warning ("%s: error creating thread handle", __func__);
640 SetLastError (ERROR_GEN_FAILURE);
644 thr_ret = _wapi_handle_lock_shared_handles ();
645 g_assert (thr_ret == 0);
647 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
648 (gpointer *)&thread_handle_p);
650 g_warning ("%s: error looking up thread handle %p", __func__,
653 SetLastError (ERROR_GEN_FAILURE);
657 /* Hold a reference while the thread is active, because we use
658 * the handle to store thread exit information
660 _wapi_handle_ref (handle);
662 /* suspend_sem is not used for attached threads, but
663 * thread_exit() might try to destroy it
665 MONO_SEM_INIT (&thread_handle_p->suspend_sem, 0);
666 thread_handle_p->handle = handle;
667 thread_handle_p->id = pthread_self ();
669 thr_ret = pthread_setspecific (thread_hash_key, (void *)handle);
670 g_assert (thr_ret == 0);
672 thr_ret = pthread_setspecific (thread_attached_key, (void *)handle);
673 g_assert (thr_ret == 0);
676 g_message("%s: Attached thread handle %p ID %ld", __func__, handle,
677 thread_handle_p->id);
681 #ifdef PTHREAD_POINTER_ID
682 /* Don't use GPOINTER_TO_UINT here, it can't cope with
683 * sizeof(void *) > sizeof(uint) when a cast to uint
686 *tid = (gsize)(thread_handle_p->id);
688 *tid = thread_handle_p->id;
693 _wapi_handle_unlock_shared_handles ();
698 gpointer _wapi_thread_duplicate ()
702 mono_once (&thread_hash_once, thread_hash_init);
703 mono_once (&thread_ops_once, thread_ops_init);
705 ret = _wapi_thread_handle_from_id (pthread_self ());
707 ret = thread_attach (NULL);
709 _wapi_handle_ref (ret);
718 * Looks up the handle associated with the current thread. Under
719 * Windows this is a pseudohandle, and must be duplicated with
720 * DuplicateHandle() for some operations.
722 * Return value: The current thread handle, or %NULL on failure.
723 * (Unknown whether Windows has a possible failure here. It may be
724 * necessary to implement the pseudohandle-constant behaviour).
726 gpointer GetCurrentThread(void)
728 mono_once(&thread_hash_once, thread_hash_init);
729 mono_once (&thread_ops_once, thread_ops_init);
731 return(_WAPI_THREAD_CURRENT);
736 * @handle: the thread handle to resume
738 * Decrements the suspend count of thread @handle. A thread can only
739 * run if its suspend count is zero.
741 * Return value: the previous suspend count, or 0xFFFFFFFF on error.
743 guint32 ResumeThread(gpointer handle)
745 struct _WapiHandle_thread *thread_handle;
748 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
749 (gpointer *)&thread_handle);
751 g_warning ("%s: error looking up thread handle %p", __func__,
757 /* This is still a kludge that only copes with starting a
758 * thread that was suspended on create, so don't bother with
759 * the suspend count crap yet
761 _wapi_thread_resume (thread_handle);
767 * @handle: the thread handle to suspend
769 * Increments the suspend count of thread @handle. A thread can only
770 * run if its suspend count is zero.
772 * Return value: the previous suspend count, or 0xFFFFFFFF on error.
774 guint32 SuspendThread(gpointer handle)
780 * We assume here that TLS_MINIMUM_AVAILABLE is less than
781 * PTHREAD_KEYS_MAX, allowing enough overhead for a few TLS keys for
784 * Currently TLS_MINIMUM_AVAILABLE is 64 and _POSIX_THREAD_KEYS_MAX
785 * (the minimum value for PTHREAD_KEYS_MAX) is 128, so we should be
789 static pthread_key_t TLS_keys[TLS_MINIMUM_AVAILABLE];
790 static gboolean TLS_used[TLS_MINIMUM_AVAILABLE]={FALSE};
791 static guint32 TLS_spinlock=0;
794 mono_pthread_key_for_tls (guint32 idx)
796 return (guint32)TLS_keys [idx];
802 * Allocates a Thread Local Storage (TLS) index. Any thread in the
803 * same process can use this index to store and retrieve values that
804 * are local to that thread.
806 * Return value: The index value, or %TLS_OUT_OF_INDEXES if no index
809 guint32 TlsAlloc(void)
814 MONO_SPIN_LOCK (TLS_spinlock);
816 for(i=0; i<TLS_MINIMUM_AVAILABLE; i++) {
817 if(TLS_used[i]==FALSE) {
819 thr_ret = pthread_key_create(&TLS_keys[i], NULL);
820 g_assert (thr_ret == 0);
822 MONO_SPIN_UNLOCK (TLS_spinlock);
825 g_message ("%s: returning key %d", __func__, i);
832 MONO_SPIN_UNLOCK (TLS_spinlock);
835 g_message ("%s: out of indices", __func__);
839 return(TLS_OUT_OF_INDEXES);
842 #define MAKE_GC_ID(idx) (GUINT_TO_POINTER((idx)|(GetCurrentThreadId()<<8)))
846 * @idx: The TLS index to free
848 * Releases a TLS index, making it available for reuse. This call
849 * will delete any TLS data stored under index @idx in all threads.
851 * Return value: %TRUE on success, %FALSE otherwise.
853 gboolean TlsFree(guint32 idx)
858 g_message ("%s: freeing key %d", __func__, idx);
861 MONO_SPIN_LOCK (TLS_spinlock);
863 if(TLS_used[idx]==FALSE) {
864 MONO_SPIN_UNLOCK (TLS_spinlock);
870 thr_ret = pthread_key_delete(TLS_keys[idx]);
871 g_assert (thr_ret == 0);
873 MONO_SPIN_UNLOCK (TLS_spinlock);
880 * @idx: The TLS index to retrieve
882 * Retrieves the TLS data stored under index @idx.
884 * Return value: The value stored in the TLS index @idx in the current
885 * thread, or %NULL on error. As %NULL can be a valid return value,
886 * in this case GetLastError() returns %ERROR_SUCCESS.
888 gpointer TlsGetValue(guint32 idx)
893 g_message ("%s: looking up key %d", __func__, idx);
896 ret=pthread_getspecific(TLS_keys[idx]);
899 g_message ("%s: returning %p", __func__, ret);
907 * @idx: The TLS index to store
908 * @value: The value to store under index @idx
910 * Stores @value at TLS index @idx.
912 * Return value: %TRUE on success, %FALSE otherwise.
914 gboolean TlsSetValue(guint32 idx, gpointer value)
919 g_message ("%s: setting key %d to %p", __func__, idx, value);
922 MONO_SPIN_LOCK (TLS_spinlock);
924 if(TLS_used[idx]==FALSE) {
926 g_message ("%s: key %d unused", __func__, idx);
929 MONO_SPIN_UNLOCK (TLS_spinlock);
934 ret=pthread_setspecific(TLS_keys[idx], value);
937 g_message ("%s: pthread_setspecific error: %s", __func__,
941 MONO_SPIN_UNLOCK (TLS_spinlock);
946 MONO_SPIN_UNLOCK (TLS_spinlock);
953 * @ms: The time in milliseconds to suspend for
954 * @alertable: if TRUE, the wait can be interrupted by an APC call
956 * Suspends execution of the current thread for @ms milliseconds. A
957 * value of zero causes the thread to relinquish its time slice. A
958 * value of %INFINITE causes an infinite delay.
960 guint32 SleepEx(guint32 ms, gboolean alertable)
962 struct timespec req, rem;
965 gpointer current_thread = NULL;
968 g_message("%s: Sleeping for %d ms", __func__, ms);
972 current_thread = _wapi_thread_handle_from_id (pthread_self ());
973 if (current_thread == NULL) {
974 SetLastError (ERROR_INVALID_HANDLE);
978 if (_wapi_thread_apc_pending (current_thread)) {
979 _wapi_thread_dispatch_apc_queue (current_thread);
980 return WAIT_IO_COMPLETION;
989 /* FIXME: check for INFINITE and sleep forever */
994 req.tv_nsec=ms_rem*1000000;
997 ret=nanosleep(&req, &rem);
999 if (alertable && _wapi_thread_apc_pending (current_thread)) {
1000 _wapi_thread_dispatch_apc_queue (current_thread);
1001 return WAIT_IO_COMPLETION;
1005 /* Sleep interrupted with rem time remaining */
1007 guint32 rems=rem.tv_sec*1000 + rem.tv_nsec/1000000;
1009 g_message("%s: Still got %d ms to go", __func__, rems);
1018 void Sleep(guint32 ms)
1023 static mono_mutex_t apc_mutex = MONO_MUTEX_INITIALIZER;
1025 gboolean _wapi_thread_cur_apc_pending (void)
1027 gpointer thread = _wapi_thread_handle_from_id (pthread_self ());
1029 if (thread == NULL) {
1030 SetLastError (ERROR_INVALID_HANDLE);
1034 return(_wapi_thread_apc_pending (thread));
1037 static void _wapi_thread_queue_apc (struct _WapiHandle_thread *thread,
1038 guint32 (*apc_callback)(gpointer),
1044 if (thread->owner_pid != _wapi_getpid ()) {
1048 apc = (ApcInfo *)g_new (ApcInfo, 1);
1049 apc->callback = apc_callback;
1052 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
1053 (void *)&apc_mutex);
1054 thr_ret = mono_mutex_lock (&apc_mutex);
1055 g_assert (thr_ret == 0);
1057 thread->apc_queue = g_slist_append (thread->apc_queue, apc);
1059 thr_ret = mono_mutex_unlock (&apc_mutex);
1060 g_assert (thr_ret == 0);
1061 pthread_cleanup_pop (0);
1064 gboolean _wapi_thread_apc_pending (gpointer handle)
1066 struct _WapiHandle_thread *thread;
1069 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
1070 (gpointer *)&thread);
1073 /* This might happen at process shutdown, as all
1074 * thread handles are forcibly closed. If a thread
1075 * still has an alertable wait the final
1076 * _wapi_thread_apc_pending check will probably fail
1077 * to find the handle
1079 g_warning ("%s: error looking up thread handle %p", __func__,
1085 if (thread->owner_pid != _wapi_getpid ()) {
1089 return(thread->apc_queue != NULL);
1092 gboolean _wapi_thread_dispatch_apc_queue (gpointer handle)
1094 struct _WapiHandle_thread *thread;
1100 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
1101 (gpointer *)&thread);
1103 g_warning ("%s: error looking up thread handle %p", __func__,
1108 if (thread->owner_pid != _wapi_getpid ()) {
1112 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
1113 (void *)&apc_mutex);
1114 thr_ret = mono_mutex_lock (&apc_mutex);
1115 g_assert (thr_ret == 0);
1117 list = thread->apc_queue;
1118 thread->apc_queue = NULL;
1120 thr_ret = mono_mutex_unlock (&apc_mutex);
1121 g_assert (thr_ret == 0);
1122 pthread_cleanup_pop (0);
1124 while (list != NULL) {
1125 apc = (ApcInfo *)list->data;
1126 apc->callback (apc->param);
1128 list = g_slist_next (list);
1130 g_slist_free (list);
1135 guint32 QueueUserAPC (WapiApcProc apc_callback, gpointer handle,
1138 struct _WapiHandle_thread *thread_handle;
1141 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
1142 (gpointer *)&thread_handle);
1144 g_warning ("%s: error looking up thread handle %p", __func__,
1149 _wapi_thread_queue_apc (thread_handle, apc_callback, param);
1153 void _wapi_thread_own_mutex (gpointer mutex)
1155 struct _WapiHandle_thread *thread_handle;
1159 thread = _wapi_thread_handle_from_id (pthread_self ());
1160 if (thread == NULL) {
1161 g_warning ("%s: error looking up thread by ID", __func__);
1165 ok = _wapi_lookup_handle (thread, WAPI_HANDLE_THREAD,
1166 (gpointer *)&thread_handle);
1168 g_warning ("%s: error looking up thread handle %p", __func__,
1173 _wapi_handle_ref (mutex);
1175 g_ptr_array_add (thread_handle->owned_mutexes, mutex);
1178 void _wapi_thread_disown_mutex (gpointer mutex)
1180 struct _WapiHandle_thread *thread_handle;
1184 thread = _wapi_thread_handle_from_id (pthread_self ());
1185 if (thread == NULL) {
1186 g_warning ("%s: error looking up thread by ID", __func__);
1190 ok = _wapi_lookup_handle (thread, WAPI_HANDLE_THREAD,
1191 (gpointer *)&thread_handle);
1193 g_warning ("%s: error looking up thread handle %p", __func__,
1198 _wapi_handle_unref (mutex);
1200 g_ptr_array_remove (thread_handle->owned_mutexes, mutex);