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