Enable new warning for fragile/incorrect CPP #if usage
[ghc.git] / rts / posix / OSThreads.c
1 /* ---------------------------------------------------------------------------
2 *
3 * (c) The GHC Team, 2001-2005
4 *
5 * Accessing OS threads functionality in a (mostly) OS-independent
6 * manner.
7 *
8 * --------------------------------------------------------------------------*/
9
10 #include "PosixSource.h"
11
12 #if defined(freebsd_HOST_OS)
13 /* Inclusion of system headers usually requires __BSD_VISIBLE on FreeBSD,
14 * because of some specific types, like u_char, u_int, etc. */
15 #define __BSD_VISIBLE 1
16 #endif
17 #if defined(darwin_HOST_OS)
18 /* Inclusion of system headers usually requires _DARWIN_C_SOURCE on Mac OS X
19 * because of some specific types like u_char, u_int, etc. */
20 #define _DARWIN_C_SOURCE 1
21 #endif
22
23 #include "Rts.h"
24
25 #if defined(linux_HOST_OS)
26 #include <unistd.h>
27 #include <sys/types.h>
28 #include <sys/syscall.h>
29 #endif
30
31 #if defined(HAVE_PTHREAD_H)
32 #include <pthread.h>
33 #if defined(freebsd_HOST_OS)
34 #include <pthread_np.h>
35 #endif
36 #endif
37
38 #include "RtsUtils.h"
39 #include "Task.h"
40
41 #if HAVE_STRING_H
42 #include <string.h>
43 #endif
44
45 #if defined(darwin_HOST_OS) || defined(freebsd_HOST_OS)
46 #include <sys/types.h>
47 #include <sys/sysctl.h>
48 #endif
49
50 #if !defined(HAVE_PTHREAD_H)
51 #error pthreads.h is required for the threaded RTS on Posix platforms
52 #endif
53
54 #if defined(HAVE_SCHED_H)
55 #include <sched.h>
56 #endif
57
58 #if defined(HAVE_SYS_PARAM_H)
59 #include <sys/param.h>
60 #endif
61 #if defined(HAVE_SYS_CPUSET_H)
62 #include <sys/cpuset.h>
63 #endif
64
65 #ifdef HAVE_UNISTD_H
66 #include <unistd.h>
67 #endif
68
69 #if defined(darwin_HOST_OS)
70 #include <mach/mach.h>
71 #endif
72
73 #ifdef HAVE_SIGNAL_H
74 # include <signal.h>
75 #endif
76
77 #ifdef HAVE_NUMA_H
78 #include <numa.h>
79 #endif
80
81 /*
82 * This (allegedly) OS threads independent layer was initially
83 * abstracted away from code that used Pthreads, so the functions
84 * provided here are mostly just wrappers to the Pthreads API.
85 *
86 */
87
88 void
89 initCondition( Condition* pCond )
90 {
91 pthread_cond_init(pCond, NULL);
92 return;
93 }
94
95 void
96 closeCondition( Condition* pCond )
97 {
98 pthread_cond_destroy(pCond);
99 return;
100 }
101
102 bool
103 broadcastCondition ( Condition* pCond )
104 {
105 return (pthread_cond_broadcast(pCond) == 0);
106 }
107
108 bool
109 signalCondition ( Condition* pCond )
110 {
111 return (pthread_cond_signal(pCond) == 0);
112 }
113
114 bool
115 waitCondition ( Condition* pCond, Mutex* pMut )
116 {
117 return (pthread_cond_wait(pCond,pMut) == 0);
118 }
119
120 void
121 yieldThread(void)
122 {
123 sched_yield();
124 return;
125 }
126
127 void
128 shutdownThread(void)
129 {
130 pthread_exit(NULL);
131 }
132
133 int
134 createOSThread (OSThreadId* pId, char *name STG_UNUSED,
135 OSThreadProc *startProc, void *param)
136 {
137 int result = pthread_create(pId, NULL, (void *(*)(void *))startProc, param);
138 if (!result) {
139 pthread_detach(*pId);
140 #ifdef HAVE_PTHREAD_SETNAME_NP
141 pthread_setname_np(*pId, name);
142 #endif
143 }
144 return result;
145 }
146
147 OSThreadId
148 osThreadId(void)
149 {
150 return pthread_self();
151 }
152
153 bool
154 osThreadIsAlive(OSThreadId id STG_UNUSED)
155 {
156 // no good way to implement this on POSIX, AFAICT. Returning true
157 // is safe.
158 return true;
159 }
160
161 void
162 initMutex(Mutex* pMut)
163 {
164 #if defined(DEBUG)
165 pthread_mutexattr_t attr;
166 pthread_mutexattr_init(&attr);
167 pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_ERRORCHECK);
168 pthread_mutex_init(pMut,&attr);
169 #else
170 pthread_mutex_init(pMut,NULL);
171 #endif
172 return;
173 }
174 void
175 closeMutex(Mutex* pMut)
176 {
177 pthread_mutex_destroy(pMut);
178 }
179
180 void
181 newThreadLocalKey (ThreadLocalKey *key)
182 {
183 int r;
184 if ((r = pthread_key_create(key, NULL)) != 0) {
185 barf("newThreadLocalKey: %s", strerror(r));
186 }
187 }
188
189 void *
190 getThreadLocalVar (ThreadLocalKey *key)
191 {
192 return pthread_getspecific(*key);
193 // Note: a return value of NULL can indicate that either the key
194 // is not valid, or the key is valid and the data value has not
195 // yet been set. We need to use the latter case, so we cannot
196 // detect errors here.
197 }
198
199 void
200 setThreadLocalVar (ThreadLocalKey *key, void *value)
201 {
202 int r;
203 if ((r = pthread_setspecific(*key,value)) != 0) {
204 barf("setThreadLocalVar: %s", strerror(r));
205 }
206 }
207
208 void
209 freeThreadLocalKey (ThreadLocalKey *key)
210 {
211 int r;
212 if ((r = pthread_key_delete(*key)) != 0) {
213 barf("freeThreadLocalKey: %s", strerror(r));
214 }
215 }
216
217 #if defined(THREADED_RTS)
218
219 static void *
220 forkOS_createThreadWrapper ( void * entry )
221 {
222 Capability *cap;
223 cap = rts_lock();
224 rts_evalStableIO(&cap, (HsStablePtr) entry, NULL);
225 rts_unlock(cap);
226 return NULL;
227 }
228
229 int
230 forkOS_createThread ( HsStablePtr entry )
231 {
232 pthread_t tid;
233 int result = pthread_create(&tid, NULL,
234 forkOS_createThreadWrapper, (void*)entry);
235 if(!result)
236 pthread_detach(tid);
237 return result;
238 }
239
240 void freeThreadingResources (void) { /* nothing */ }
241
242 uint32_t
243 getNumberOfProcessors (void)
244 {
245 static uint32_t nproc = 0;
246
247 if (nproc == 0) {
248 #if defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN)
249 nproc = sysconf(_SC_NPROCESSORS_ONLN);
250 #elif defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_CONF)
251 nproc = sysconf(_SC_NPROCESSORS_CONF);
252 #elif defined(darwin_HOST_OS)
253 size_t size = sizeof(uint32_t);
254 if(sysctlbyname("hw.logicalcpu",&nproc,&size,NULL,0) != 0) {
255 if(sysctlbyname("hw.ncpu",&nproc,&size,NULL,0) != 0)
256 nproc = 1;
257 }
258 #elif defined(freebsd_HOST_OS)
259 size_t size = sizeof(uint32_t);
260 if(sysctlbyname("hw.ncpu",&nproc,&size,NULL,0) != 0)
261 nproc = 1;
262 #else
263 nproc = 1;
264 #endif
265 }
266
267 return nproc;
268 }
269
270 #else /* !defined(THREADED_RTS) */
271
272 int
273 forkOS_createThread ( HsStablePtr entry STG_UNUSED )
274 {
275 return -1;
276 }
277
278 void freeThreadingResources (void) { /* nothing */ }
279
280 uint32_t getNumberOfProcessors (void)
281 {
282 return 1;
283 }
284
285 #endif /* defined(THREADED_RTS) */
286
287 #if defined(HAVE_SCHED_H) && defined(HAVE_SCHED_SETAFFINITY)
288 // Schedules the thread to run on CPU n of m. m may be less than the
289 // number of physical CPUs, in which case, the thread will be allowed
290 // to run on CPU n, n+m, n+2m etc.
291 void
292 setThreadAffinity (uint32_t n, uint32_t m)
293 {
294 uint32_t nproc;
295 cpu_set_t cs;
296 uint32_t i;
297
298 nproc = getNumberOfProcessors();
299 CPU_ZERO(&cs);
300 for (i = n; i < nproc; i+=m) {
301 CPU_SET(i, &cs);
302 }
303 sched_setaffinity(0, sizeof(cpu_set_t), &cs);
304 }
305
306 #elif defined(darwin_HOST_OS) && defined(THREAD_AFFINITY_POLICY)
307 // Schedules the current thread in the affinity set identified by tag n.
308 void
309 setThreadAffinity (uint32_t n, uint32_t m GNUC3_ATTRIBUTE(__unused__))
310 {
311 thread_affinity_policy_data_t policy;
312
313 policy.affinity_tag = n;
314 thread_policy_set(mach_thread_self(),
315 THREAD_AFFINITY_POLICY,
316 (thread_policy_t) &policy,
317 THREAD_AFFINITY_POLICY_COUNT);
318 }
319
320 #elif defined(HAVE_SYS_CPUSET_H) /* FreeBSD 7.1+ */
321 void
322 setThreadAffinity(uint32_t n, uint32_t m)
323 {
324 uint32_t nproc;
325 cpuset_t cs;
326 uint32_t i;
327
328 nproc = getNumberOfProcessors();
329 CPU_ZERO(&cs);
330
331 for (i = n; i < nproc; i += m)
332 CPU_SET(i, &cs);
333
334 cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID,
335 -1, sizeof(cpuset_t), &cs);
336 }
337
338 #else
339 void
340 setThreadAffinity (uint32_t n STG_UNUSED,
341 uint32_t m STG_UNUSED)
342 {
343 }
344 #endif
345
346 #if HAVE_LIBNUMA
347 void setThreadNode (uint32_t node)
348 {
349 if (numa_run_on_node(node) == -1) {
350 sysErrorBelch("numa_run_on_node");
351 stg_exit(1);
352 }
353 }
354
355 void releaseThreadNode (void)
356 {
357 if (numa_run_on_node(-1) == -1) {
358 sysErrorBelch("numa_run_on_node");
359 stg_exit(1);
360 }
361 }
362
363 #else
364 void setThreadNode (uint32_t node STG_UNUSED) { /* nothing */ }
365 void releaseThreadNode (void) { /* nothing */ }
366 #endif
367
368 void
369 interruptOSThread (OSThreadId id)
370 {
371 pthread_kill(id, SIGPIPE);
372 }
373
374 KernelThreadId kernelThreadId (void)
375 {
376 #if defined(linux_HOST_OS)
377 pid_t tid = syscall(SYS_gettid); // no really, see man gettid
378 return (KernelThreadId) tid;
379
380 /* FreeBSD 9.0+ */
381 #elif defined(freebsd_HOST_OS) && (__FreeBSD_version >= 900031)
382 return pthread_getthreadid_np();
383
384 // Check for OS X >= 10.6 (see #7356)
385 #elif defined(darwin_HOST_OS) && \
386 !(defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && \
387 __MAC_OS_X_VERSION_MIN_REQUIRED < 1060)
388 uint64_t ktid;
389 pthread_threadid_np(NULL, &ktid);
390 return ktid;
391
392 #else
393 // unsupported
394 return 0;
395 #endif
396 }