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