2005-02-05 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mono / io-layer / threads.c
index 6262fe8e15c0644572f8fd8c3d079321512264c4..f464f0b94230e4f83d2dcb43c2636bb23e2aa0d9 100644 (file)
@@ -12,6 +12,7 @@
 #include <mono/os/gc_wrapper.h>
 #include "mono/utils/mono-hash.h"
 #endif
+#include <stdio.h>
 #include <glib.h>
 #include <string.h>
 #include <pthread.h>
@@ -19,6 +20,8 @@
 #include <sched.h>
 #include <sys/time.h>
 #include <errno.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 #include <mono/io-layer/wapi.h>
 #include <mono/io-layer/wapi-private.h>
 #include <mono/io-layer/mono-mutex.h>
 #include <mono/io-layer/thread-private.h>
 #include <mono/io-layer/mono-spinlock.h>
+#include <mono/io-layer/mutex-private.h>
+
+#if HAVE_VALGRIND_MEMCHECK_H
+#include <valgrind/memcheck.h>
+#endif
 
 #undef DEBUG
 #undef TLS_DEBUG
-#undef TLS_PTHREAD_MUTEX
 
 
 /* Hash threads with tids. I thought of using TLS for this, but that
@@ -92,9 +99,7 @@ static void thread_close_private (gpointer handle)
                  thread_handle->thread->id);
 #endif
 
-       if(thread_handle->thread!=NULL) {
-               _wapi_timed_thread_destroy (thread_handle->thread);
-       }
+       thread_handle->thread=NULL;
 }
 
 static void thread_own (gpointer handle)
@@ -124,6 +129,7 @@ static void thread_exit(guint32 exitstatus, gpointer handle)
        struct _WapiHandle_thread *thread_handle;
        struct _WapiHandlePrivate_thread *thread_private_handle;
        gboolean ok;
+       int thr_ret;
        
        ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
                                (gpointer *)&thread_handle,
@@ -133,8 +139,14 @@ static void thread_exit(guint32 exitstatus, gpointer handle)
                           ": error looking up thread handle %p", handle);
                return;
        }
+       
+       _wapi_mutex_check_abandoned (getpid (),
+                                    thread_private_handle->thread->id);
 
-       _wapi_handle_lock_handle (handle);
+       pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
+                             handle);
+       thr_ret = _wapi_handle_lock_handle (handle);
+       g_assert (thr_ret == 0);
 
 #ifdef DEBUG
        g_message (G_GNUC_PRETTY_FUNCTION
@@ -145,7 +157,9 @@ static void thread_exit(guint32 exitstatus, gpointer handle)
        thread_handle->state=THREAD_STATE_EXITED;
        _wapi_handle_set_signal_state (handle, TRUE, TRUE);
 
-       _wapi_handle_unlock_handle (handle);
+       thr_ret = _wapi_handle_unlock_handle (handle);
+       g_assert (thr_ret == 0);
+       pthread_cleanup_pop (0);
        
 #ifdef DEBUG
        g_message(G_GNUC_PRETTY_FUNCTION
@@ -154,9 +168,16 @@ static void thread_exit(guint32 exitstatus, gpointer handle)
 #endif
 
        /* Remove this thread from the hash */
-       mono_mutex_lock(&thread_hash_mutex);
+       pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
+                             (void *)&thread_hash_mutex);
+       thr_ret = mono_mutex_lock(&thread_hash_mutex);
+       g_assert (thr_ret == 0);
+       
        g_hash_table_remove(thread_hash, &thread_private_handle->thread->id);
-       mono_mutex_unlock(&thread_hash_mutex);
+
+       thr_ret = mono_mutex_unlock(&thread_hash_mutex);
+       g_assert (thr_ret == 0);
+       pthread_cleanup_pop (0);
 
        /* The thread is no longer active, so unref it */
        _wapi_handle_unref (handle);
@@ -193,6 +214,9 @@ gpointer CreateThread(WapiSecurityAttributes *security G_GNUC_UNUSED, guint32 st
        gpointer handle;
        gboolean ok;
        int ret;
+       int thr_ret;
+       int i, unrefs = 0;
+       gpointer ct_ret = NULL;
        
        mono_once(&thread_hash_once, thread_hash_init);
        mono_once (&thread_ops_once, thread_ops_init);
@@ -208,7 +232,10 @@ gpointer CreateThread(WapiSecurityAttributes *security G_GNUC_UNUSED, guint32 st
                return(NULL);
        }
 
-       _wapi_handle_lock_handle (handle);
+       pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
+                             handle);
+       thr_ret = _wapi_handle_lock_handle (handle);
+       g_assert (thr_ret == 0);
        
        ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
                                (gpointer *)&thread_handle,
