PPC: Implement SMP primitives using gcc built-ins
[ghc.git] / includes / rts / OSThreads.h
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://ghc.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 near 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, char *name,
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 (uint32_t n, uint32_t 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 uint32_t getNumberOfProcessors (void);
225
226 //
227 // Support for getting at the kernel thread Id for tracing/profiling.
228 //
229 // This stuff is optional and only used for tracing/profiling purposes, to
230 // match up thread ids recorded by other tools. For example, on Linux and OSX
231 // the pthread_t type is not the same as the kernel thread id, and system
232 // profiling tools like Linux perf, and OSX's DTrace use the kernel thread Id.
233 // So if we want to match up RTS tasks with kernel threads recorded by these
234 // tools then we need to know the kernel thread Id, and this must be a separate
235 // type from the OSThreadId.
236 //
237 // If the feature cannot be supported on an OS, it is OK to always return 0.
238 // In particular it would almost certaily be meaningless on systems not using
239 // a 1:1 threading model.
240
241 // We use a common serialisable representation on all OSs
242 // This is ok for Windows, OSX and Linux.
243 typedef StgWord64 KernelThreadId;
244
245 // Get the current kernel thread id
246 KernelThreadId kernelThreadId (void);
247
248 #endif /* CMINUSMINUS */
249
250 #endif /* RTS_OSTHREADS_H */