| 1 | /* --------------------------------------------------------------------------- |
|---|
| 2 | * |
|---|
| 3 | * (c) The GHC Team, 2001-2009 |
|---|
| 4 | * |
|---|
| 5 | * Accessing OS threads functionality in a (mostly) OS-independent |
|---|
| 6 | * manner. |
|---|
| 7 | * |
|---|
| 8 | * Do not #include this file directly: #include "Rts.h" instead. |
|---|
| 9 | * |
|---|
| 10 | * To understand the structure of the RTS headers, see the wiki: |
|---|
| 11 | * http://hackage.haskell.org/trac/ghc/wiki/Commentary/SourceTree/Includes |
|---|
| 12 | * |
|---|
| 13 | * --------------------------------------------------------------------------*/ |
|---|
| 14 | |
|---|
| 15 | #ifndef RTS_OSTHREADS_H |
|---|
| 16 | #define RTS_OSTHREADS_H |
|---|
| 17 | |
|---|
| 18 | #if defined(THREADED_RTS) /* to the end */ |
|---|
| 19 | |
|---|
| 20 | #if defined(HAVE_PTHREAD_H) && !defined(mingw32_HOST_OS) |
|---|
| 21 | |
|---|
| 22 | #if CMINUSMINUS |
|---|
| 23 | |
|---|
| 24 | #define ACQUIRE_LOCK(mutex) foreign "C" pthread_mutex_lock(mutex) |
|---|
| 25 | #define RELEASE_LOCK(mutex) foreign "C" pthread_mutex_unlock(mutex) |
|---|
| 26 | #define ASSERT_LOCK_HELD(mutex) /* nothing */ |
|---|
| 27 | |
|---|
| 28 | #else |
|---|
| 29 | |
|---|
| 30 | #include <pthread.h> |
|---|
| 31 | #include <errno.h> |
|---|
| 32 | |
|---|
| 33 | typedef pthread_cond_t Condition; |
|---|
| 34 | typedef pthread_mutex_t Mutex; |
|---|
| 35 | typedef pthread_t OSThreadId; |
|---|
| 36 | typedef pthread_key_t ThreadLocalKey; |
|---|
| 37 | |
|---|
| 38 | #define OSThreadProcAttr /* nothing */ |
|---|
| 39 | |
|---|
| 40 | #define INIT_COND_VAR PTHREAD_COND_INITIALIZER |
|---|
| 41 | |
|---|
| 42 | #ifdef LOCK_DEBUG |
|---|
| 43 | #define LOCK_DEBUG_BELCH(what, mutex) \ |
|---|
| 44 | debugBelch("%s(0x%p) %s %d\n", what, mutex, __FILE__, __LINE__) |
|---|
| 45 | #else |
|---|
| 46 | #define LOCK_DEBUG_BELCH(what, mutex) /* nothing */ |
|---|
| 47 | #endif |
|---|
| 48 | |
|---|
| 49 | /* Always check the result of lock and unlock. */ |
|---|
| 50 | #define ACQUIRE_LOCK(mutex) \ |
|---|
| 51 | LOCK_DEBUG_BELCH("ACQUIRE_LOCK", mutex); \ |
|---|
| 52 | if (pthread_mutex_lock(mutex) == EDEADLK) { \ |
|---|
| 53 | barf("multiple ACQUIRE_LOCK: %s %d", __FILE__,__LINE__); \ |
|---|
| 54 | } |
|---|
| 55 | |
|---|
| 56 | // Returns zero if the lock was acquired. |
|---|
| 57 | EXTERN_INLINE int TRY_ACQUIRE_LOCK(pthread_mutex_t *mutex); |
|---|
| 58 | EXTERN_INLINE int TRY_ACQUIRE_LOCK(pthread_mutex_t *mutex) |
|---|
| 59 | { |
|---|
| 60 | LOCK_DEBUG_BELCH("TRY_ACQUIRE_LOCK", mutex); |
|---|
| 61 | return pthread_mutex_trylock(mutex); |
|---|
| 62 | } |
|---|
| 63 | |
|---|
| 64 | #define RELEASE_LOCK(mutex) \ |
|---|
| 65 | LOCK_DEBUG_BELCH("RELEASE_LOCK", mutex); \ |
|---|
| 66 | if (pthread_mutex_unlock(mutex) != 0) { \ |
|---|
| 67 | barf("RELEASE_LOCK: I do not own this lock: %s %d", __FILE__,__LINE__); \ |
|---|
| 68 | } |
|---|
| 69 | |
|---|
| 70 | // Note: this assertion calls pthread_mutex_lock() on a mutex that |
|---|
| 71 | // is already held by the calling thread. The mutex should therefore |
|---|
| 72 | // have been created with PTHREAD_MUTEX_ERRORCHECK, otherwise this |
|---|
| 73 | // assertion will hang. We always initialise mutexes with |
|---|
| 74 | // PTHREAD_MUTEX_ERRORCHECK when DEBUG is on (see rts/posix/OSThreads.h). |
|---|
| 75 | #define ASSERT_LOCK_HELD(mutex) ASSERT(pthread_mutex_lock(mutex) == EDEADLK) |
|---|
| 76 | |
|---|
| 77 | #endif // CMINUSMINUS |
|---|
| 78 | |
|---|
| 79 | # elif defined(HAVE_WINDOWS_H) |
|---|
| 80 | |
|---|
| 81 | #if CMINUSMINUS |
|---|
| 82 | |
|---|
| 83 | /* We jump through a hoop here to get a CCall EnterCriticalSection |
|---|
| 84 | and LeaveCriticalSection, as that's what C-- wants. */ |
|---|
| 85 | |
|---|
| 86 | #define ACQUIRE_LOCK(mutex) foreign "stdcall" EnterCriticalSection(mutex) |
|---|
| 87 | #define RELEASE_LOCK(mutex) foreign "stdcall" LeaveCriticalSection(mutex) |
|---|
| 88 | #define ASSERT_LOCK_HELD(mutex) /* nothing */ |
|---|
| 89 | |
|---|
| 90 | #else |
|---|
| 91 | |
|---|
| 92 | #include <windows.h> |
|---|
| 93 | |
|---|
| 94 | typedef HANDLE Condition; |
|---|
| 95 | typedef DWORD OSThreadId; |
|---|
| 96 | // don't be tempted to use HANDLE as the OSThreadId: there can be |
|---|
| 97 | // many HANDLES to a given thread, so comparison would not work. |
|---|
| 98 | typedef DWORD ThreadLocalKey; |
|---|
| 99 | |
|---|
| 100 | #define OSThreadProcAttr __stdcall |
|---|
| 101 | |
|---|
| 102 | #define INIT_COND_VAR 0 |
|---|
| 103 | |
|---|
| 104 | // We have a choice for implementing Mutexes on Windows. Standard |
|---|
| 105 | // Mutexes are kernel objects that require kernel calls to |
|---|
| 106 | // acquire/release, whereas CriticalSections are spin-locks that block |
|---|
| 107 | // in the kernel after spinning for a configurable number of times. |
|---|
| 108 | // CriticalSections are *much* faster, so we use those. The Mutex |
|---|
| 109 | // implementation is left here for posterity. |
|---|
| 110 | #define USE_CRITICAL_SECTIONS 1 |
|---|
| 111 | |
|---|
| 112 | #if USE_CRITICAL_SECTIONS |
|---|
| 113 | |
|---|
| 114 | typedef CRITICAL_SECTION Mutex; |
|---|
| 115 | |
|---|
| 116 | #ifdef LOCK_DEBUG |
|---|
| 117 | |
|---|
| 118 | #define ACQUIRE_LOCK(mutex) \ |
|---|
| 119 | debugBelch("ACQUIRE_LOCK(0x%p) %s %d\n", mutex,__FILE__,__LINE__); \ |
|---|
| 120 | EnterCriticalSection(mutex) |
|---|
| 121 | #define RELEASE_LOCK(mutex) \ |
|---|
| 122 | debugBelch("RELEASE_LOCK(0x%p) %s %d\n", mutex,__FILE__,__LINE__); \ |
|---|
| 123 | LeaveCriticalSection(mutex) |
|---|
| 124 | #define ASSERT_LOCK_HELD(mutex) /* nothing */ |
|---|
| 125 | |
|---|
| 126 | #else |
|---|
| 127 | |
|---|
| 128 | #define ACQUIRE_LOCK(mutex) EnterCriticalSection(mutex) |
|---|
| 129 | #define TRY_ACQUIRE_LOCK(mutex) (TryEnterCriticalSection(mutex) == 0) |
|---|
| 130 | #define RELEASE_LOCK(mutex) LeaveCriticalSection(mutex) |
|---|
| 131 | |
|---|
| 132 | // I don't know how to do this. TryEnterCriticalSection() doesn't do |
|---|
| 133 | // the right thing. |
|---|
| 134 | #define ASSERT_LOCK_HELD(mutex) /* nothing */ |
|---|
| 135 | |
|---|
| 136 | #endif |
|---|
| 137 | |
|---|
| 138 | #else |
|---|
| 139 | |
|---|
| 140 | typedef HANDLE Mutex; |
|---|
| 141 | |
|---|
| 142 | // casting to (Mutex *) here required due to use in .cmm files where |
|---|
| 143 | // the argument has (void *) type. |
|---|
| 144 | #define ACQUIRE_LOCK(mutex) \ |
|---|
| 145 | if (WaitForSingleObject(*((Mutex *)mutex),INFINITE) == WAIT_FAILED) { \ |
|---|
| 146 | barf("WaitForSingleObject: %d", GetLastError()); \ |
|---|
| 147 | } |
|---|
| 148 | |
|---|
| 149 | #define RELEASE_LOCK(mutex) \ |
|---|
| 150 | if (ReleaseMutex(*((Mutex *)mutex)) == 0) { \ |
|---|
| 151 | barf("ReleaseMutex: %d", GetLastError()); \ |
|---|
| 152 | } |
|---|
| 153 | |
|---|
| 154 | #define ASSERT_LOCK_HELD(mutex) /* nothing */ |
|---|
| 155 | #endif |
|---|
| 156 | |
|---|
| 157 | #endif // CMINUSMINUS |
|---|
| 158 | |
|---|
| 159 | # else |
|---|
| 160 | # error "Threads not supported" |
|---|
| 161 | # endif |
|---|
| 162 | |
|---|
| 163 | |
|---|
| 164 | #ifndef CMINUSMINUS |
|---|
| 165 | // |
|---|
| 166 | // General thread operations |
|---|
| 167 | // |
|---|
| 168 | extern OSThreadId osThreadId ( void ); |
|---|
| 169 | extern void shutdownThread ( void ) GNUC3_ATTRIBUTE(__noreturn__); |
|---|
| 170 | extern void yieldThread ( void ); |
|---|
| 171 | |
|---|
| 172 | typedef void OSThreadProcAttr OSThreadProc(void *); |
|---|
| 173 | |
|---|
| 174 | extern int createOSThread ( OSThreadId* tid, |
|---|
| 175 | OSThreadProc *startProc, void *param); |
|---|
| 176 | extern rtsBool osThreadIsAlive ( OSThreadId id ); |
|---|
| 177 | extern void interruptOSThread (OSThreadId id); |
|---|
| 178 | |
|---|
| 179 | // |
|---|
| 180 | // Condition Variables |
|---|
| 181 | // |
|---|
| 182 | extern void initCondition ( Condition* pCond ); |
|---|
| 183 | extern void closeCondition ( Condition* pCond ); |
|---|
| 184 | extern rtsBool broadcastCondition ( Condition* pCond ); |
|---|
| 185 | extern rtsBool signalCondition ( Condition* pCond ); |
|---|
| 186 | extern rtsBool waitCondition ( Condition* pCond, Mutex* pMut ); |
|---|
| 187 | |
|---|
| 188 | // |
|---|
| 189 | // Mutexes |
|---|
| 190 | // |
|---|
| 191 | extern void initMutex ( Mutex* pMut ); |
|---|
| 192 | extern void closeMutex ( Mutex* pMut ); |
|---|
| 193 | |
|---|
| 194 | // |
|---|
| 195 | // Thread-local storage |
|---|
| 196 | // |
|---|
| 197 | void newThreadLocalKey (ThreadLocalKey *key); |
|---|
| 198 | void *getThreadLocalVar (ThreadLocalKey *key); |
|---|
| 199 | void setThreadLocalVar (ThreadLocalKey *key, void *value); |
|---|
| 200 | void freeThreadLocalKey (ThreadLocalKey *key); |
|---|
| 201 | |
|---|
| 202 | // Processors and affinity |
|---|
| 203 | void setThreadAffinity (nat n, nat m); |
|---|
| 204 | #endif // !CMINUSMINUS |
|---|
| 205 | |
|---|
| 206 | #else |
|---|
| 207 | |
|---|
| 208 | #define ACQUIRE_LOCK(l) |
|---|
| 209 | #define RELEASE_LOCK(l) |
|---|
| 210 | #define ASSERT_LOCK_HELD(l) |
|---|
| 211 | |
|---|
| 212 | #endif /* defined(THREADED_RTS) */ |
|---|
| 213 | |
|---|
| 214 | #ifndef CMINUSMINUS |
|---|
| 215 | // |
|---|
| 216 | // Support for forkOS (defined regardless of THREADED_RTS, but does |
|---|
| 217 | // nothing when !THREADED_RTS). |
|---|
| 218 | // |
|---|
| 219 | int forkOS_createThread ( HsStablePtr entry ); |
|---|
| 220 | |
|---|
| 221 | // |
|---|
| 222 | // Returns the number of processor cores in the machine |
|---|
| 223 | // |
|---|
| 224 | nat getNumberOfProcessors (void); |
|---|
| 225 | #endif |
|---|
| 226 | |
|---|
| 227 | #endif /* RTS_OSTHREADS_H */ |
|---|