@@ -216,8 +243,7 @@ gpointer CreateThread(WapiSecurityAttributes *security G_GNUC_UNUSED, guint32 st
        if(ok==FALSE) {
                g_warning (G_GNUC_PRETTY_FUNCTION
                           ": error looking up thread handle %p", handle);
-               _wapi_handle_unlock_handle (handle);
-               return(NULL);
+               goto cleanup;
        }
 
        /* Hold a reference while the thread is active, because we use
@@ -230,20 +256,35 @@ gpointer CreateThread(WapiSecurityAttributes *security G_GNUC_UNUSED, guint32 st
        /* Lock around the thread create, so that the new thread cant
         * race us to look up the thread handle in GetCurrentThread()
         */
-       mono_mutex_lock(&thread_hash_mutex);
+       pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
+                             (void *)&thread_hash_mutex);
+       thr_ret = mono_mutex_lock(&thread_hash_mutex);
+       g_assert (thr_ret == 0);
        
        /* Set a 2M stack size.  This is the default on Linux, but BSD
         * needs it.  (The original bug report from Martin Dvorak <md@9ll.cz>
         * set the size to 2M-4k.  I don't know why it's short by 4k, so
         * I'm leaving it as 2M until I'm told differently.)
         */
-       pthread_attr_init(&attr);
+       thr_ret = pthread_attr_init(&attr);
+       g_assert (thr_ret == 0);
+       
        /* defaults of 2Mb for 32bits and 4Mb for 64bits */
-       if (stacksize == 0)
-               stacksize = (SIZEOF_VOID_P / 2) * 1024 *1024;
+       if (stacksize == 0){
+#if HAVE_VALGRIND_MEMCHECK_H
+               if (RUNNING_ON_VALGRIND)
+                       stacksize = 1 << 20;
+               else
+                       stacksize = (SIZEOF_VOID_P / 2) * 1024 * 1024;
+#else
+               stacksize = (SIZEOF_VOID_P / 2) * 1024 * 1024;
+#endif
+               
+       }
 
 #ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE
