2 * threads.c: Thread handles
5 * Dick Porter (dick@ximian.com)
7 * (C) 2002 Ximian, Inc.
12 #include <mono/os/gc_wrapper.h>
13 #include "mono/utils/mono-hash.h"
24 #include <mono/io-layer/wapi.h>
25 #include <mono/io-layer/wapi-private.h>
26 #include <mono/io-layer/timed-thread.h>
27 #include <mono/io-layer/handles-private.h>
28 #include <mono/io-layer/misc-private.h>
29 #include <mono/io-layer/mono-mutex.h>
30 #include <mono/io-layer/thread-private.h>
31 #include <mono/io-layer/mono-spinlock.h>
33 #if HAVE_VALGRIND_MEMCHECK_H
34 #include <valgrind/memcheck.h>
41 /* Hash threads with tids. I thought of using TLS for this, but that
42 * would have to set the data in the new thread, which is more hassle
44 static mono_once_t thread_hash_once = MONO_ONCE_INIT;
45 static mono_mutex_t thread_hash_mutex = MONO_MUTEX_INITIALIZER;
46 static GHashTable *thread_hash=NULL;
49 static MonoGHashTable *tls_gc_hash = NULL;
52 static void thread_close_private (gpointer handle);
53 static void thread_own (gpointer handle);
55 struct _WapiHandleOps _wapi_thread_ops = {
56 NULL, /* close_shared */
57 thread_close_private, /* close_private */
63 static mono_once_t thread_ops_once=MONO_ONCE_INIT;
65 #ifdef WITH_INCLUDED_LIBGC
66 static void gc_init (void);
69 static void thread_ops_init (void)
71 _wapi_handle_register_capabilities (WAPI_HANDLE_THREAD,
72 WAPI_HANDLE_CAP_WAIT);
74 #ifdef WITH_INCLUDED_LIBGC
79 static void thread_close_private (gpointer handle)
81 struct _WapiHandlePrivate_thread *thread_handle;
84 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD, NULL,
85 (gpointer *)&thread_handle);
87 g_warning (G_GNUC_PRETTY_FUNCTION
88 ": error looking up thread handle %p", handle);
93 g_message(G_GNUC_PRETTY_FUNCTION
94 ": closing thread handle %p with thread %p id %ld",
95 handle, thread_handle->thread,
96 thread_handle->thread->id);
99 if(thread_handle->thread!=NULL) {
100 _wapi_timed_thread_destroy (thread_handle->thread);
104 static void thread_own (gpointer handle)
106 struct _WapiHandle_thread *thread_handle;
107 struct _WapiHandlePrivate_thread *thread_private_handle;
110 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
111 (gpointer *)&thread_handle,
112 (gpointer *)&thread_private_handle);
114 g_warning (G_GNUC_PRETTY_FUNCTION
115 ": error looking up thread handle %p", handle);
119 if(thread_private_handle->joined==FALSE) {
120 _wapi_timed_thread_join (thread_private_handle->thread, NULL,
122 thread_private_handle->joined=TRUE;
126 static void thread_exit(guint32 exitstatus, gpointer handle)
128 struct _WapiHandle_thread *thread_handle;
129 struct _WapiHandlePrivate_thread *thread_private_handle;
133 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
134 (gpointer *)&thread_handle,
135 (gpointer *)&thread_private_handle);
137 g_warning (G_GNUC_PRETTY_FUNCTION
138 ": error looking up thread handle %p", handle);
142 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
144 thr_ret = _wapi_handle_lock_handle (handle);
145 g_assert (thr_ret == 0);
148 g_message (G_GNUC_PRETTY_FUNCTION
149 ": Recording thread handle %p exit status", handle);
152 thread_handle->exitstatus=exitstatus;
153 thread_handle->state=THREAD_STATE_EXITED;
154 _wapi_handle_set_signal_state (handle, TRUE, TRUE);
156 thr_ret = _wapi_handle_unlock_handle (handle);
157 g_assert (thr_ret == 0);
158 pthread_cleanup_pop (0);
161 g_message(G_GNUC_PRETTY_FUNCTION
162 ": Recording thread handle %p id %ld status as %d",
163 handle, thread_private_handle->thread->id, exitstatus);
166 /* Remove this thread from the hash */
167 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
168 (void *)&thread_hash_mutex);
169 thr_ret = mono_mutex_lock(&thread_hash_mutex);
170 g_assert (thr_ret == 0);
172 g_hash_table_remove(thread_hash, &thread_private_handle->thread->id);
174 thr_ret = mono_mutex_unlock(&thread_hash_mutex);
175 g_assert (thr_ret == 0);
176 pthread_cleanup_pop (0);
178 /* The thread is no longer active, so unref it */
179 _wapi_handle_unref (handle);
182 static void thread_hash_init(void)
184 thread_hash=g_hash_table_new(g_int_hash, g_int_equal);
189 * @security: Ignored for now.
190 * @stacksize: the size in bytes of the new thread's stack. Use 0 to
191 * default to the normal stack size. (Ignored for now).
192 * @start: The function that the new thread should start with
193 * @param: The parameter to give to @start.
194 * @create: If 0, the new thread is ready to run immediately. If
195 * %CREATE_SUSPENDED, the new thread will be in the suspended state,
196 * requiring a ResumeThread() call to continue running.
197 * @tid: If non-NULL, the ID of the new thread is stored here.
199 * Creates a new threading handle.
201 * Return value: a new handle, or NULL
203 gpointer CreateThread(WapiSecurityAttributes *security G_GNUC_UNUSED, guint32 stacksize,
204 WapiThreadStart start, gpointer param, guint32 create,
207 struct _WapiHandle_thread *thread_handle;
208 struct _WapiHandlePrivate_thread *thread_private_handle;
215 gpointer ct_ret = NULL;
217 mono_once(&thread_hash_once, thread_hash_init);
218 mono_once (&thread_ops_once, thread_ops_init);
224 handle=_wapi_handle_new (WAPI_HANDLE_THREAD);
225 if(handle==_WAPI_HANDLE_INVALID) {
226 g_warning (G_GNUC_PRETTY_FUNCTION
227 ": error creating thread handle");
231 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
233 thr_ret = _wapi_handle_lock_handle (handle);
234 g_assert (thr_ret == 0);
236 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
237 (gpointer *)&thread_handle,
238 (gpointer *)&thread_private_handle);
240 g_warning (G_GNUC_PRETTY_FUNCTION
241 ": error looking up thread handle %p", handle);
245 /* Hold a reference while the thread is active, because we use
246 * the handle to store thread exit information
248 _wapi_handle_ref (handle);
250 thread_handle->state=THREAD_STATE_START;
252 /* Lock around the thread create, so that the new thread cant
253 * race us to look up the thread handle in GetCurrentThread()
255 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
256 (void *)&thread_hash_mutex);
257 thr_ret = mono_mutex_lock(&thread_hash_mutex);
258 g_assert (thr_ret == 0);
260 /* Set a 2M stack size. This is the default on Linux, but BSD
261 * needs it. (The original bug report from Martin Dvorak <md@9ll.cz>
262 * set the size to 2M-4k. I don't know why it's short by 4k, so
263 * I'm leaving it as 2M until I'm told differently.)
265 thr_ret = pthread_attr_init(&attr);
266 g_assert (thr_ret == 0);
268 /* defaults of 2Mb for 32bits and 4Mb for 64bits */
270 #if HAVE_VALGRIND_MEMCHECK_H
271 if (RUNNING_ON_VALGRIND)
274 stacksize = (SIZEOF_VOID_P / 2) * 1024 * 1024;
276 stacksize = (SIZEOF_VOID_P / 2) * 1024 * 1024;
281 #ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE
282 thr_ret = pthread_attr_setstacksize(&attr, stacksize);
283 g_assert (thr_ret == 0);
286 ret=_wapi_timed_thread_create(&thread_private_handle->thread, &attr,
287 create, start, thread_exit, param,
291 g_message(G_GNUC_PRETTY_FUNCTION ": Thread create error: %s",
294 /* Two, because of the reference we took above */
296 goto thread_hash_cleanup;
300 g_hash_table_insert(thread_hash, &thread_private_handle->thread->id,
304 g_message(G_GNUC_PRETTY_FUNCTION
305 ": Started thread handle %p thread %p ID %ld", handle,
306 thread_private_handle->thread,
307 thread_private_handle->thread->id);
311 #ifdef PTHREAD_POINTER_ID
312 *tid=GPOINTER_TO_UINT(thread_private_handle->thread->id);
314 *tid=thread_private_handle->thread->id;
319 thr_ret = mono_mutex_unlock (&thread_hash_mutex);
320 g_assert (thr_ret == 0);
321 pthread_cleanup_pop (0);
324 thr_ret = _wapi_handle_unlock_handle (handle);
325 g_assert (thr_ret == 0);
326 pthread_cleanup_pop (0);
328 /* Must not call _wapi_handle_unref() with the handle already
331 for (i = 0; i < unrefs; i++) {
332 _wapi_handle_unref (handle);
338 gpointer OpenThread (guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, guint32 tid)
343 mono_once(&thread_hash_once, thread_hash_init);
344 mono_once (&thread_ops_once, thread_ops_init);
347 g_message (G_GNUC_PRETTY_FUNCTION ": looking up thread %d", tid);
350 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
351 (void *)&thread_hash_mutex);
352 thr_ret = mono_mutex_lock(&thread_hash_mutex);
353 g_assert (thr_ret == 0);
355 ret=g_hash_table_lookup(thread_hash, &tid);
357 thr_ret = mono_mutex_unlock(&thread_hash_mutex);
358 g_assert (thr_ret == 0);
359 pthread_cleanup_pop (0);
362 _wapi_handle_ref (ret);
366 g_message (G_GNUC_PRETTY_FUNCTION ": returning thread handle %p", ret);
374 * @exitcode: Sets the thread's exit code, which can be read from
375 * another thread with GetExitCodeThread().
377 * Terminates the calling thread. A thread can also exit by returning
378 * from its start function. When the last thread in a process
379 * terminates, the process itself terminates.
381 void ExitThread(guint32 exitcode)
383 _wapi_timed_thread_exit(exitcode);
388 * @handle: The thread handle to query
389 * @exitcode: The thread @handle exit code is stored here
391 * Finds the exit code of @handle, and stores it in @exitcode. If the
392 * thread @handle is still running, the value stored is %STILL_ACTIVE.
394 * Return value: %TRUE, or %FALSE on error.
396 gboolean GetExitCodeThread(gpointer handle, guint32 *exitcode)
398 struct _WapiHandle_thread *thread_handle;
399 struct _WapiHandlePrivate_thread *thread_private_handle;
402 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
403 (gpointer *)&thread_handle,
404 (gpointer *)&thread_private_handle);
406 g_warning (G_GNUC_PRETTY_FUNCTION
407 ": error looking up thread handle %p", handle);
412 g_message(G_GNUC_PRETTY_FUNCTION
413 ": Finding exit status for thread handle %p id %ld", handle,
414 thread_private_handle->thread->id);
419 g_message(G_GNUC_PRETTY_FUNCTION
420 ": Nowhere to store exit code");
425 if(thread_handle->state!=THREAD_STATE_EXITED) {
427 g_message(G_GNUC_PRETTY_FUNCTION
428 ": Thread still active (state %d, exited is %d)",
429 thread_handle->state, THREAD_STATE_EXITED);
431 *exitcode=STILL_ACTIVE;
435 *exitcode=thread_handle->exitstatus;
441 * GetCurrentThreadId:
443 * Looks up the thread ID of the current thread. This ID can be
444 * passed to OpenThread() to create a new handle on this thread.
446 * Return value: the thread ID.
448 guint32 GetCurrentThreadId(void)
450 pthread_t tid=pthread_self();
452 #ifdef PTHREAD_POINTER_ID
453 return(GPOINTER_TO_UINT(tid));
459 static gpointer thread_attach(guint32 *tid)
461 struct _WapiHandle_thread *thread_handle;
462 struct _WapiHandlePrivate_thread *thread_private_handle;
468 gpointer ta_ret = NULL;
470 mono_once(&thread_hash_once, thread_hash_init);
471 mono_once (&thread_ops_once, thread_ops_init);
473 handle=_wapi_handle_new (WAPI_HANDLE_THREAD);
474 if(handle==_WAPI_HANDLE_INVALID) {
475 g_warning (G_GNUC_PRETTY_FUNCTION
476 ": error creating thread handle");
480 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
482 thr_ret = _wapi_handle_lock_handle (handle);
483 g_assert (thr_ret == 0);
485 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
486 (gpointer *)&thread_handle,
487 (gpointer *)&thread_private_handle);
489 g_warning (G_GNUC_PRETTY_FUNCTION
490 ": error looking up thread handle %p", handle);
494 /* Hold a reference while the thread is active, because we use
495 * the handle to store thread exit information
497 _wapi_handle_ref (handle);
499 thread_handle->state=THREAD_STATE_START;
501 /* Lock around the thread create, so that the new thread cant
502 * race us to look up the thread handle in GetCurrentThread()
504 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
505 (void *)&thread_hash_mutex);
506 thr_ret = mono_mutex_lock(&thread_hash_mutex);
507 g_assert (thr_ret == 0);
509 ret=_wapi_timed_thread_attach(&thread_private_handle->thread,
510 thread_exit, handle);
513 g_message(G_GNUC_PRETTY_FUNCTION ": Thread attach error: %s",
516 /* Two, because of the reference we took above */
519 goto thread_hash_cleanup;
523 g_hash_table_insert(thread_hash, &thread_private_handle->thread->id,
527 g_message(G_GNUC_PRETTY_FUNCTION
528 ": Attached thread handle %p thread %p ID %ld", handle,
529 thread_private_handle->thread,
530 thread_private_handle->thread->id);
534 #ifdef PTHREAD_POINTER_ID
535 *tid=GPOINTER_TO_UINT(thread_private_handle->thread->id);
537 *tid=thread_private_handle->thread->id;
542 thr_ret = mono_mutex_unlock (&thread_hash_mutex);
543 g_assert (thr_ret == 0);
544 pthread_cleanup_pop (0);
547 thr_ret = _wapi_handle_unlock_handle (handle);
548 g_assert (thr_ret == 0);
549 pthread_cleanup_pop (0);
551 /* Must not call _wapi_handle_unref() with the handle already
554 for (i = 0; i < unrefs; i++) {
555 _wapi_handle_unref (handle);
564 * Looks up the handle associated with the current thread. Under
565 * Windows this is a pseudohandle, and must be duplicated with
566 * DuplicateHandle() for some operations.
568 * Return value: The current thread handle, or %NULL on failure.
569 * (Unknown whether Windows has a possible failure here. It may be
570 * necessary to implement the pseudohandle-constant behaviour).
572 gpointer GetCurrentThread(void)
578 mono_once(&thread_hash_once, thread_hash_init);
579 mono_once (&thread_ops_once, thread_ops_init);
581 tid=GetCurrentThreadId();
583 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
584 (void *)&thread_hash_mutex);
585 thr_ret = mono_mutex_lock(&thread_hash_mutex);
586 g_assert (thr_ret == 0);
588 ret=g_hash_table_lookup(thread_hash, &tid);
590 thr_ret = mono_mutex_unlock(&thread_hash_mutex);
591 g_assert (thr_ret == 0);
592 pthread_cleanup_pop (0);
595 ret = thread_attach (NULL);
603 * @handle: the thread handle to resume
605 * Decrements the suspend count of thread @handle. A thread can only
606 * run if its suspend count is zero.
608 * Return value: the previous suspend count, or 0xFFFFFFFF on error.
610 guint32 ResumeThread(gpointer handle)
612 struct _WapiHandle_thread *thread_handle;
613 struct _WapiHandlePrivate_thread *thread_private_handle;
616 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
617 (gpointer *)&thread_handle,
618 (gpointer *)&thread_private_handle);
620 g_warning (G_GNUC_PRETTY_FUNCTION
621 ": error looking up thread handle %p", handle);
625 #ifdef WITH_INCLUDED_LIBGC
626 if (thread_private_handle->thread->suspend_count <= 1)
627 _wapi_timed_thread_resume (thread_private_handle->thread);
629 return --thread_private_handle->thread->suspend_count;
631 /* This is still a kludge that only copes with starting a
632 * thread that was suspended on create, so don't bother with
633 * the suspend count crap yet
635 _wapi_timed_thread_resume (thread_private_handle->thread);
642 * @handle: the thread handle to suspend
644 * Increments the suspend count of thread @handle. A thread can only
645 * run if its suspend count is zero.
647 * Return value: the previous suspend count, or 0xFFFFFFFF on error.
649 guint32 SuspendThread(gpointer handle)
651 #ifdef WITH_INCLUDED_LIBGC
652 struct _WapiHandle_thread *thread_handle;
653 struct _WapiHandlePrivate_thread *thread_private_handle;
657 current = GetCurrentThread ();
658 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
659 (gpointer *)&thread_handle,
660 (gpointer *)&thread_private_handle);
662 g_warning (G_GNUC_PRETTY_FUNCTION
663 ": error looking up thread handle %p", handle);
667 if (!thread_private_handle->thread->suspend_count) {
668 if (handle == current)
669 _wapi_timed_thread_suspend (thread_private_handle->thread);
671 pthread_kill (thread_private_handle->thread->id, SIGPWR);
672 MONO_SEM_WAIT (&thread_private_handle->thread->suspended_sem);
676 return thread_private_handle->thread->suspend_count++;
683 * We assume here that TLS_MINIMUM_AVAILABLE is less than
684 * PTHREAD_KEYS_MAX, allowing enough overhead for a few TLS keys for
687 * Currently TLS_MINIMUM_AVAILABLE is 64 and _POSIX_THREAD_KEYS_MAX
688 * (the minimum value for PTHREAD_KEYS_MAX) is 128, so we should be
692 static pthread_key_t TLS_keys[TLS_MINIMUM_AVAILABLE];
693 static gboolean TLS_used[TLS_MINIMUM_AVAILABLE]={FALSE};
694 static guint32 TLS_spinlock=0;
699 * Allocates a Thread Local Storage (TLS) index. Any thread in the
700 * same process can use this index to store and retrieve values that
701 * are local to that thread.
703 * Return value: The index value, or %TLS_OUT_OF_INDEXES if no index
706 guint32 TlsAlloc(void)
711 MONO_SPIN_LOCK (TLS_spinlock);
713 for(i=0; i<TLS_MINIMUM_AVAILABLE; i++) {
714 if(TLS_used[i]==FALSE) {
716 thr_ret = pthread_key_create(&TLS_keys[i], NULL);
717 g_assert (thr_ret == 0);
719 MONO_SPIN_UNLOCK (TLS_spinlock);
722 g_message (G_GNUC_PRETTY_FUNCTION ": returning key %d",
730 MONO_SPIN_UNLOCK (TLS_spinlock);
733 g_message (G_GNUC_PRETTY_FUNCTION ": out of indices");
737 return(TLS_OUT_OF_INDEXES);
740 #define MAKE_GC_ID(idx) (GUINT_TO_POINTER((idx)|(GetCurrentThreadId()<<8)))
744 * @idx: The TLS index to free
746 * Releases a TLS index, making it available for reuse. This call
747 * will delete any TLS data stored under index @idx in all threads.
749 * Return value: %TRUE on success, %FALSE otherwise.
751 gboolean TlsFree(guint32 idx)
756 g_message (G_GNUC_PRETTY_FUNCTION ": freeing key %d", idx);
759 MONO_SPIN_LOCK (TLS_spinlock);
761 if(TLS_used[idx]==FALSE) {
762 MONO_SPIN_UNLOCK (TLS_spinlock);
768 thr_ret = pthread_key_delete(TLS_keys[idx]);
769 g_assert (thr_ret == 0);
772 mono_g_hash_table_remove (tls_gc_hash, MAKE_GC_ID (idx));
775 MONO_SPIN_UNLOCK (TLS_spinlock);
782 * @idx: The TLS index to retrieve
784 * Retrieves the TLS data stored under index @idx.
786 * Return value: The value stored in the TLS index @idx in the current
787 * thread, or %NULL on error. As %NULL can be a valid return value,
788 * in this case GetLastError() returns %ERROR_SUCCESS.
790 gpointer TlsGetValue(guint32 idx)
795 g_message (G_GNUC_PRETTY_FUNCTION ": looking up key %d", idx);
798 ret=pthread_getspecific(TLS_keys[idx]);
801 g_message (G_GNUC_PRETTY_FUNCTION ": returning %p", ret);
809 * @idx: The TLS index to store
810 * @value: The value to store under index @idx
812 * Stores @value at TLS index @idx.
814 * Return value: %TRUE on success, %FALSE otherwise.
816 gboolean TlsSetValue(guint32 idx, gpointer value)
821 g_message (G_GNUC_PRETTY_FUNCTION ": setting key %d to %p", idx,
825 MONO_SPIN_LOCK (TLS_spinlock);
827 if(TLS_used[idx]==FALSE) {
829 g_message (G_GNUC_PRETTY_FUNCTION ": key %d unused", idx);
832 MONO_SPIN_UNLOCK (TLS_spinlock);
837 ret=pthread_setspecific(TLS_keys[idx], value);
840 g_message (G_GNUC_PRETTY_FUNCTION
841 ": pthread_setspecific error: %s", strerror (ret));
844 MONO_SPIN_UNLOCK (TLS_spinlock);
851 tls_gc_hash = mono_g_hash_table_new(g_direct_hash, g_direct_equal);
852 mono_g_hash_table_insert (tls_gc_hash, MAKE_GC_ID (idx), value);
855 MONO_SPIN_UNLOCK (TLS_spinlock);
862 * @ms: The time in milliseconds to suspend for
863 * @alertable: if TRUE, the wait can be interrupted by an APC call
865 * Suspends execution of the current thread for @ms milliseconds. A
866 * value of zero causes the thread to relinquish its time slice. A
867 * value of %INFINITE causes an infinite delay.
869 guint32 SleepEx(guint32 ms, gboolean alertable)
871 struct timespec req, rem;
874 gpointer current_thread = NULL;
877 g_message(G_GNUC_PRETTY_FUNCTION ": Sleeping for %d ms", ms);
881 current_thread = GetCurrentThread ();
882 if (_wapi_thread_apc_pending (current_thread)) {
883 _wapi_thread_dispatch_apc_queue (current_thread);
884 return WAIT_IO_COMPLETION;
893 /* FIXME: check for INFINITE and sleep forever */
898 req.tv_nsec=ms_rem*1000000;
901 ret=nanosleep(&req, &rem);
903 if (alertable && _wapi_thread_apc_pending (current_thread)) {
904 _wapi_thread_dispatch_apc_queue (current_thread);
905 return WAIT_IO_COMPLETION;
909 /* Sleep interrupted with rem time remaining */
911 guint32 rems=rem.tv_sec*1000 + rem.tv_nsec/1000000;
913 g_message(G_GNUC_PRETTY_FUNCTION ": Still got %d ms to go",
923 void Sleep(guint32 ms)
929 BindIoCompletionCallback (gpointer handle,
930 WapiOverlappedCB callback,
935 type = _wapi_handle_type (handle);
936 if (type == WAPI_HANDLE_FILE || type == WAPI_HANDLE_PIPE)
937 return _wapi_io_add_callback (handle, callback, flags);
939 SetLastError (ERROR_NOT_SUPPORTED);
943 guint32 QueueUserAPC (WapiApcProc apc_callback, gpointer handle,
946 struct _WapiHandle_thread *thread_handle;
947 struct _WapiHandlePrivate_thread *thread_private_handle;
950 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
951 (gpointer *)&thread_handle,
952 (gpointer *)&thread_private_handle);
954 g_warning (G_GNUC_PRETTY_FUNCTION
955 ": error looking up thread handle %p", handle);
959 _wapi_timed_thread_queue_apc (thread_private_handle->thread,
960 apc_callback, param);
964 gboolean _wapi_thread_cur_apc_pending (void)
966 return _wapi_thread_apc_pending (GetCurrentThread ());
969 gboolean _wapi_thread_apc_pending (gpointer handle)
971 struct _WapiHandle_thread *thread_handle;
972 struct _WapiHandlePrivate_thread *thread_private_handle;
975 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
976 (gpointer *)&thread_handle,
977 (gpointer *)&thread_private_handle);
979 g_warning (G_GNUC_PRETTY_FUNCTION
980 ": error looking up thread handle %p", handle);
984 return _wapi_timed_thread_apc_pending (thread_private_handle->thread);
987 gboolean _wapi_thread_dispatch_apc_queue (gpointer handle)
989 struct _WapiHandle_thread *thread_handle;
990 struct _WapiHandlePrivate_thread *thread_private_handle;
993 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
994 (gpointer *)&thread_handle,
995 (gpointer *)&thread_private_handle);
997 g_warning (G_GNUC_PRETTY_FUNCTION
998 ": error looking up thread handle %p", handle);
1002 _wapi_timed_thread_dispatch_apc_queue (thread_private_handle->thread);
1008 #ifdef WITH_INCLUDED_LIBGC
1010 static void GC_suspend_handler (int sig)
1012 struct _WapiHandle_thread *thread_handle;
1013 struct _WapiHandlePrivate_thread *thread_private_handle;
1017 handle = GetCurrentThread ();
1018 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
1019 (gpointer *)&thread_handle,
1020 (gpointer *)&thread_private_handle);
1022 g_warning (G_GNUC_PRETTY_FUNCTION
1023 ": error looking up thread handle %p", handle);
1027 thread_private_handle->thread->stack_ptr = &ok;
1028 MONO_SEM_POST (&thread_private_handle->thread->suspended_sem);
1030 _wapi_timed_thread_suspend (thread_private_handle->thread);
1032 thread_private_handle->thread->stack_ptr = NULL;
1035 static void gc_init (void)
1037 struct sigaction act;
1039 act.sa_handler = GC_suspend_handler;
1040 g_assert (sigaction (SIGPWR, &act, NULL) == 0);
1043 void mono_wapi_push_thread_stack (gpointer handle, gpointer stack_ptr)
1045 struct _WapiHandle_thread *thread_handle;
1046 struct _WapiHandlePrivate_thread *thread_private_handle;
1049 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
1050 (gpointer *)&thread_handle,
1051 (gpointer *)&thread_private_handle);
1053 g_warning (G_GNUC_PRETTY_FUNCTION
1054 ": error looking up thread handle %p", handle);
1058 GC_push_all_stack (thread_private_handle->thread->stack_ptr, stack_ptr);
1061 #endif /* WITH_INCLUDED_LIBGC */