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