-       pthread_attr_setstacksize(&attr, stacksize);
+       thr_ret = pthread_attr_setstacksize(&attr, stacksize);
+       g_assert (thr_ret == 0);
 #endif
 
        ret=_wapi_timed_thread_create(&thread_private_handle->thread, &attr,
@@ -254,18 +295,14 @@ gpointer CreateThread(WapiSecurityAttributes *security G_GNUC_UNUSED, guint32 st
                g_message(G_GNUC_PRETTY_FUNCTION ": Thread create error: %s",
                          strerror(ret));
 #endif
-               mono_mutex_unlock(&thread_hash_mutex);
-               _wapi_handle_unlock_handle (handle);
-               _wapi_handle_unref (handle);
-               
-               /* And again, because of the reference we took above */
-               _wapi_handle_unref (handle);
-               return(NULL);
+               /* Two, because of the reference we took above */
+               unrefs = 2;
+               goto thread_hash_cleanup;
        }
-
+       ct_ret = handle;
+       
        g_hash_table_insert(thread_hash, &thread_private_handle->thread->id,
                            handle);
-       mono_mutex_unlock(&thread_hash_mutex);
        
 #ifdef DEBUG
        g_message(G_GNUC_PRETTY_FUNCTION
@@ -282,14 +319,30 @@ gpointer CreateThread(WapiSecurityAttributes *security G_GNUC_UNUSED, guint32 st
 #endif
        }
 
-       _wapi_handle_unlock_handle (handle);
+thread_hash_cleanup:
+       thr_ret = mono_mutex_unlock (&thread_hash_mutex);
+       g_assert (thr_ret == 0);
+       pthread_cleanup_pop (0);
        
-       return(handle);
+cleanup:
+       thr_ret = _wapi_handle_unlock_handle (handle);
+       g_assert (thr_ret == 0);
+       pthread_cleanup_pop (0);
+       
+       /* Must not call _wapi_handle_unref() with the handle already
+        * locked
+        */
+       for (i = 0; i < unrefs; i++) {
+               _wapi_handle_unref (handle);
+       }
+
+       return(ct_ret);
 }
 
 gpointer OpenThread (guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, guint32 tid)
 {
        gpointer ret=NULL;
+       int thr_ret;
        
        mono_once(&thread_hash_once, thread_hash_init);
        mono_once (&thread_ops_once, thread_ops_init);
@@ -298,10 +351,16 @@ gpointer OpenThread (guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSE
        g_message (G_GNUC_PRETTY_FUNCTION ": looking up thread %d", tid);
 #endif
 
-       mono_mutex_lock(&thread_hash_mutex);
+       pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
+                             (void *)&thread_hash_mutex);
+       thr_ret = mono_mutex_lock(&thread_hash_mutex);
+       g_assert (thr_ret == 0);
        
        ret=g_hash_table_lookup(thread_hash, &tid);
-       mono_mutex_unlock(&thread_hash_mutex);
+
+       thr_ret = mono_mutex_unlock(&thread_hash_mutex);
+       g_assert (thr_ret == 0);
+       pthread_cleanup_pop (0);
        
        if(ret!=NULL) {
                _wapi_handle_ref (ret);
@@ -408,7 +467,10 @@ static gpointer thread_attach(guint32 *tid)
        gpointer handle;
        gboolean ok;
        int ret;
-
+       int thr_ret;
+       int i, unrefs = 0;
+       gpointer ta_ret = NULL;
+       
        mono_once(&thread_hash_once, thread_hash_init);
        mono_once (&thread_ops_once, thread_ops_init);
 
@@ -419,7 +481,10 @@ static gpointer thread_attach(guint32 *tid)
                return(NULL);
        }
 
-       _wapi_handle_lock_handle (handle);
+       pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
+                             handle);
+       thr_ret = _wapi_handle_lock_handle (handle);
+       g_assert (thr_ret == 0);
 
        ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
                                (gpointer *)&thread_handle,
@@ -427,8 +492,7 @@ static gpointer thread_attach(guint32 *tid)
        if(ok==FALSE) {
                g_warning (G_GNUC_PRETTY_FUNCTION
                           ": error looking up thread handle %p", handle);
-               _wapi_handle_unlock_handle (handle);
-               return(NULL);
+               goto cleanup;
        }
 
        /* Hold a reference while the thread is active, because we use
@@ -441,7 +505,10 @@ static gpointer thread_attach(guint32 *tid)
        /* Lock around the thread create, so that the new thread cant
         * race us to look up the thread handle in GetCurrentThread()
         */
-       mono_mutex_lock(&thread_hash_mutex);
+       pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
+                             (void *)&thread_hash_mutex);
+       thr_ret = mono_mutex_lock(&thread_hash_mutex);
+       g_assert (thr_ret == 0);
 
        ret=_wapi_timed_thread_attach(&thread_private_handle->thread,
                                      thread_exit, handle);
@@ -450,18 +517,15 @@ static gpointer thread_attach(guint32 *tid)
                g_message(G_GNUC_PRETTY_FUNCTION ": Thread attach error: %s",
                          strerror(ret));
 #endif
-               mono_mutex_unlock(&thread_hash_mutex);
-               _wapi_handle_unlock_handle (handle);
-               _wapi_handle_unref (handle);
+               /* Two, because of the reference we took above */
+               unrefs = 2;
 
-               /* And again, because of the reference we took above */
-               _wapi_handle_unref (handle);
-               return(NULL);
+               goto thread_hash_cleanup;
        }
-
+       ta_ret = handle;
+       
        g_hash_table_insert(thread_hash, &thread_private_handle->thread->id,
                            handle);
-       mono_mutex_unlock(&thread_hash_mutex);
 
 #ifdef DEBUG
        g_message(G_GNUC_PRETTY_FUNCTION
@@ -478,9 +542,24 @@ static gpointer thread_attach(guint32 *tid)
 #endif
        }
 
-       _wapi_handle_unlock_handle (handle);
+thread_hash_cleanup:
+       thr_ret = mono_mutex_unlock (&thread_hash_mutex);
+       g_assert (thr_ret == 0);
+       pthread_cleanup_pop (0);
+       
+cleanup:
+       thr_ret = _wapi_handle_unlock_handle (handle);
+       g_assert (thr_ret == 0);
+       pthread_cleanup_pop (0);
 
