Interruptible FFI calls with pthread_kill and CancelSynchronousIO. v4
[ghc-hetmet.git] / rts / win32 / OSThreads.c
index 00effda..44db42f 100644 (file)
@@ -7,10 +7,12 @@
  *
  * --------------------------------------------------------------------------*/
 
+#define _WIN32_WINNT 0x0500
+
 #include "Rts.h"
 #if defined(THREADED_RTS)
-#include "OSThreads.h"
 #include "RtsUtils.h"
+#include <windows.h>
 
 /* For reasons not yet clear, the entire contents of process.h is protected 
  * by __STRICT_ANSI__ not being defined.
@@ -38,7 +40,8 @@ initCondition( Condition* pCond )
                          NULL); /* unnamed => process-local. */
   
   if ( h == NULL ) {
-    errorBelch("initCondition: unable to create");
+      sysErrorBelch("initCondition: unable to create");
+      stg_exit(EXIT_FAILURE);
   }
   *pCond = h;
   return;
@@ -48,7 +51,7 @@ void
 closeCondition( Condition* pCond )
 {
   if ( CloseHandle(*pCond) == 0 ) {
-    errorBelch("closeCondition: failed to close");
+      sysErrorBelch("closeCondition: failed to close");
   }
   return;
 }
@@ -64,7 +67,8 @@ rtsBool
 signalCondition ( Condition* pCond )
 {
     if (SetEvent(*pCond) == 0) {
-       barf("SetEvent: %d", GetLastError());
+       sysErrorBelch("SetEvent");
+       stg_exit(EXIT_FAILURE);
     }
     return rtsTrue;
 }
@@ -82,7 +86,7 @@ waitCondition ( Condition* pCond, Mutex* pMut )
 void
 yieldThread()
 {
-  Sleep(0);
+  SwitchToThread();
   return;
 }
 
@@ -90,6 +94,7 @@ void
 shutdownThread()
 {
   _endthreadex(0);
+  barf("_endthreadex returned"); // avoid gcc warning
 }
 
 int
@@ -110,6 +115,22 @@ osThreadId()
   return GetCurrentThreadId();
 }
 
+rtsBool
+osThreadIsAlive(OSThreadId id)
+{
+    DWORD exit_code;
+    HANDLE hdl;
+    if (!(hdl = OpenThread(THREAD_QUERY_INFORMATION,FALSE,id))) {
+        sysErrorBelch("osThreadIsAlive: OpenThread");
+        stg_exit(EXIT_FAILURE);
+    }
+    if (!GetExitCodeThread(hdl, &exit_code)) {
+        sysErrorBelch("osThreadIsAlive: GetExitCodeThread");
+        stg_exit(EXIT_FAILURE);
+    }
+    return (exit_code == STILL_ACTIVE);
+}
+
 #ifdef USE_CRITICAL_SECTIONS
 void
 initMutex (Mutex* pMut)
@@ -159,7 +180,8 @@ getThreadLocalVar (ThreadLocalKey *key)
     // r is allowed to be NULL - it can mean that either there was an
     // error or the stored value is in fact NULL.
     if (GetLastError() != NO_ERROR) {
-       barf("getThreadLocalVar: key not found");
+       sysErrorBelch("getThreadLocalVar");
+        stg_exit(EXIT_FAILURE);
     }
 #endif
     return r;
@@ -171,7 +193,19 @@ setThreadLocalVar (ThreadLocalKey *key, void *value)
     BOOL b;
     b = TlsSetValue(*key, value);
     if (!b) {
-       barf("setThreadLocalVar: %d", GetLastError());
+       sysErrorBelch("setThreadLocalVar");
+        stg_exit(EXIT_FAILURE);
+    }
+}
+
+void
+freeThreadLocalKey (ThreadLocalKey *key)
+{
+    BOOL r;
+    r = TlsFree(*key);
+    if (r == 0) {
+        DWORD dw = GetLastError();
+       barf("freeThreadLocalKey failed: %lu", dw);
     }
 }
 
@@ -198,6 +232,62 @@ forkOS_createThread ( HsStablePtr entry )
                           (unsigned*)&pId) == 0);
 }
 
+nat
+getNumberOfProcessors (void)
+{
+    static nat nproc = 0;
+
+    if (nproc == 0) {
+        SYSTEM_INFO si;
+        GetSystemInfo(&si);
+        nproc = si.dwNumberOfProcessors;
+    }
+
+    return nproc;
+}
+
+void
+setThreadAffinity (nat n, nat m) // cap N of M
+{
+    HANDLE hThread;
+    DWORD_PTR mask, r;  // 64-bit win is required to handle more than 32 procs
+    nat nproc, i;
+
+    hThread = GetCurrentThread();
+
+    nproc = getNumberOfProcessors();
+
+    mask = 0;
+    for (i = n; i < nproc; i+=m) {
+        mask |= 1 << i;
+    }
+
+    r = SetThreadAffinityMask(hThread, mask);
+    if (r == 0) {
+       sysErrorBelch("SetThreadAffinity");
+        stg_exit(EXIT_FAILURE);
+    }
+}
+
+typedef BOOL (WINAPI *PCSIO)(HANDLE);
+
+void
+interruptOSThread (OSThreadId id)
+{
+    HANDLE hdl;
+    PCSIO pCSIO;
+    if (!(hdl = OpenThread(THREAD_TERMINATE,FALSE,id))) {
+        sysErrorBelch("interruptOSThread: OpenThread");
+        stg_exit(EXIT_FAILURE);
+    }
+    pCSIO = (PCSIO) GetProcAddress(GetModuleHandle(TEXT("Kernel32.dll")), "CancelSynchronousIo");
+    if ( NULL != pCSIO ) {
+        pCSIO(hdl);
+    } else {
+        // Nothing to do, unfortunately
+    }
+}
+
 #else /* !defined(THREADED_RTS) */
 
 int