RTS tidyup sweep, first phase
[ghc-hetmet.git] / includes / rts / OSThreads.h
diff --git a/includes/rts/OSThreads.h b/includes/rts/OSThreads.h
new file mode 100644 (file)
index 0000000..2d32136
--- /dev/null
@@ -0,0 +1,209 @@
+/* ---------------------------------------------------------------------------
+ *
+ * (c) The GHC Team, 2001-2005
+ *
+ * Accessing OS threads functionality in a (mostly) OS-independent
+ * manner. 
+ * 
+ * --------------------------------------------------------------------------*/
+
+#ifndef RTS_OSTHREADS_H
+#define RTS_OSTHREADS_H
+
+#if defined(THREADED_RTS) /* to the end */
+
+# if defined(HAVE_PTHREAD_H) && !defined(WANT_NATIVE_WIN32_THREADS)
+
+#if CMINUSMINUS
+
+#define ACQUIRE_LOCK(mutex) foreign "C" pthread_mutex_lock(mutex)
+#define RELEASE_LOCK(mutex) foreign "C" pthread_mutex_unlock(mutex)
+#define ASSERT_LOCK_HELD(mutex) /* nothing */
+
+#else
+
+#include <pthread.h>
+#include <errno.h>
+
+typedef pthread_cond_t  Condition;
+typedef pthread_mutex_t Mutex;
+typedef pthread_t       OSThreadId;
+typedef pthread_key_t   ThreadLocalKey;
+
+#define OSThreadProcAttr /* nothing */
+
+#define INIT_COND_VAR       PTHREAD_COND_INITIALIZER
+
+#ifdef LOCK_DEBUG
+#define LOCK_DEBUG_BELCH(what, mutex) \
+  debugBelch("%s(0x%p) %s %d\n", what, mutex, __FILE__, __LINE__)
+#else
+#define LOCK_DEBUG_BELCH(what, mutex) /* nothing */
+#endif
+
+/* Always check the result of lock and unlock. */
+#define ACQUIRE_LOCK(mutex) \
+  LOCK_DEBUG_BELCH("ACQUIRE_LOCK", mutex); \
+  if (pthread_mutex_lock(mutex) == EDEADLK) { \
+    barf("multiple ACQUIRE_LOCK: %s %d", __FILE__,__LINE__); \
+  }
+
+#define RELEASE_LOCK(mutex) \
+  LOCK_DEBUG_BELCH("RELEASE_LOCK", mutex); \
+  if (pthread_mutex_unlock(mutex) != 0) { \
+    barf("RELEASE_LOCK: I do not own this lock: %s %d", __FILE__,__LINE__); \
+  }
+
+// Note: this assertion calls pthread_mutex_lock() on a mutex that
+// is already held by the calling thread.  The mutex should therefore
+// have been created with PTHREAD_MUTEX_ERRORCHECK, otherwise this
+// assertion will hang.  We always initialise mutexes with
+// PTHREAD_MUTEX_ERRORCHECK when DEBUG is on (see rts/posix/OSThreads.h).
+#define ASSERT_LOCK_HELD(mutex) ASSERT(pthread_mutex_lock(mutex) == EDEADLK)
+
+#endif // CMINUSMINUS
+
+# elif defined(HAVE_WINDOWS_H)
+
+#if CMINUSMINUS
+
+/* We jump through a hoop here to get a CCall EnterCriticalSection
+   and LeaveCriticalSection, as that's what C-- wants. */
+
+#define ACQUIRE_LOCK(mutex) foreign "stdcall" EnterCriticalSection(mutex)
+#define RELEASE_LOCK(mutex) foreign "stdcall" LeaveCriticalSection(mutex)
+#define ASSERT_LOCK_HELD(mutex) /* nothing */
+
+#else
+
+#include <windows.h>
+
+typedef HANDLE Condition;
+typedef DWORD OSThreadId;
+// don't be tempted to use HANDLE as the OSThreadId: there can be 
+// many HANDLES to a given thread, so comparison would not work.
+typedef DWORD ThreadLocalKey;
+
+#define OSThreadProcAttr __stdcall
+
+#define INIT_COND_VAR  0
+
+// We have a choice for implementing Mutexes on Windows.  Standard
+// Mutexes are kernel objects that require kernel calls to
+// acquire/release, whereas CriticalSections are spin-locks that block
+// in the kernel after spinning for a configurable number of times.
+// CriticalSections are *much* faster, so we use those.  The Mutex
+// implementation is left here for posterity.
+#define USE_CRITICAL_SECTIONS 1
+
+#if USE_CRITICAL_SECTIONS
+
+typedef CRITICAL_SECTION Mutex;
+
+#ifdef LOCK_DEBUG
+
+#define ACQUIRE_LOCK(mutex) \
+  debugBelch("ACQUIRE_LOCK(0x%p) %s %d\n", mutex,__FILE__,__LINE__); \
+  EnterCriticalSection(mutex)
+#define RELEASE_LOCK(mutex) \
+  debugBelch("RELEASE_LOCK(0x%p) %s %d\n", mutex,__FILE__,__LINE__); \
+  LeaveCriticalSection(mutex)
+#define ASSERT_LOCK_HELD(mutex) /* nothing */
+
+#else
+
+#define ACQUIRE_LOCK(mutex)  EnterCriticalSection(mutex)
+#define RELEASE_LOCK(mutex)  LeaveCriticalSection(mutex)
+
+// I don't know how to do this.  TryEnterCriticalSection() doesn't do
+// the right thing.
+#define ASSERT_LOCK_HELD(mutex) /* nothing */
+
+#endif
+
+#else
+
+typedef HANDLE Mutex;
+
+// casting to (Mutex *) here required due to use in .cmm files where
+// the argument has (void *) type.
+#define ACQUIRE_LOCK(mutex)                                    \
+    if (WaitForSingleObject(*((Mutex *)mutex),INFINITE) == WAIT_FAILED) { \
+       barf("WaitForSingleObject: %d", GetLastError());        \
+    }
+
+#define RELEASE_LOCK(mutex)                            \
+    if (ReleaseMutex(*((Mutex *)mutex)) == 0) {                \
+       barf("ReleaseMutex: %d", GetLastError());       \
+    }
+
+#define ASSERT_LOCK_HELD(mutex) /* nothing */
+#endif
+
+#endif // CMINUSMINUS
+
+# else
+#  error "Threads not supported"
+# endif
+
+
+#ifndef CMINUSMINUS
+//
+// General thread operations
+//
+extern OSThreadId osThreadId      ( void );
+extern void shutdownThread        ( void )   GNUC3_ATTRIBUTE(__noreturn__);
+extern void yieldThread           ( void );
+
+typedef void OSThreadProcAttr OSThreadProc(void *);
+
+extern int  createOSThread        ( OSThreadId* tid, 
+                                   OSThreadProc *startProc, void *param);
+extern rtsBool osThreadIsAlive    ( OSThreadId id );
+
+//
+// Condition Variables
+//
+extern void initCondition         ( Condition* pCond );
+extern void closeCondition        ( Condition* pCond );
+extern rtsBool broadcastCondition ( Condition* pCond );
+extern rtsBool signalCondition    ( Condition* pCond );
+extern rtsBool waitCondition      ( Condition* pCond, 
+                                   Mutex* pMut );
+
+//
+// Mutexes
+//
+extern void initMutex             ( Mutex* pMut );
+extern void closeMutex            ( Mutex* pMut );
+
+//
+// Thread-local storage
+//
+void  newThreadLocalKey (ThreadLocalKey *key);
+void *getThreadLocalVar (ThreadLocalKey *key);
+void  setThreadLocalVar (ThreadLocalKey *key, void *value);
+void  freeThreadLocalKey (ThreadLocalKey *key);
+
+// Processors and affinity
+nat  getNumberOfProcessors (void);
+void setThreadAffinity     (nat n, nat m);
+#endif // !CMINUSMINUS
+
+#else
+
+#define ACQUIRE_LOCK(l)
+#define RELEASE_LOCK(l)
+#define ASSERT_LOCK_HELD(l)
+
+#endif /* defined(THREADED_RTS) */
+
+//
+// Support for forkOS (defined regardless of THREADED_RTS, but does
+// nothing when !THREADED_RTS).
+//
+#ifndef CMINUSMINUS
+int forkOS_createThread ( HsStablePtr entry );
+#endif
+
+#endif /* RTS_OSTHREADS_H */