fix haddock submodule pointer
[ghc-hetmet.git] / rts / win32 / 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 #define _WIN32_WINNT 0x0500
11
12 #include "Rts.h"
13 #if defined(THREADED_RTS)
14 #include "RtsUtils.h"
15 #include <windows.h>
16
17 /* For reasons not yet clear, the entire contents of process.h is protected 
18  * by __STRICT_ANSI__ not being defined.
19  */
20 #undef __STRICT_ANSI__
21 #include <process.h>
22
23 /* Win32 threads and synchronisation objects */
24
25 /* A Condition is represented by a Win32 Event object;
26  * a Mutex by a Mutex kernel object.
27  *
28  * ToDo: go through the defn and usage of these to
29  * make sure the semantics match up with that of 
30  * the (assumed) pthreads behaviour. This is really
31  * just a first pass at getting something compilable.
32  */
33
34 void
35 initCondition( Condition* pCond )
36 {
37   HANDLE h =  CreateEvent(NULL, 
38                           FALSE,  /* auto reset */
39                           FALSE,  /* initially not signalled */
40                           NULL); /* unnamed => process-local. */
41   
42   if ( h == NULL ) {
43       sysErrorBelch("initCondition: unable to create");
44       stg_exit(EXIT_FAILURE);
45   }
46   *pCond = h;
47   return;
48 }
49
50 void
51 closeCondition( Condition* pCond )
52 {
53   if ( CloseHandle(*pCond) == 0 ) {
54       sysErrorBelch("closeCondition: failed to close");
55   }
56   return;
57 }
58
59 rtsBool
60 broadcastCondition ( Condition* pCond )
61 {
62   PulseEvent(*pCond);
63   return rtsTrue;
64 }
65
66 rtsBool
67 signalCondition ( Condition* pCond )
68 {
69     if (SetEvent(*pCond) == 0) {
70         sysErrorBelch("SetEvent");
71         stg_exit(EXIT_FAILURE);
72     }
73     return rtsTrue;
74 }
75
76 rtsBool
77 waitCondition ( Condition* pCond, Mutex* pMut )
78 {
79   RELEASE_LOCK(pMut);
80   WaitForSingleObject(*pCond, INFINITE);
81   /* Hmm..use WaitForMultipleObjects() ? */
82   ACQUIRE_LOCK(pMut);
83   return rtsTrue;
84 }
85
86 void
87 yieldThread()
88 {
89   SwitchToThread();
90   return;
91 }
92
93 void
94 shutdownThread()
95 {
96   _endthreadex(0);
97   barf("_endthreadex returned"); // avoid gcc warning
98 }
99
100 int
101 createOSThread (OSThreadId* pId, OSThreadProc *startProc, void *param)
102 {
103   
104   return (_beginthreadex ( NULL,  /* default security attributes */
105                            0,
106                            (unsigned (__stdcall *)(void *)) startProc,
107                            param,
108                            0,
109                            (unsigned*)pId) == 0);
110 }
111
112 OSThreadId
113 osThreadId()
114 {
115   return GetCurrentThreadId();
116 }
117
118 rtsBool
119 osThreadIsAlive(OSThreadId id)
120 {
121     DWORD exit_code;
122     HANDLE hdl;
123     if (!(hdl = OpenThread(THREAD_QUERY_INFORMATION,FALSE,id))) {
124         sysErrorBelch("osThreadIsAlive: OpenThread");
125         stg_exit(EXIT_FAILURE);
126     }
127     if (!GetExitCodeThread(hdl, &exit_code)) {
128         sysErrorBelch("osThreadIsAlive: GetExitCodeThread");
129         stg_exit(EXIT_FAILURE);
130     }
131     return (exit_code == STILL_ACTIVE);
132 }
133
134 #ifdef USE_CRITICAL_SECTIONS
135 void
136 initMutex (Mutex* pMut)
137 {
138     InitializeCriticalSectionAndSpinCount(pMut,4000);
139 }
140 void
141 closeMutex (Mutex* pMut)
142 {
143     DeleteCriticalSection(pMut);
144 }
145 #else
146 void
147 initMutex (Mutex* pMut)
148 {
149   HANDLE h = CreateMutex ( NULL,  /* default sec. attributes */
150                            FALSE, /* not owned => initially signalled */
151                            NULL
152                            );
153   *pMut = h;
154   return;
155 }
156 void
157 closeMutex (Mutex* pMut)
158 {
159     CloseHandle(*pMut);
160 }
161 #endif
162
163 void
164 newThreadLocalKey (ThreadLocalKey *key)
165 {
166     DWORD r;
167     r = TlsAlloc();
168     if (r == TLS_OUT_OF_INDEXES) {
169         barf("newThreadLocalKey: out of keys");
170     }
171     *key = r;
172 }
173
174 void *
175 getThreadLocalVar (ThreadLocalKey *key)
176 {
177     void *r;
178     r = TlsGetValue(*key);
179 #ifdef DEBUG
180     // r is allowed to be NULL - it can mean that either there was an
181     // error or the stored value is in fact NULL.
182     if (GetLastError() != NO_ERROR) {
183         sysErrorBelch("getThreadLocalVar");
184         stg_exit(EXIT_FAILURE);
185     }
186 #endif
187     return r;
188 }
189
190 void
191 setThreadLocalVar (ThreadLocalKey *key, void *value)
192 {
193     BOOL b;
194     b = TlsSetValue(*key, value);
195     if (!b) {
196         sysErrorBelch("setThreadLocalVar");
197         stg_exit(EXIT_FAILURE);
198     }
199 }
200
201 void
202 freeThreadLocalKey (ThreadLocalKey *key)
203 {
204     BOOL r;
205     r = TlsFree(*key);
206     if (r == 0) {
207         DWORD dw = GetLastError();
208         barf("freeThreadLocalKey failed: %lu", dw);
209     }
210 }
211
212
213 static unsigned __stdcall
214 forkOS_createThreadWrapper ( void * entry )
215 {
216     Capability *cap;
217     cap = rts_lock();
218     cap = rts_evalStableIO(cap, (HsStablePtr) entry, NULL);
219     rts_unlock(cap);
220     return 0;
221 }
222
223 int
224 forkOS_createThread ( HsStablePtr entry )
225 {
226     unsigned long pId;
227     return (_beginthreadex ( NULL,  /* default security attributes */
228                            0,
229                            forkOS_createThreadWrapper,
230                            (void*)entry,
231                            0,
232                            (unsigned*)&pId) == 0);
233 }
234
235 nat
236 getNumberOfProcessors (void)
237 {
238     static nat nproc = 0;
239
240     if (nproc == 0) {
241         SYSTEM_INFO si;
242         GetSystemInfo(&si);
243         nproc = si.dwNumberOfProcessors;
244     }
245
246     return nproc;
247 }
248
249 void
250 setThreadAffinity (nat n, nat m) // cap N of M
251 {
252     HANDLE hThread;
253     DWORD_PTR mask, r;  // 64-bit win is required to handle more than 32 procs
254     nat nproc, i;
255
256     hThread = GetCurrentThread();
257
258     nproc = getNumberOfProcessors();
259
260     mask = 0;
261     for (i = n; i < nproc; i+=m) {
262         mask |= 1 << i;
263     }
264
265     r = SetThreadAffinityMask(hThread, mask);
266     if (r == 0) {
267         sysErrorBelch("SetThreadAffinity");
268         stg_exit(EXIT_FAILURE);
269     }
270 }
271
272 typedef BOOL (WINAPI *PCSIO)(HANDLE);
273
274 void
275 interruptOSThread (OSThreadId id)
276 {
277     HANDLE hdl;
278     PCSIO pCSIO;
279     if (!(hdl = OpenThread(THREAD_TERMINATE,FALSE,id))) {
280         sysErrorBelch("interruptOSThread: OpenThread");
281         stg_exit(EXIT_FAILURE);
282     }
283     pCSIO = (PCSIO) GetProcAddress(GetModuleHandle(TEXT("Kernel32.dll")), "CancelSynchronousIo");
284     if ( NULL != pCSIO ) {
285         pCSIO(hdl);
286     } else {
287         // Nothing to do, unfortunately
288     }
289 }
290
291 #else /* !defined(THREADED_RTS) */
292
293 int
294 forkOS_createThread ( HsStablePtr entry STG_UNUSED )
295 {
296     return -1;
297 }
298
299 #endif /* !defined(THREADED_RTS) */