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"
23 #include <sys/types.h>
26 #include <mono/io-layer/wapi.h>
27 #include <mono/io-layer/wapi-private.h>
28 #include <mono/io-layer/timed-thread.h>
29 #include <mono/io-layer/handles-private.h>
30 #include <mono/io-layer/misc-private.h>
31 #include <mono/io-layer/mono-mutex.h>
32 #include <mono/io-layer/thread-private.h>
33 #include <mono/io-layer/mono-spinlock.h>
34 #include <mono/io-layer/mutex-private.h>
36 #if HAVE_VALGRIND_MEMCHECK_H
37 #include <valgrind/memcheck.h>
44 /* Hash threads with tids. I thought of using TLS for this, but that
45 * would have to set the data in the new thread, which is more hassle
47 static mono_once_t thread_hash_once = MONO_ONCE_INIT;
48 static mono_mutex_t thread_hash_mutex = MONO_MUTEX_INITIALIZER;
49 static GHashTable *thread_hash=NULL;
52 static MonoGHashTable *tls_gc_hash = NULL;
55 static void thread_close_private (gpointer handle);
56 static void thread_own (gpointer handle);
58 struct _WapiHandleOps _wapi_thread_ops = {
59 NULL, /* close_shared */
60 thread_close_private, /* close_private */
66 static mono_once_t thread_ops_once=MONO_ONCE_INIT;
68 #ifdef WITH_INCLUDED_LIBGC
69 static void gc_init (void);
72 static void thread_ops_init (void)
74 _wapi_handle_register_capabilities (WAPI_HANDLE_THREAD,
75 WAPI_HANDLE_CAP_WAIT);
77 #ifdef WITH_INCLUDED_LIBGC
82 static void thread_close_private (gpointer handle)
84 struct _WapiHandlePrivate_thread *thread_handle;
87 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD, NULL,
88 (gpointer *)&thread_handle);
90 g_warning (G_GNUC_PRETTY_FUNCTION
91 ": error looking up thread handle %p", handle);
96 g_message(G_GNUC_PRETTY_FUNCTION
97 ": closing thread handle %p with thread %p id %ld",
98 handle, thread_handle->thread,
99 thread_handle->thread->id);
102 thread_handle->thread=NULL;
105 static void thread_own (gpointer handle)
107 struct _WapiHandle_thread *thread_handle;
108 struct _WapiHandlePrivate_thread *thread_private_handle;
111 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
112 (gpointer *)&thread_handle,
113 (gpointer *)&thread_private_handle);
115 g_warning (G_GNUC_PRETTY_FUNCTION
116 ": error looking up thread handle %p", handle);
120 if(thread_private_handle->joined==FALSE) {
121 _wapi_timed_thread_join (thread_private_handle->thread, NULL,
123 thread_private_handle->joined=TRUE;
127 static void thread_exit(guint32 exitstatus, gpointer handle)
129 struct _WapiHandle_thread *thread_handle;
130 struct _WapiHandlePrivate_thread *thread_private_handle;
134 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
135 (gpointer *)&thread_handle,
136 (gpointer *)&thread_private_handle);
138 g_warning (G_GNUC_PRETTY_FUNCTION
139 ": error looking up thread handle %p", handle);
143 _wapi_mutex_check_abandoned (getpid (),
144 thread_private_handle->thread->id);
146 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
148 thr_ret = _wapi_handle_lock_handle (handle);
149 g_assert (thr_ret == 0);
152 g_message (G_GNUC_PRETTY_FUNCTION
153 ": Recording thread handle %p exit status", handle);
156 thread_handle->exitstatus=exitstatus;
157 thread_handle->state=THREAD_STATE_EXITED;
158 _wapi_handle_set_signal_state (handle, TRUE, TRUE);
160 thr_ret = _wapi_handle_unlock_handle (handle);
161 g_assert (thr_ret == 0);
162 pthread_cleanup_pop (0);
165 g_message(G_GNUC_PRETTY_FUNCTION
166 ": Recording thread handle %p id %ld status as %d",
167 handle, thread_private_handle->thread->id, exitstatus);
170 /* Remove this thread from the hash */
171 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
172 (void *)&thread_hash_mutex);
173 thr_ret = mono_mutex_lock(&thread_hash_mutex);
174 g_assert (thr_ret == 0);
176 g_hash_table_remove(thread_hash, &thread_private_handle->thread->id);
178 thr_ret = mono_mutex_unlock(&thread_hash_mutex);
179 g_assert (thr_ret == 0);
180 pthread_cleanup_pop (0);
182 /* The thread is no longer active, so unref it */
183 _wapi_handle_unref (handle);
186 static void thread_hash_init(void)
188 thread_hash=g_hash_table_new(g_int_hash, g_int_equal);
193 * @security: Ignored for now.
194 * @stacksize: the size in bytes of the new thread's stack. Use 0 to
195 * default to the normal stack size. (Ignored for now).
196 * @start: The function that the new thread should start with
197 * @param: The parameter to give to @start.
198 * @create: If 0, the new thread is ready to run immediately. If
199 * %CREATE_SUSPENDED, the new thread will be in the suspended state,
200 * requiring a ResumeThread() call to continue running.
201 * @tid: If non-NULL, the ID of the new thread is stored here.
203 * Creates a new threading handle.
205 * Return value: a new handle, or NULL
207 gpointer CreateThread(WapiSecurityAttributes *security G_GNUC_UNUSED, guint32 stacksize,
208 WapiThreadStart start, gpointer param, guint32 create,
211 struct _WapiHandle_thread *thread_handle;
212 struct _WapiHandlePrivate_thread *thread_private_handle;
219 gpointer ct_ret = NULL;
221 mono_once(&thread_hash_once, thread_hash_init);
222 mono_once (&thread_ops_once, thread_ops_init);
228 handle=_wapi_handle_new (WAPI_HANDLE_THREAD);
229 if(handle==_WAPI_HANDLE_INVALID) {
230 g_warning (G_GNUC_PRETTY_FUNCTION
231 ": error creating thread handle");
235 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
237 thr_ret = _wapi_handle_lock_handle (handle);
238 g_assert (thr_ret == 0);
240 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
241 (gpointer *)&thread_handle,
242 (gpointer *)&thread_private_handle);
244 g_warning (G_GNUC_PRETTY_FUNCTION
245 ": error looking up thread handle %p", handle);
249 /* Hold a reference while the thread is active, because we use
250 * the handle to store thread exit information
252 _wapi_handle_ref (handle);
254 thread_handle->state=THREAD_STATE_START;
256 /* Lock around the thread create, so that the new thread cant
257 * race us to look up the thread handle in GetCurrentThread()
259 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
260 (void *)&thread_hash_mutex);
261 thr_ret = mono_mutex_lock(&thread_hash_mutex);
262 g_assert (thr_ret == 0);
264 /* Set a 2M stack size. This is the default on Linux, but BSD
265 * needs it. (The original bug report from Martin Dvorak <md@9ll.cz>
266 * set the size to 2M-4k. I don't know why it's short by 4k, so
267 * I'm leaving it as 2M until I'm told differently.)
269 thr_ret = pthread_attr_init(&attr);
270 g_assert (thr_ret == 0);
272 /* defaults of 2Mb for 32bits and 4Mb for 64bits */
273 /* temporarily changed to use 1 MB: this allows more threads to be used,
274 * as well as using less virtual memory and so more is available for
278 #if HAVE_VALGRIND_MEMCHECK_H
279 if (RUNNING_ON_VALGRIND)
282 stacksize = (SIZEOF_VOID_P / 4) * 1024 * 1024;
284 stacksize = (SIZEOF_VOID_P / 4) * 1024 * 1024;
289 #ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE
290 thr_ret = pthread_attr_setstacksize(&attr, stacksize);
291 g_assert (thr_ret == 0);
294 ret=_wapi_timed_thread_create(&thread_private_handle->thread, &attr,
295 create, start, thread_exit, param,
299 g_message(G_GNUC_PRETTY_FUNCTION ": Thread create error: %s",
302 /* Two, because of the reference we took above */
304 goto thread_hash_cleanup;
308 g_hash_table_insert(thread_hash, &thread_private_handle->thread->id,
312 g_message(G_GNUC_PRETTY_FUNCTION
313 ": Started thread handle %p thread %p ID %ld", handle,
314 thread_private_handle->thread,
315 thread_private_handle->thread->id);
319 #ifdef PTHREAD_POINTER_ID
320 *tid=GPOINTER_TO_UINT(thread_private_handle->thread->id);
322 *tid=thread_private_handle->thread->id;
327 thr_ret = mono_mutex_unlock (&thread_hash_mutex);
328 g_assert (thr_ret == 0);
329 pthread_cleanup_pop (0);
332 thr_ret = _wapi_handle_unlock_handle (handle);
333 g_assert (thr_ret == 0);
334 pthread_cleanup_pop (0);
336 /* Must not call _wapi_handle_unref() with the handle already
339 for (i = 0; i < unrefs; i++) {
340 _wapi_handle_unref (handle);
346 gpointer OpenThread (guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, guint32 tid)
351 mono_once(&thread_hash_once, thread_hash_init);
352 mono_once (&thread_ops_once, thread_ops_init);
355 g_message (G_GNUC_PRETTY_FUNCTION ": looking up thread %d", tid);
358 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
359 (void *)&thread_hash_mutex);
360 thr_ret = mono_mutex_lock(&thread_hash_mutex);
361 g_assert (thr_ret == 0);
363 ret=g_hash_table_lookup(thread_hash, &tid);
365 thr_ret = mono_mutex_unlock(&thread_hash_mutex);
366 g_assert (thr_ret == 0);
367 pthread_cleanup_pop (0);
370 _wapi_handle_ref (ret);
374 g_message (G_GNUC_PRETTY_FUNCTION ": returning thread handle %p", ret);
382 * @exitcode: Sets the thread's exit code, which can be read from
383 * another thread with GetExitCodeThread().
385 * Terminates the calling thread. A thread can also exit by returning
386 * from its start function. When the last thread in a process
387 * terminates, the process itself terminates.
389 void ExitThread(guint32 exitcode)
391 _wapi_timed_thread_exit(exitcode);
396 * @handle: The thread handle to query
397 * @exitcode: The thread @handle exit code is stored here
399 * Finds the exit code of @handle, and stores it in @exitcode. If the
400 * thread @handle is still running, the value stored is %STILL_ACTIVE.
402 * Return value: %TRUE, or %FALSE on error.
404 gboolean GetExitCodeThread(gpointer handle, guint32 *exitcode)
406 struct _WapiHandle_thread *thread_handle;
407 struct _WapiHandlePrivate_thread *thread_private_handle;
410 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
411 (gpointer *)&thread_handle,
412 (gpointer *)&thread_private_handle);
414 g_warning (G_GNUC_PRETTY_FUNCTION
415 ": error looking up thread handle %p", handle);
420 g_message(G_GNUC_PRETTY_FUNCTION
421 ": Finding exit status for thread handle %p id %ld", handle,
422 thread_private_handle->thread->id);
427 g_message(G_GNUC_PRETTY_FUNCTION
428 ": Nowhere to store exit code");
433 if(thread_handle->state!=THREAD_STATE_EXITED) {
435 g_message(G_GNUC_PRETTY_FUNCTION
436 ": Thread still active (state %d, exited is %d)",
437 thread_handle->state, THREAD_STATE_EXITED);
439 *exitcode=STILL_ACTIVE;
443 *exitcode=thread_handle->exitstatus;
449 * GetCurrentThreadId:
451 * Looks up the thread ID of the current thread. This ID can be
452 * passed to OpenThread() to create a new handle on this thread.
454 * Return value: the thread ID.
456 guint32 GetCurrentThreadId(void)
458 pthread_t tid=pthread_self();
460 #ifdef PTHREAD_POINTER_ID
461 return(GPOINTER_TO_UINT(tid));
467 static gpointer thread_attach(guint32 *tid)
469 struct _WapiHandle_thread *thread_handle;
470 struct _WapiHandlePrivate_thread *thread_private_handle;
476 gpointer ta_ret = NULL;
478 mono_once(&thread_hash_once, thread_hash_init);
479 mono_once (&thread_ops_once, thread_ops_init);
481 handle=_wapi_handle_new (WAPI_HANDLE_THREAD);
482 if(handle==_WAPI_HANDLE_INVALID) {
483 g_warning (G_GNUC_PRETTY_FUNCTION
484 ": error creating thread handle");
488 pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
490 thr_ret = _wapi_handle_lock_handle (handle);
491 g_assert (thr_ret == 0);
493 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
494 (gpointer *)&thread_handle,
495 (gpointer *)&thread_private_handle);
497 g_warning (G_GNUC_PRETTY_FUNCTION
498 ": error looking up thread handle %p", handle);
502 /* Hold a reference while the thread is active, because we use
503 * the handle to store thread exit information
505 _wapi_handle_ref (handle);
507 thread_handle->state=THREAD_STATE_START;
509 /* Lock around the thread create, so that the new thread cant
510 * race us to look up the thread handle in GetCurrentThread()
512 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
513 (void *)&thread_hash_mutex);
514 thr_ret = mono_mutex_lock(&thread_hash_mutex);
515 g_assert (thr_ret == 0);
517 ret=_wapi_timed_thread_attach(&thread_private_handle->thread,
518 thread_exit, handle);
521 g_message(G_GNUC_PRETTY_FUNCTION ": Thread attach error: %s",
524 /* Two, because of the reference we took above */
527 goto thread_hash_cleanup;
531 g_hash_table_insert(thread_hash, &thread_private_handle->thread->id,
535 g_message(G_GNUC_PRETTY_FUNCTION
536 ": Attached thread handle %p thread %p ID %ld", handle,
537 thread_private_handle->thread,
538 thread_private_handle->thread->id);
542 #ifdef PTHREAD_POINTER_ID
543 *tid=GPOINTER_TO_UINT(thread_private_handle->thread->id);
545 *tid=thread_private_handle->thread->id;
550 thr_ret = mono_mutex_unlock (&thread_hash_mutex);
551 g_assert (thr_ret == 0);
552 pthread_cleanup_pop (0);
555 thr_ret = _wapi_handle_unlock_handle (handle);
556 g_assert (thr_ret == 0);
557 pthread_cleanup_pop (0);
559 /* Must not call _wapi_handle_unref() with the handle already
562 for (i = 0; i < unrefs; i++) {
563 _wapi_handle_unref (handle);
572 * Looks up the handle associated with the current thread. Under
573 * Windows this is a pseudohandle, and must be duplicated with
574 * DuplicateHandle() for some operations.
576 * Return value: The current thread handle, or %NULL on failure.
577 * (Unknown whether Windows has a possible failure here. It may be
578 * necessary to implement the pseudohandle-constant behaviour).
580 gpointer GetCurrentThread(void)
586 mono_once(&thread_hash_once, thread_hash_init);
587 mono_once (&thread_ops_once, thread_ops_init);
589 tid=GetCurrentThreadId();
591 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
592 (void *)&thread_hash_mutex);
593 thr_ret = mono_mutex_lock(&thread_hash_mutex);
594 g_assert (thr_ret == 0);
596 ret=g_hash_table_lookup(thread_hash, &tid);
598 thr_ret = mono_mutex_unlock(&thread_hash_mutex);
599 g_assert (thr_ret == 0);
600 pthread_cleanup_pop (0);
603 ret = thread_attach (NULL);
611 * @handle: the thread handle to resume
613 * Decrements the suspend count of thread @handle. A thread can only
614 * run if its suspend count is zero.
616 * Return value: the previous suspend count, or 0xFFFFFFFF on error.
618 guint32 ResumeThread(gpointer handle)
620 struct _WapiHandle_thread *thread_handle;
621 struct _WapiHandlePrivate_thread *thread_private_handle;
624 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
625 (gpointer *)&thread_handle,
626 (gpointer *)&thread_private_handle);
628 g_warning (G_GNUC_PRETTY_FUNCTION
629 ": error looking up thread handle %p", handle);
633 if (thread_private_handle->thread == NULL) {
637 #ifdef WITH_INCLUDED_LIBGC
638 if (thread_private_handle->thread->suspend_count <= 1)
639 _wapi_timed_thread_resume (thread_private_handle->thread);
641 return --thread_private_handle->thread->suspend_count;
643 /* This is still a kludge that only copes with starting a
644 * thread that was suspended on create, so don't bother with
645 * the suspend count crap yet
647 _wapi_timed_thread_resume (thread_private_handle->thread);
654 * @handle: the thread handle to suspend
656 * Increments the suspend count of thread @handle. A thread can only
657 * run if its suspend count is zero.
659 * Return value: the previous suspend count, or 0xFFFFFFFF on error.
661 guint32 SuspendThread(gpointer handle)
663 #ifdef WITH_INCLUDED_LIBGC
664 struct _WapiHandle_thread *thread_handle;
665 struct _WapiHandlePrivate_thread *thread_private_handle;
669 current = GetCurrentThread ();
670 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
671 (gpointer *)&thread_handle,
672 (gpointer *)&thread_private_handle);
674 g_warning (G_GNUC_PRETTY_FUNCTION
675 ": error looking up thread handle %p", handle);
679 if (thread_private_handle->thread == NULL) {
683 if (!thread_private_handle->thread->suspend_count) {
684 if (handle == current)
685 _wapi_timed_thread_suspend (thread_private_handle->thread);
687 pthread_kill (thread_private_handle->thread->id, SIGPWR);
688 while (MONO_SEM_WAIT (&thread_private_handle->thread->suspended_sem) != 0) {
689 if (errno != EINTR) {
696 return thread_private_handle->thread->suspend_count++;
703 * We assume here that TLS_MINIMUM_AVAILABLE is less than
704 * PTHREAD_KEYS_MAX, allowing enough overhead for a few TLS keys for
707 * Currently TLS_MINIMUM_AVAILABLE is 64 and _POSIX_THREAD_KEYS_MAX
708 * (the minimum value for PTHREAD_KEYS_MAX) is 128, so we should be
712 static pthread_key_t TLS_keys[TLS_MINIMUM_AVAILABLE];
713 static gboolean TLS_used[TLS_MINIMUM_AVAILABLE]={FALSE};
714 static guint32 TLS_spinlock=0;
717 mono_pthread_key_for_tls (guint32 idx)
719 return (guint32)TLS_keys [idx];
725 * Allocates a Thread Local Storage (TLS) index. Any thread in the
726 * same process can use this index to store and retrieve values that
727 * are local to that thread.
729 * Return value: The index value, or %TLS_OUT_OF_INDEXES if no index
732 guint32 TlsAlloc(void)
737 MONO_SPIN_LOCK (TLS_spinlock);
739 for(i=0; i<TLS_MINIMUM_AVAILABLE; i++) {
740 if(TLS_used[i]==FALSE) {
742 thr_ret = pthread_key_create(&TLS_keys[i], NULL);
743 g_assert (thr_ret == 0);
745 MONO_SPIN_UNLOCK (TLS_spinlock);
748 g_message (G_GNUC_PRETTY_FUNCTION ": returning key %d",
756 MONO_SPIN_UNLOCK (TLS_spinlock);
759 g_message (G_GNUC_PRETTY_FUNCTION ": out of indices");
763 return(TLS_OUT_OF_INDEXES);
766 #define MAKE_GC_ID(idx) (GUINT_TO_POINTER((idx)|(GetCurrentThreadId()<<8)))
770 * @idx: The TLS index to free
772 * Releases a TLS index, making it available for reuse. This call
773 * will delete any TLS data stored under index @idx in all threads.
775 * Return value: %TRUE on success, %FALSE otherwise.
777 gboolean TlsFree(guint32 idx)
782 g_message (G_GNUC_PRETTY_FUNCTION ": freeing key %d", idx);
785 MONO_SPIN_LOCK (TLS_spinlock);
787 if(TLS_used[idx]==FALSE) {
788 MONO_SPIN_UNLOCK (TLS_spinlock);
794 thr_ret = pthread_key_delete(TLS_keys[idx]);
795 g_assert (thr_ret == 0);
798 mono_g_hash_table_remove (tls_gc_hash, MAKE_GC_ID (idx));
801 MONO_SPIN_UNLOCK (TLS_spinlock);
808 * @idx: The TLS index to retrieve
810 * Retrieves the TLS data stored under index @idx.
812 * Return value: The value stored in the TLS index @idx in the current
813 * thread, or %NULL on error. As %NULL can be a valid return value,
814 * in this case GetLastError() returns %ERROR_SUCCESS.
816 gpointer TlsGetValue(guint32 idx)
821 g_message (G_GNUC_PRETTY_FUNCTION ": looking up key %d", idx);
824 ret=pthread_getspecific(TLS_keys[idx]);
827 g_message (G_GNUC_PRETTY_FUNCTION ": returning %p", ret);
835 * @idx: The TLS index to store
836 * @value: The value to store under index @idx
838 * Stores @value at TLS index @idx.
840 * Return value: %TRUE on success, %FALSE otherwise.
842 gboolean TlsSetValue(guint32 idx, gpointer value)
847 g_message (G_GNUC_PRETTY_FUNCTION ": setting key %d to %p", idx,
851 MONO_SPIN_LOCK (TLS_spinlock);
853 if(TLS_used[idx]==FALSE) {
855 g_message (G_GNUC_PRETTY_FUNCTION ": key %d unused", idx);
858 MONO_SPIN_UNLOCK (TLS_spinlock);
863 ret=pthread_setspecific(TLS_keys[idx], value);
866 g_message (G_GNUC_PRETTY_FUNCTION
867 ": pthread_setspecific error: %s", strerror (ret));
870 MONO_SPIN_UNLOCK (TLS_spinlock);
877 MONO_GC_REGISTER_ROOT (tls_gc_hash);
878 tls_gc_hash = mono_g_hash_table_new(g_direct_hash, g_direct_equal);
880 mono_g_hash_table_insert (tls_gc_hash, MAKE_GC_ID (idx), value);
883 MONO_SPIN_UNLOCK (TLS_spinlock);
890 * @ms: The time in milliseconds to suspend for
891 * @alertable: if TRUE, the wait can be interrupted by an APC call
893 * Suspends execution of the current thread for @ms milliseconds. A
894 * value of zero causes the thread to relinquish its time slice. A
895 * value of %INFINITE causes an infinite delay.
897 guint32 SleepEx(guint32 ms, gboolean alertable)
899 struct timespec req, rem;
902 gpointer current_thread = NULL;
905 g_message(G_GNUC_PRETTY_FUNCTION ": Sleeping for %d ms", ms);
909 current_thread = GetCurrentThread ();
910 if (_wapi_thread_apc_pending (current_thread)) {
911 _wapi_thread_dispatch_apc_queue (current_thread);
912 return WAIT_IO_COMPLETION;
921 /* FIXME: check for INFINITE and sleep forever */
926 req.tv_nsec=ms_rem*1000000;
929 ret=nanosleep(&req, &rem);
931 if (alertable && _wapi_thread_apc_pending (current_thread)) {
932 _wapi_thread_dispatch_apc_queue (current_thread);
933 return WAIT_IO_COMPLETION;
937 /* Sleep interrupted with rem time remaining */
939 guint32 rems=rem.tv_sec*1000 + rem.tv_nsec/1000000;
941 g_message(G_GNUC_PRETTY_FUNCTION ": Still got %d ms to go",
951 void Sleep(guint32 ms)
957 BindIoCompletionCallback (gpointer handle,
958 WapiOverlappedCB callback,
963 type = _wapi_handle_type (handle);
964 if (type == WAPI_HANDLE_FILE || type == WAPI_HANDLE_PIPE)
965 return _wapi_io_add_callback (handle, callback, flags);
967 SetLastError (ERROR_NOT_SUPPORTED);
971 guint32 QueueUserAPC (WapiApcProc apc_callback, gpointer handle,
974 struct _WapiHandle_thread *thread_handle;
975 struct _WapiHandlePrivate_thread *thread_private_handle;
978 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
979 (gpointer *)&thread_handle,
980 (gpointer *)&thread_private_handle);
982 g_warning (G_GNUC_PRETTY_FUNCTION
983 ": error looking up thread handle %p", handle);
987 _wapi_timed_thread_queue_apc (thread_private_handle->thread,
988 apc_callback, param);
992 gboolean _wapi_thread_cur_apc_pending (void)
994 return _wapi_thread_apc_pending (GetCurrentThread ());
997 gboolean _wapi_thread_apc_pending (gpointer handle)
999 struct _WapiHandle_thread *thread_handle;
1000 struct _WapiHandlePrivate_thread *thread_private_handle;
1003 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
1004 (gpointer *)&thread_handle,
1005 (gpointer *)&thread_private_handle);
1007 g_warning (G_GNUC_PRETTY_FUNCTION
1008 ": error looking up thread handle %p", handle);
1012 return _wapi_timed_thread_apc_pending (thread_private_handle->thread);
1015 gboolean _wapi_thread_dispatch_apc_queue (gpointer handle)
1017 struct _WapiHandle_thread *thread_handle;
1018 struct _WapiHandlePrivate_thread *thread_private_handle;
1021 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
1022 (gpointer *)&thread_handle,
1023 (gpointer *)&thread_private_handle);
1025 g_warning (G_GNUC_PRETTY_FUNCTION
1026 ": error looking up thread handle %p", handle);
1030 _wapi_timed_thread_dispatch_apc_queue (thread_private_handle->thread);
1036 #ifdef WITH_INCLUDED_LIBGC
1038 static void GC_suspend_handler (int sig)
1040 struct _WapiHandle_thread *thread_handle;
1041 struct _WapiHandlePrivate_thread *thread_private_handle;
1045 handle = GetCurrentThread ();
1046 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
1047 (gpointer *)&thread_handle,
1048 (gpointer *)&thread_private_handle);
1050 g_warning (G_GNUC_PRETTY_FUNCTION
1051 ": error looking up thread handle %p", handle);
1055 thread_private_handle->thread->stack_ptr = &ok;
1056 MONO_SEM_POST (&thread_private_handle->thread->suspended_sem);
1058 _wapi_timed_thread_suspend (thread_private_handle->thread);
1060 thread_private_handle->thread->stack_ptr = NULL;
1063 static void gc_init (void)
1065 struct sigaction act;
1067 act.sa_handler = GC_suspend_handler;
1068 g_assert (sigaction (SIGPWR, &act, NULL) == 0);
1071 void mono_wapi_push_thread_stack (gpointer handle, gpointer stack_ptr)
1073 struct _WapiHandle_thread *thread_handle;
1074 struct _WapiHandlePrivate_thread *thread_private_handle;
1077 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
1078 (gpointer *)&thread_handle,
1079 (gpointer *)&thread_private_handle);
1081 g_warning (G_GNUC_PRETTY_FUNCTION
1082 ": error looking up thread handle %p", handle);
1086 GC_push_all_stack (thread_private_handle->thread->stack_ptr, stack_ptr);
1089 #endif /* WITH_INCLUDED_LIBGC */