-       return(handle);
+       /* Must not call _wapi_handle_unref() with the handle already
+        * locked
+        */
+       for (i = 0; i < unrefs; i++) {
+               _wapi_handle_unref (handle);
+       }
+       
+       return(ta_ret);
 }
 
 /**
@@ -498,16 +577,23 @@ gpointer GetCurrentThread(void)
 {
        gpointer ret=NULL;
        guint32 tid;
+       int thr_ret;
        
        mono_once(&thread_hash_once, thread_hash_init);
        mono_once (&thread_ops_once, thread_ops_init);
        
        tid=GetCurrentThreadId();
        
-       mono_mutex_lock(&thread_hash_mutex);
+       pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
+                             (void *)&thread_hash_mutex);
+       thr_ret = mono_mutex_lock(&thread_hash_mutex);
+       g_assert (thr_ret == 0);
 
        ret=g_hash_table_lookup(thread_hash, &tid);
-       mono_mutex_unlock(&thread_hash_mutex);
+
+       thr_ret = mono_mutex_unlock(&thread_hash_mutex);
+       g_assert (thr_ret == 0);
+       pthread_cleanup_pop (0);
        
        if (!ret) {
                ret = thread_attach (NULL);
@@ -540,6 +626,10 @@ guint32 ResumeThread(gpointer handle)
                return(0xFFFFFFFF);
        }
 
+       if (thread_private_handle->thread == NULL) {
+               return(0xFFFFFFFF);
+       }
+
 #ifdef WITH_INCLUDED_LIBGC
        if (thread_private_handle->thread->suspend_count <= 1)
                _wapi_timed_thread_resume (thread_private_handle->thread);
@@ -582,12 +672,20 @@ guint32 SuspendThread(gpointer handle)
                return(0xFFFFFFFF);
        }
 
+       if (thread_private_handle->thread == NULL) {
+               return(0xFFFFFFFF);
+       }
+
        if (!thread_private_handle->thread->suspend_count) {
                if (handle == current)
                        _wapi_timed_thread_suspend (thread_private_handle->thread);
                else {
                        pthread_kill (thread_private_handle->thread->id, SIGPWR);
-                       sem_wait (&thread_private_handle->thread->suspended_sem);
+                       while (MONO_SEM_WAIT (&thread_private_handle->thread->suspended_sem) != 0) {
+                               if (errno != EINTR) {
+                                       return(0xFFFFFFFF);
+                               }
+                       }
                }
        }
 
@@ -609,11 +707,13 @@ guint32 SuspendThread(gpointer handle)
 
 static pthread_key_t TLS_keys[TLS_MINIMUM_AVAILABLE];
 static gboolean TLS_used[TLS_MINIMUM_AVAILABLE]={FALSE};
-#ifdef TLS_PTHREAD_MUTEX
-static mono_mutex_t TLS_mutex=MONO_MUTEX_INITIALIZER;
-#else
 static guint32 TLS_spinlock=0;
-#endif
+
+guint32
+mono_pthread_key_for_tls (guint32 idx)
+{
+       return (guint32)TLS_keys [idx];
+}
 
 /**
  * TlsAlloc:
@@ -628,23 +728,17 @@ static guint32 TLS_spinlock=0;
 guint32 TlsAlloc(void)
 {
        guint32 i;
+       int thr_ret;
        
-#ifdef TLS_PTHREAD_MUTEX
-       mono_mutex_lock(&TLS_mutex);
-#else
        MONO_SPIN_LOCK (TLS_spinlock);
-#endif
        
        for(i=0; i<TLS_MINIMUM_AVAILABLE; i++) {
                if(TLS_used[i]==FALSE) {
                        TLS_used[i]=TRUE;
-                       pthread_key_create(&TLS_keys[i], NULL);
+                       thr_ret = pthread_key_create(&TLS_keys[i], NULL);
+                       g_assert (thr_ret == 0);
 
-#ifdef TLS_PTHREAD_MUTEX
-                       mono_mutex_unlock(&TLS_mutex);
-#else
                        MONO_SPIN_UNLOCK (TLS_spinlock);
-#endif
        
 #ifdef TLS_DEBUG
                        g_message (G_GNUC_PRETTY_FUNCTION ": returning key %d",
@@ -655,11 +749,7 @@ guint32 TlsAlloc(void)
                }
        }
 
-#ifdef TLS_PTHREAD_MUTEX
-       mono_mutex_unlock(&TLS_mutex);
-#else
        MONO_SPIN_UNLOCK (TLS_spinlock);
-#endif
        
 #ifdef TLS_DEBUG
        g_message (G_GNUC_PRETTY_FUNCTION ": out of indices");
@@ -682,37 +772,29 @@ guint32 TlsAlloc(void)
  */
 gboolean TlsFree(guint32 idx)
 {
+       int thr_ret;
+       
 #ifdef TLS_DEBUG
        g_message (G_GNUC_PRETTY_FUNCTION ": freeing key %d", idx);
 #endif
 
-#ifdef TLS_PTHREAD_MUTEX
-       mono_mutex_lock(&TLS_mutex);
-#else
        MONO_SPIN_LOCK (TLS_spinlock);
-#endif
        
        if(TLS_used[idx]==FALSE) {
-#ifdef TLS_PTHREAD_MUTEX
-               mono_mutex_unlock(&TLS_mutex);
-#else
                MONO_SPIN_UNLOCK (TLS_spinlock);
-#endif
+
                return(FALSE);
        }
        
        TLS_used[idx]=FALSE;
-       pthread_key_delete(TLS_keys[idx]);
+       thr_ret = pthread_key_delete(TLS_keys[idx]);
+       g_assert (thr_ret == 0);
        
 #if HAVE_BOEHM_GC
        mono_g_hash_table_remove (tls_gc_hash, MAKE_GC_ID (idx));
 #endif
 
-#ifdef TLS_PTHREAD_MUTEX
-       mono_mutex_unlock(&TLS_mutex);
-#else
        MONO_SPIN_UNLOCK (TLS_spinlock);
-#endif
        
        return(TRUE);
 }
