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