testsuite: Assert that testsuite ways are known
[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) || defined(dragonfly_HOST_OS)
13 /* Inclusion of system headers usually requires __BSD_VISIBLE on FreeBSD and
14 * DragonflyBSD, 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 #if defined(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 #if defined(HAVE_SIGNAL_H)
74 # include <signal.h>
75 #endif
76
77 #if defined(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, startProc, param);
138 if (!result) {
139 pthread_detach(*pId);
140 #if defined(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 rts_done();
227 return NULL;
228 }
229
230 int
231 forkOS_createThread ( HsStablePtr entry )
232 {
233 pthread_t tid;
234 int result = pthread_create(&tid, NULL,
235 forkOS_createThreadWrapper, (void*)entry);
236 if(!result)
237 pthread_detach(tid);
238 return result;
239 }
240
241 void freeThreadingResources (void) { /* nothing */ }
242
243 uint32_t
244 getNumberOfProcessors (void)
245 {
246 static uint32_t nproc = 0;
247
248 if (nproc == 0) {
249 #if defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN)
250 nproc = sysconf(_SC_NPROCESSORS_ONLN);
251 #elif defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_CONF)
252 nproc = sysconf(_SC_NPROCESSORS_CONF);
253 #elif defined(darwin_HOST_OS)
254 size_t size = sizeof(uint32_t);
255 if(sysctlbyname("hw.logicalcpu",&nproc,&size,NULL,0) != 0) {
256 if(sysctlbyname("hw.ncpu",&nproc,&size,NULL,0) != 0)
257 nproc = 1;
258 }
259 #elif defined(freebsd_HOST_OS)
260 size_t size = sizeof(uint32_t);
261 if(sysctlbyname("hw.ncpu",&nproc,&size,NULL,0) != 0)
262 nproc = 1;
263 #else
264 nproc = 1;
265 #endif
266 }
267
268 return nproc;
269 }
270
271 #else /* !defined(THREADED_RTS) */
272
273 int
274 forkOS_createThread ( HsStablePtr entry STG_UNUSED )
275 {
276 return -1;
277 }
278
279 void freeThreadingResources (void) { /* nothing */ }
280
281 uint32_t getNumberOfProcessors (void)
282 {
283 return 1;
284 }
285
286 #endif /* defined(THREADED_RTS) */
287
288 #if defined(HAVE_SCHED_H) && defined(HAVE_SCHED_SETAFFINITY)
289 // Schedules the thread to run on CPU n of m. m may be less than the
290 // number of physical CPUs, in which case, the thread will be allowed
291 // to run on CPU n, n+m, n+2m etc.
292 void
293 setThreadAffinity (uint32_t n, uint32_t m)
294 {
295 uint32_t nproc;
296 cpu_set_t cs;
297 uint32_t i;
298
299 nproc = getNumberOfProcessors();
300 CPU_ZERO(&cs);
301 for (i = n; i < nproc; i+=m) {
302 CPU_SET(i, &cs);
303 }
304 sched_setaffinity(0, sizeof(cpu_set_t), &cs);
305 }
306
307 #elif defined(darwin_HOST_OS) && defined(THREAD_AFFINITY_POLICY)
308 // Schedules the current thread in the affinity set identified by tag n.
309 void
310 setThreadAffinity (uint32_t n, uint32_t m GNUC3_ATTRIBUTE(__unused__))
311 {
312 thread_affinity_policy_data_t policy;
313
314 policy.affinity_tag = n;
315 thread_policy_set(mach_thread_self(),
316 THREAD_AFFINITY_POLICY,
317 (thread_policy_t) &policy,
318 THREAD_AFFINITY_POLICY_COUNT);
319 }
320
321 #elif defined(HAVE_SYS_CPUSET_H) /* FreeBSD 7.1+ */
322 void
323 setThreadAffinity(uint32_t n, uint32_t m)
324 {
325 uint32_t nproc;
326 cpuset_t cs;
327 uint32_t i;
328
329 nproc = getNumberOfProcessors();
330 CPU_ZERO(&cs);
331
332 for (i = n; i < nproc; i += m)
333 CPU_SET(i, &cs);
334
335 cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID,
336 -1, sizeof(cpuset_t), &cs);
337 }
338
339 #else
340 void
341 setThreadAffinity (uint32_t n STG_UNUSED,
342 uint32_t m STG_UNUSED)
343 {
344 }
345 #endif
346
347 #if HAVE_LIBNUMA
348 void setThreadNode (uint32_t node)
349 {
350 if (numa_run_on_node(node) == -1) {
351 sysErrorBelch("numa_run_on_node");
352 stg_exit(1);
353 }
354 }
355
356 void releaseThreadNode (void)
357 {
358 if (numa_run_on_node(-1) == -1) {
359 sysErrorBelch("numa_run_on_node");
360 stg_exit(1);
361 }
362 }
363
364 #else
365 void setThreadNode (uint32_t node STG_UNUSED) { /* nothing */ }
366 void releaseThreadNode (void) { /* nothing */ }
367 #endif
368
369 void
370 interruptOSThread (OSThreadId id)
371 {
372 pthread_kill(id, SIGPIPE);
373 }
374
375 KernelThreadId kernelThreadId (void)
376 {
377 #if defined(linux_HOST_OS)
378 pid_t tid = syscall(SYS_gettid); // no really, see man gettid
379 return (KernelThreadId) tid;
380
381 /* FreeBSD 9.0+ */
382 #elif defined(freebsd_HOST_OS) && (__FreeBSD_version >= 900031)
383 return pthread_getthreadid_np();
384
385 // Check for OS X >= 10.6 (see #7356)
386 #elif defined(darwin_HOST_OS) && \
387 !(defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && \
388 __MAC_OS_X_VERSION_MIN_REQUIRED < 1060)
389 uint64_t ktid;
390 pthread_threadid_np(NULL, &ktid);
391 return ktid;
392
393 #else
394 // unsupported
395 return 0;
396 #endif
397 }