@@ -762,22 +844,15 @@ gboolean TlsSetValue(guint32 idx, gpointer value)
                   value);
 #endif
        
-#ifdef TLS_PTHREAD_MUTEX
-       mono_mutex_lock(&TLS_mutex);
-#else
        MONO_SPIN_LOCK (TLS_spinlock);
-#endif
        
        if(TLS_used[idx]==FALSE) {
 #ifdef TLS_DEBUG
                g_message (G_GNUC_PRETTY_FUNCTION ": key %d unused", idx);
 #endif
 
-#ifdef TLS_PTHREAD_MUTEX
-               mono_mutex_unlock(&TLS_mutex);
-#else
                MONO_SPIN_UNLOCK (TLS_spinlock);
-#endif
+
                return(FALSE);
        }
        
@@ -788,60 +863,72 @@ gboolean TlsSetValue(guint32 idx, gpointer value)
                           ": pthread_setspecific error: %s", strerror (ret));
 #endif
 
-#ifdef TLS_PTHREAD_MUTEX
-               mono_mutex_unlock(&TLS_mutex);
-#else
                MONO_SPIN_UNLOCK (TLS_spinlock);
-#endif
+
                return(FALSE);
        }
        
 #if HAVE_BOEHM_GC
-       if (!tls_gc_hash)
+       if (!tls_gc_hash) {
+               MONO_GC_REGISTER_ROOT (tls_gc_hash);
                tls_gc_hash = mono_g_hash_table_new(g_direct_hash, g_direct_equal);
+       }
        mono_g_hash_table_insert (tls_gc_hash, MAKE_GC_ID (idx), value);
 #endif
 
-#ifdef TLS_PTHREAD_MUTEX
-       mono_mutex_unlock(&TLS_mutex);
-#else
        MONO_SPIN_UNLOCK (TLS_spinlock);
-#endif
        
        return(TRUE);
 }
 
 /**
- * Sleep:
+ * SleepEx:
  * @ms: The time in milliseconds to suspend for
+ * @alertable: if TRUE, the wait can be interrupted by an APC call
  *
  * Suspends execution of the current thread for @ms milliseconds.  A
  * value of zero causes the thread to relinquish its time slice.  A
  * value of %INFINITE causes an infinite delay.
  */
