Flush
[mono.git] / mono / io-layer / threads.c
index 877e0245a60b6cd94dd5b747a03a6345698762ed..c2425ae01bf37ed44557a677dd0562c066b44b26 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>
 #include <mono/io-layer/thread-private.h>
 #include <mono/io-layer/mono-spinlock.h>
 
+#if HAVE_VALGRIND_MEMCHECK_H
+#include <valgrind/memcheck.h>
+#endif
+
 #undef DEBUG
 #undef TLS_DEBUG
 
@@ -261,8 +266,17 @@ gpointer CreateThread(WapiSecurityAttributes *security G_GNUC_UNUSED, guint32 st
        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
        thr_ret = pthread_attr_setstacksize(&attr, stacksize);
@@ -844,26 +858,36 @@ gboolean TlsSetValue(guint32 idx, gpointer value)
 }
 
 /**
- * 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;
        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 */
@@ -875,6 +899,12 @@ void Sleep(guint32 ms)
        
 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
@@ -886,16 +916,13 @@ 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");
-       }
-       
-       Sleep(ms);
+       SleepEx(ms, FALSE);
 }
 
 gboolean
@@ -913,6 +940,71 @@ BindIoCompletionCallback (gpointer handle,
        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)