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