Interruptible FFI calls with pthread_kill and CancelSynchronousIO. v4
[ghc-hetmet.git] / rts / posix / OSThreads.c
index 6eb2d2b..2831553 100644 (file)
@@ -7,14 +7,23 @@
  *
  * --------------------------------------------------------------------------*/
 
-#if defined(DEBUG) && defined(__linux__)
+#if defined(__linux__)
 /* We want GNU extensions in DEBUG mode for mutex error checking */
+/* We also want the affinity API, which requires _GNU_SOURCE */
 #define _GNU_SOURCE
 #endif
 
+#include "PosixSource.h"
+
+#if defined(freebsd_HOST_OS)
+/* Inclusion of system headers usually requires __BSD_VISIBLE on FreeBSD,
+ * because of some specific types, like u_char, u_int, etc. */
+#define __BSD_VISIBLE  1
+#endif
+
 #include "Rts.h"
+
 #if defined(THREADED_RTS)
-#include "OSThreads.h"
 #include "RtsUtils.h"
 #include "Task.h"
 
 #include <string.h>
 #endif
 
+#if defined(darwin_HOST_OS) || defined(freebsd_HOST_OS)
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#endif
+
 #if !defined(HAVE_PTHREAD_H)
 #error pthreads.h is required for the threaded RTS on Posix platforms
 #endif
 
+#if defined(HAVE_SCHED_H)
+#include <sched.h>
+#endif
+
+#if defined(HAVE_SYS_CPUSET_H)
+#include <sys/param.h>
+#include <sys/cpuset.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#if defined(darwin_HOST_OS)
+#include <mach/mach.h>
+#endif
+
+#ifdef HAVE_SIGNAL_H
+# include <signal.h>
+#endif
+
 /*
  * This (allegedly) OS threads independent layer was initially
  * abstracted away from code that used Pthreads, so the functions
@@ -189,6 +224,10 @@ getNumberOfProcessors (void)
         nproc = sysconf(_SC_NPROCESSORS_ONLN);
 #elif defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_CONF)
         nproc = sysconf(_SC_NPROCESSORS_CONF);
+#elif defined(darwin_HOST_OS) || defined(freebsd_HOST_OS)
+        size_t size = sizeof(nat);
+        if(0 != sysctlbyname("hw.ncpu",&nproc,&size,NULL,0))
+            nproc = 1;
 #else
         nproc = 1;
 #endif
@@ -197,6 +236,70 @@ getNumberOfProcessors (void)
     return nproc;
 }
 
+#if defined(HAVE_SCHED_H) && defined(HAVE_SCHED_SETAFFINITY)
+// Schedules the thread to run on CPU n of m.  m may be less than the
+// number of physical CPUs, in which case, the thread will be allowed
+// to run on CPU n, n+m, n+2m etc.
+void
+setThreadAffinity (nat n, nat m)
+{
+    nat nproc;
+    cpu_set_t cs;
+    nat i;
+
+    nproc = getNumberOfProcessors();
+    CPU_ZERO(&cs);
+    for (i = n; i < nproc; i+=m) {
+        CPU_SET(i, &cs);
+    }
+    sched_setaffinity(0, sizeof(cpu_set_t), &cs);
+}
+
+#elif defined(darwin_HOST_OS) && defined(THREAD_AFFINITY_POLICY)
+// Schedules the current thread in the affinity set identified by tag n.
+void
+setThreadAffinity (nat n, nat m GNUC3_ATTRIBUTE(__unused__))
+{
+    thread_affinity_policy_data_t policy;
+
+    policy.affinity_tag = n;
+    thread_policy_set(mach_thread_self(), 
+                     THREAD_AFFINITY_POLICY,
+                     (thread_policy_t) &policy,
+                     THREAD_AFFINITY_POLICY_COUNT);
+}
+
+#elif defined(HAVE_SYS_CPUSET_H) /* FreeBSD 7.1+ */
+void
+setThreadAffinity(nat n, nat m)
+{
+       nat nproc;
+       cpuset_t cs;
+       nat i;
+
+       nproc = getNumberOfProcessors();
+       CPU_ZERO(&cs);
+
+       for (i = n; i < nproc; i += m)
+               CPU_SET(i, &cs);
+
+       cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, sizeof(cpuset_t), &cs);
+}
+
+#else
+void
+setThreadAffinity (nat n GNUC3_ATTRIBUTE(__unused__), 
+                  nat m GNUC3_ATTRIBUTE(__unused__))
+{
+}
+#endif
+
+void
+interruptOSThread (OSThreadId id)
+{
+    pthread_kill(id, SIGPIPE);
+}
+
 #else /* !defined(THREADED_RTS) */
 
 int