ed5c968cf1cfd6a609a16e3693680e769a9b1603
[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 "OSThreads.h"
15 #include "RtsUtils.h"
16 #include <windows.h>
17
18 /* For reasons not yet clear, the entire contents of process.h is protected 
19  * by __STRICT_ANSI__ not being defined.
20  */
21 #undef __STRICT_ANSI__
22 #include <process.h>
23
24 /* Win32 threads and synchronisation objects */
25
26 /* A Condition is represented by a Win32 Event object;
27  * a Mutex by a Mutex kernel object.
28  *
29  * ToDo: go through the defn and usage of these to
30  * make sure the semantics match up with that of 
31  * the (assumed) pthreads behaviour. This is really
32  * just a first pass at getting something compilable.
33  */
34
35 void
36 initCondition( Condition* pCond )
37 {
38   HANDLE h =  CreateEvent(NULL, 
39                           FALSE,  /* auto reset */
40                           FALSE,  /* initially not signalled */
41                           NULL); /* unnamed => process-local. */
42   
43   if ( h == NULL ) {
44       sysErrorBelch("initCondition: unable to create");
45       stg_exit(EXIT_FAILURE);
46   }
47   *pCond = h;
48   return;
49 }
50
51 void
52 closeCondition( Condition* pCond )
53 {
54   if ( CloseHandle(*pCond) == 0 ) {
55       sysErrorBelch("closeCondition: failed to close");
56   }
57   return;
58 }
59
60 rtsBool
61 broadcastCondition ( Condition* pCond )
62 {
63   PulseEvent(*pCond);
64   return rtsTrue;
65 }
66
67 rtsBool
68 signalCondition ( Condition* pCond )
69 {
70     if (SetEvent(*pCond) == 0) {
71         sysErrorBelch("SetEvent");
72         stg_exit(EXIT_FAILURE);
73     }
74     return rtsTrue;
75 }
76
77 rtsBool
78 waitCondition ( Condition* pCond, Mutex* pMut )
79 {
80   RELEASE_LOCK(pMut);
81   WaitForSingleObject(*pCond, INFINITE);
82   /* Hmm..use WaitForMultipleObjects() ? */
83   ACQUIRE_LOCK(pMut);
84   return rtsTrue;
85 }
86
87 void
88 yieldThread()
89 {
90   Sleep(0);
91   return;
92 }
93
94 void
95 shutdownThread()
96 {
97   _endthreadex(0);
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 #else /* !defined(THREADED_RTS) */
236
237 int
238 forkOS_createThread ( HsStablePtr entry STG_UNUSED )
239 {
240     return -1;
241 }
242
243 #endif /* !defined(THREADED_RTS) */