Partial fix for #926
[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
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   Sleep(0);
90   return;
91 }
92
93 void
94 shutdownThread()
95 {
96   _endthreadex(0);
97 }
98
99 int
100 createOSThread (OSThreadId* pId, OSThreadProc *startProc, void *param)
101 {
102   
103   return (_beginthreadex ( NULL,  /* default security attributes */
104                            0,
105                            (unsigned (__stdcall *)(void *)) startProc,
106                            param,
107                            0,
108                            (unsigned*)pId) == 0);
109 }
110
111 OSThreadId
112 osThreadId()
113 {
114   return GetCurrentThreadId();
115 }
116
117 rtsBool
118 osThreadIsAlive(OSThreadId id)
119 {
120     DWORD exit_code;
121     HANDLE hdl;
122     if (!(hdl = OpenThread(THREAD_QUERY_INFORMATION,FALSE,id))) {
123         sysErrorBelch("osThreadIsAlive: OpenThread");
124         stg_exit(EXIT_FAILURE);
125     }
126     if (!GetExitCodeThread(hdl, &exit_code)) {
127         sysErrorBelch("osThreadIsAlive: GetExitCodeThread");
128         stg_exit(EXIT_FAILURE);
129     }
130     return (exit_code == STILL_ACTIVE);
131 }
132
133 #ifdef USE_CRITICAL_SECTIONS
134 void
135 initMutex (Mutex* pMut)
136 {
137     InitializeCriticalSectionAndSpinCount(pMut,4000);
138 }
139 void
140 closeMutex (Mutex* pMut)
141 {
142     DeleteCriticalSection(pMut);
143 }
144 #else
145 void
146 initMutex (Mutex* pMut)
147 {
148   HANDLE h = CreateMutex ( NULL,  /* default sec. attributes */
149                            FALSE, /* not owned => initially signalled */
150                            NULL
151                            );
152   *pMut = h;
153   return;
154 }
155 void
156 closeMutex (Mutex* pMut)
157 {
158     CloseHandle(*pMut);
159 }
160 #endif
161
162 void
163 newThreadLocalKey (ThreadLocalKey *key)
164 {
165     DWORD r;
166     r = TlsAlloc();
167     if (r == TLS_OUT_OF_INDEXES) {
168         barf("newThreadLocalKey: out of keys");
169     }
170     *key = r;
171 }
172
173 void *
174 getThreadLocalVar (ThreadLocalKey *key)
175 {
176     void *r;
177     r = TlsGetValue(*key);
178 #ifdef DEBUG
179     // r is allowed to be NULL - it can mean that either there was an
180     // error or the stored value is in fact NULL.
181     if (GetLastError() != NO_ERROR) {
182         sysErrorBelch("getThreadLocalVar");
183         stg_exit(EXIT_FAILURE);
184     }
185 #endif
186     return r;
187 }
188
189 void
190 setThreadLocalVar (ThreadLocalKey *key, void *value)
191 {
192     BOOL b;
193     b = TlsSetValue(*key, value);
194     if (!b) {
195         sysErrorBelch("setThreadLocalVar");
196         stg_exit(EXIT_FAILURE);
197     }
198 }
199
200
201 static unsigned __stdcall
202 forkOS_createThreadWrapper ( void * entry )
203 {
204     Capability *cap;
205     cap = rts_lock();
206     cap = rts_evalStableIO(cap, (HsStablePtr) entry, NULL);
207     rts_unlock(cap);
208     return 0;
209 }
210
211 int
212 forkOS_createThread ( HsStablePtr entry )
213 {
214     unsigned long pId;
215     return (_beginthreadex ( NULL,  /* default security attributes */
216                            0,
217                            forkOS_createThreadWrapper,
218                            (void*)entry,
219                            0,
220                            (unsigned*)&pId) == 0);
221 }
222
223 #else /* !defined(THREADED_RTS) */
224
225 int
226 forkOS_createThread ( HsStablePtr entry STG_UNUSED )
227 {
228     return -1;
229 }
230
231 #endif /* !defined(THREADED_RTS) */