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