* (c) The GHC Team, 2001-2005
*
* Accessing OS threads functionality in a (mostly) OS-independent
- * manner.
+ * manner.
*
* --------------------------------------------------------------------------*/
-#if defined(DEBUG) && defined(__linux__)
+#if defined(__linux__) || defined(__GLIBC__)
/* 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(linux_HOST_OS)
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/syscall.h>
+#endif
+
+#if defined(HAVE_PTHREAD_H)
+#include <pthread.h>
+#if defined(freebsd_HOST_OS)
+#include <pthread_np.h>
+#endif
+#endif
+
#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_PARAM_H)
+#include <sys/param.h>
+#endif
+#if defined(HAVE_SYS_CPUSET_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
}
void
-yieldThread()
+yieldThread(void)
{
sched_yield();
return;
}
void
-shutdownThread()
+shutdownThread(void)
{
pthread_exit(NULL);
}
int
-createOSThread (OSThreadId* pId, OSThreadProc *startProc, void *param)
+createOSThread (OSThreadId* pId, char *name STG_UNUSED,
+ OSThreadProc *startProc, void *param)
{
int result = pthread_create(pId, NULL, (void *(*)(void *))startProc, param);
- if(!result)
+ if (!result) {
pthread_detach(*pId);
+#if HAVE_PTHREAD_SETNAME_NP
+ pthread_setname_np(*pId, name);
+#endif
+ }
return result;
}
OSThreadId
-osThreadId()
+osThreadId(void)
{
return pthread_self();
}
{
int r;
if ((r = pthread_key_create(key, NULL)) != 0) {
- barf("newThreadLocalKey: %s", strerror(r));
+ barf("newThreadLocalKey: %s", strerror(r));
}
}
{
int r;
if ((r = pthread_setspecific(*key,value)) != 0) {
- barf("setThreadLocalVar: %s", strerror(r));
+ barf("setThreadLocalVar: %s", strerror(r));
}
}
{
int r;
if ((r = pthread_key_delete(*key)) != 0) {
- barf("freeThreadLocalKey: %s", strerror(r));
+ barf("freeThreadLocalKey: %s", strerror(r));
}
}
{
Capability *cap;
cap = rts_lock();
- cap = rts_evalStableIO(cap, (HsStablePtr) entry, NULL);
- taskTimeStamp(myTask());
+ rts_evalStableIO(&cap, (HsStablePtr) entry, NULL);
rts_unlock(cap);
return NULL;
}
{
pthread_t tid;
int result = pthread_create(&tid, NULL,
- forkOS_createThreadWrapper, (void*)entry);
+ forkOS_createThreadWrapper, (void*)entry);
if(!result)
pthread_detach(tid);
return result;
}
+nat
+getNumberOfProcessors (void)
+{
+ static nat nproc = 0;
+
+ if (nproc == 0) {
+#if defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN)
+ 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
+ }
+
+ 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
return -1;
}
-#endif /* !defined(THREADED_RTS) */
+nat getNumberOfProcessors (void)
+{
+ return 1;
+}
+
+#endif /* defined(THREADED_RTS) */
+
+KernelThreadId kernelThreadId (void)
+{
+#if defined(linux_HOST_OS)
+ pid_t tid = syscall(SYS_gettid); // no really, see man gettid
+ return (KernelThreadId) tid;
+
+/* FreeBSD 9.0+ */
+#elif defined(freebsd_HOST_OS) && (__FreeBSD_version >= 900031)
+ return pthread_getthreadid_np();
+
+// Check for OS X >= 10.6 (see #7356)
+#elif defined(darwin_HOST_OS) && \
+ !(defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && \
+ __MAC_OS_X_VERSION_MIN_REQUIRED < 1060)
+ uint64_t ktid;
+ pthread_threadid_np(NULL, &ktid);
+ return ktid;
+
+#else
+ // unsupported
+ return 0;
+#endif
+}