wibble for getNumberOfProcessors
[ghc-hetmet.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__)
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 "Rts.h"
17 #if defined(THREADED_RTS)
18 #include "OSThreads.h"
19 #include "RtsUtils.h"
20 #include "Task.h"
21
22 #if HAVE_STRING_H
23 #include <string.h>
24 #endif
25
26 #if !defined(HAVE_PTHREAD_H)
27 #error pthreads.h is required for the threaded RTS on Posix platforms
28 #endif
29
30 #if defined(HAVE_SCHED_H)
31 #include <sched.h>
32 #endif
33
34 #ifdef HAVE_UNISTD_H
35 #include <unistd.h>
36 #endif
37
38 /*
39  * This (allegedly) OS threads independent layer was initially
40  * abstracted away from code that used Pthreads, so the functions
41  * provided here are mostly just wrappers to the Pthreads API.
42  *
43  */
44
45 void
46 initCondition( Condition* pCond )
47 {
48   pthread_cond_init(pCond, NULL);
49   return;
50 }
51
52 void
53 closeCondition( Condition* pCond )
54 {
55   pthread_cond_destroy(pCond);
56   return;
57 }
58
59 rtsBool
60 broadcastCondition ( Condition* pCond )
61 {
62   return (pthread_cond_broadcast(pCond) == 0);
63 }
64
65 rtsBool
66 signalCondition ( Condition* pCond )
67 {
68   return (pthread_cond_signal(pCond) == 0);
69 }
70
71 rtsBool
72 waitCondition ( Condition* pCond, Mutex* pMut )
73 {
74   return (pthread_cond_wait(pCond,pMut) == 0);
75 }
76
77 void
78 yieldThread()
79 {
80   sched_yield();
81   return;
82 }
83
84 void
85 shutdownThread()
86 {
87   pthread_exit(NULL);
88 }
89
90 int
91 createOSThread (OSThreadId* pId, OSThreadProc *startProc, void *param)
92 {
93   int result = pthread_create(pId, NULL, (void *(*)(void *))startProc, param);
94   if(!result)
95     pthread_detach(*pId);
96   return result;
97 }
98
99 OSThreadId
100 osThreadId()
101 {
102   return pthread_self();
103 }
104
105 rtsBool
106 osThreadIsAlive(OSThreadId id STG_UNUSED)
107 {
108     // no good way to implement this on POSIX, AFAICT.  Returning true
109     // is safe.
110     return rtsTrue;
111 }
112
113 void
114 initMutex(Mutex* pMut)
115 {
116 #if defined(DEBUG)
117     pthread_mutexattr_t attr;
118     pthread_mutexattr_init(&attr);
119     pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_ERRORCHECK);
120     pthread_mutex_init(pMut,&attr);
121 #else
122     pthread_mutex_init(pMut,NULL);
123 #endif
124     return;
125 }
126 void
127 closeMutex(Mutex* pMut)
128 {
129     pthread_mutex_destroy(pMut);
130 }
131
132 void
133 newThreadLocalKey (ThreadLocalKey *key)
134 {
135     int r;
136     if ((r = pthread_key_create(key, NULL)) != 0) {
137         barf("newThreadLocalKey: %s", strerror(r));
138     }
139 }
140
141 void *
142 getThreadLocalVar (ThreadLocalKey *key)
143 {
144     return pthread_getspecific(*key);
145     // Note: a return value of NULL can indicate that either the key
146     // is not valid, or the key is valid and the data value has not
147     // yet been set.  We need to use the latter case, so we cannot
148     // detect errors here.
149 }
150
151 void
152 setThreadLocalVar (ThreadLocalKey *key, void *value)
153 {
154     int r;
155     if ((r = pthread_setspecific(*key,value)) != 0) {
156         barf("setThreadLocalVar: %s", strerror(r));
157     }
158 }
159
160 void
161 freeThreadLocalKey (ThreadLocalKey *key)
162 {
163     int r;
164     if ((r = pthread_key_delete(*key)) != 0) {
165         barf("freeThreadLocalKey: %s", strerror(r));
166     }
167 }
168
169 static void *
170 forkOS_createThreadWrapper ( void * entry )
171 {
172     Capability *cap;
173     cap = rts_lock();
174     cap = rts_evalStableIO(cap, (HsStablePtr) entry, NULL);
175     taskTimeStamp(myTask());
176     rts_unlock(cap);
177     return NULL;
178 }
179
180 int
181 forkOS_createThread ( HsStablePtr entry )
182 {
183     pthread_t tid;
184     int result = pthread_create(&tid, NULL,
185                                 forkOS_createThreadWrapper, (void*)entry);
186     if(!result)
187         pthread_detach(tid);
188     return result;
189 }
190
191 nat
192 getNumberOfProcessors (void)
193 {
194     static nat nproc = 0;
195
196     if (nproc == 0) {
197 #if defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN)
198         nproc = sysconf(_SC_NPROCESSORS_ONLN);
199 #elif defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_CONF)
200         nproc = sysconf(_SC_NPROCESSORS_CONF);
201 #else
202         nproc = 1;
203 #endif
204     }
205
206     return nproc;
207 }
208
209 // Schedules the thread to run on CPU n of m.  m may be less than the
210 // number of physical CPUs, in which case, the thread will be allowed
211 // to run on CPU n, n+m, n+2m etc.
212 void
213 setThreadAffinity (nat n, nat m)
214 {
215 #if defined(HAVE_SCHED_H) && defined(HAVE_SCHED_SETAFFINITY)
216     nat nproc;
217     cpu_set_t cs;
218     nat i;
219
220     nproc = getNumberOfProcessors();
221     CPU_ZERO(&cs);
222     for (i = n; i < nproc; i+=m) {
223         CPU_SET(n, &cs);
224     }
225     sched_setaffinity(0, sizeof(cpu_set_t), &cs);
226 #endif
227 }
228
229 #else /* !defined(THREADED_RTS) */
230
231 int
232 forkOS_createThread ( HsStablePtr entry STG_UNUSED )
233 {
234     return -1;
235 }
236
237 #endif /* !defined(THREADED_RTS) */