-void Sleep(guint32 ms)
+guint32 SleepEx(guint32 ms, gboolean alertable)
 {
        struct timespec req, rem;
-       div_t divvy;
+       int ms_quot, ms_rem;
        int ret;
+       gpointer current_thread = NULL;
        
 #ifdef DEBUG
        g_message(G_GNUC_PRETTY_FUNCTION ": Sleeping for %d ms", ms);
 #endif
 
+       if (alertable) {
+               current_thread = GetCurrentThread ();
+               if (_wapi_thread_apc_pending (current_thread)) {
+                       _wapi_thread_dispatch_apc_queue (current_thread);
+                       return WAIT_IO_COMPLETION;
+               }
+       }
+       
        if(ms==0) {
                sched_yield();
-               return;
+               return 0;
        }
        
        /* FIXME: check for INFINITE and sleep forever */
-       divvy=div((int)ms, 1000);
+       ms_quot = ms / 1000;
+       ms_rem = ms % 1000;
        
-       req.tv_sec=divvy.quot;
-       req.tv_nsec=divvy.rem*1000000;
+       req.tv_sec=ms_quot;
+       req.tv_nsec=ms_rem*1000000;
        
 again:
        ret=nanosleep(&req, &rem);
+
+       if (alertable && _wapi_thread_apc_pending (current_thread)) {
+               _wapi_thread_dispatch_apc_queue (current_thread);
+               return WAIT_IO_COMPLETION;
+       }
+       
        if(ret==-1) {
                /* Sleep interrupted with rem time remaining */
 #ifdef DEBUG
@@ -853,18 +940,95 @@ again:
                req=rem;
                goto again;
        }
+
+       return 0;
 }
 
-/* FIXME: implement alertable */
-void SleepEx(guint32 ms, gboolean alertable)
+void Sleep(guint32 ms)
 {
-       if(alertable==TRUE) {
-               g_warning(G_GNUC_PRETTY_FUNCTION ": alertable not implemented");
-       }
+       SleepEx(ms, FALSE);
+}
+
+gboolean
+BindIoCompletionCallback (gpointer handle,
+                         WapiOverlappedCB callback,
+                         guint64 flags)
+{
+       WapiHandleType type;
        
-       Sleep(ms);
+       type = _wapi_handle_type (handle);
+       if (type == WAPI_HANDLE_FILE || type == WAPI_HANDLE_PIPE)
+               return _wapi_io_add_callback (handle, callback, flags);
+
+       SetLastError (ERROR_NOT_SUPPORTED);
+       return FALSE;
+}
+
+guint32 QueueUserAPC (WapiApcProc apc_callback, gpointer handle, 
+                                       gpointer param)
+{
+       struct _WapiHandle_thread *thread_handle;
+       struct _WapiHandlePrivate_thread *thread_private_handle;
+       gboolean ok;
+
+       ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
+                               (gpointer *)&thread_handle,
+                               (gpointer *)&thread_private_handle);
+       if(ok==FALSE) {
+               g_warning (G_GNUC_PRETTY_FUNCTION
+                          ": error looking up thread handle %p", handle);
+               return(0);
+       }
+
+       _wapi_timed_thread_queue_apc (thread_private_handle->thread, 
+                                                       apc_callback, param);
+       return(1);
+}
+
+gboolean _wapi_thread_cur_apc_pending (void)
+{
+       return _wapi_thread_apc_pending (GetCurrentThread ());
+}
+
+gboolean _wapi_thread_apc_pending (gpointer handle)
+{
+       struct _WapiHandle_thread *thread_handle;
+       struct _WapiHandlePrivate_thread *thread_private_handle;
+       gboolean ok;
+
+       ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
+                               (gpointer *)&thread_handle,
+                               (gpointer *)&thread_private_handle);
+       if(ok==FALSE) {
+               g_warning (G_GNUC_PRETTY_FUNCTION
+                          ": error looking up thread handle %p", handle);
+               return(FALSE);
+       }
+
+       return _wapi_timed_thread_apc_pending (thread_private_handle->thread);
 }
 
+gboolean _wapi_thread_dispatch_apc_queue (gpointer handle)
+{
+       struct _WapiHandle_thread *thread_handle;
+       struct _WapiHandlePrivate_thread *thread_private_handle;
+       gboolean ok;
+
+       ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
+                               (gpointer *)&thread_handle,
+                               (gpointer *)&thread_private_handle);
+       if(ok==FALSE) {
+               g_warning (G_GNUC_PRETTY_FUNCTION
+                          ": error looking up thread handle %p", handle);
+               return(0);
+       }
+
+       _wapi_timed_thread_dispatch_apc_queue (thread_private_handle->thread);
+       return(1);
+}
+
+
+
 #ifdef WITH_INCLUDED_LIBGC
 
 static void GC_suspend_handler (int sig)
@@ -885,7 +1049,7 @@ static void GC_suspend_handler (int sig)
        }
 
        thread_private_handle->thread->stack_ptr = &ok;
-       sem_post (&thread_private_handle->thread->suspended_sem);
+       MONO_SEM_POST (&thread_private_handle->thread->suspended_sem);
 
        _wapi_timed_thread_suspend (thread_private_handle->thread);