* testsuite/18_support/numeric_limits.cc (test_extrema): Fix typo.
[gcc.git] / libjava / win32-threads.cc
1 // win32-threads.cc - interface between libjava and Win32 threads.
2
3 /* Copyright (C) 1998, 1999 Free Software Foundation, Inc.
4
5 This file is part of libgcj.
6
7 This software is copyrighted work licensed under the terms of the
8 Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
9 details. */
10
11 #include <config.h>
12
13 // If we're using the Boehm GC, then we need to override some of the
14 // thread primitives. This is fairly gross.
15 #ifdef HAVE_BOEHM_GC
16 extern "C"
17 {
18 #include <gc.h>
19 // <windows.h> #define's STRICT, which conflicts with Modifier.h
20 #undef STRICT
21 };
22 #endif /* HAVE_BOEHM_GC */
23
24 #include <gcj/cni.h>
25 #include <jvm.h>
26 #include <java/lang/Thread.h>
27 #include <java/lang/System.h>
28
29 #include <errno.h>
30
31 #ifndef ETIMEDOUT
32 #define ETIMEDOUT 116
33 #endif
34
35 // This is used to implement thread startup.
36 struct starter
37 {
38 _Jv_ThreadStartFunc *method;
39 _Jv_Thread_t *data;
40 };
41
42 // Controls access to the variable below
43 static HANDLE daemon_mutex;
44 static HANDLE daemon_cond;
45 // Number of non-daemon threads - _Jv_ThreadWait returns when this is 0
46 static int non_daemon_count;
47
48 // TLS key get Java object representing the thread
49 DWORD _Jv_ThreadKey;
50 // TLS key to get _Jv_Thread_t* representing the thread
51 DWORD _Jv_ThreadDataKey;
52
53 //
54 // These are the flags that can appear in _Jv_Thread_t.
55 //
56
57 // Thread started.
58 #define FLAG_START 0x01
59 // Thread is daemon.
60 #define FLAG_DAEMON 0x02
61
62 //
63 // Condition variables.
64 //
65
66 // we do lazy creation of Events since CreateEvent() is insanely
67 // expensive, and because the rest of libgcj will call _Jv_CondInit
68 // when only a mutex is needed.
69
70 inline void
71 ensure_condvar_initialized(_Jv_ConditionVariable_t *cv)
72 {
73 if (cv->ev[0] == 0) {
74 cv->ev[0] = CreateEvent (NULL, 0, 0, NULL);
75 if (cv->ev[0] == 0) JvFail("CreateEvent() failed");
76 cv->ev[1] = CreateEvent (NULL, 1, 0, NULL);
77 if (cv->ev[1] == 0) JvFail("CreateEvent() failed");
78 }
79 }
80
81 // Reimplementation of the general algorithm described at
82 // http://www.cs.wustl.edu/~schmidt/win32-cv-1.html (isomorphic to
83 // 3.2, not a cut-and-paste).
84
85 int
86 _Jv_CondWait(_Jv_ConditionVariable_t *cv, _Jv_Mutex_t *mu, jlong millis, jint nanos)
87 {
88
89 EnterCriticalSection(&cv->count_mutex);
90 ensure_condvar_initialized(cv);
91 cv->blocked_count++;
92 LeaveCriticalSection(&cv->count_mutex);
93
94 DWORD time;
95 if ((millis == 0) && (nanos > 0)) time = 1;
96 else if (millis == 0) time = INFINITE;
97 else time = millis;
98
99 _Jv_MutexUnlock (mu);
100
101 DWORD rval = WaitForMultipleObjects (2, &(cv->ev[0]), 0, time);
102
103 EnterCriticalSection(&cv->count_mutex);
104 cv->blocked_count--;
105 // If we were unblocked by the second event (the broadcast one) and nobody is
106 // left, then reset the signal.
107 int last_waiter = rval == WAIT_OBJECT_0 + 1 && cv->blocked_count == 0;
108 LeaveCriticalSection(&cv->count_mutex);
109
110 if (last_waiter) ResetEvent(&cv->ev[1]);
111
112 _Jv_MutexLock (mu);
113
114 if (rval == WAIT_FAILED) return GetLastError();
115 else if (rval == WAIT_TIMEOUT) return ETIMEDOUT;
116 else return 0;
117 }
118
119 void
120 _Jv_CondInit (_Jv_ConditionVariable_t *cv)
121 {
122 // we do lazy creation of Events since CreateEvent() is insanely expensive
123 cv->ev[0] = 0;
124 InitializeCriticalSection(&cv->count_mutex);
125 cv->blocked_count = 0;
126 }
127
128 void
129 _Jv_CondDestroy (_Jv_ConditionVariable_t *cv)
130 {
131 if (cv->ev[0] != 0) CloseHandle(cv->ev[0]);
132 cv = NULL;
133 }
134
135 int
136 _Jv_CondNotify (_Jv_ConditionVariable_t *cv, _Jv_Mutex_t *)
137 {
138 EnterCriticalSection(&cv->count_mutex);
139 ensure_condvar_initialized(cv);
140 int somebody_is_blocked = cv->blocked_count > 0;
141 LeaveCriticalSection(&cv->count_mutex);
142
143 if (somebody_is_blocked) return SetEvent (cv->ev[0]) ? 0 : GetLastError();
144 else return 0;
145 }
146
147 int
148 _Jv_CondNotifyAll (_Jv_ConditionVariable_t *cv, _Jv_Mutex_t *)
149 {
150 EnterCriticalSection(&cv->count_mutex);
151 ensure_condvar_initialized(cv);
152 int somebody_is_blocked = cv->blocked_count > 0;
153 LeaveCriticalSection(&cv->count_mutex);
154
155 if (somebody_is_blocked) return SetEvent (cv->ev[1]) ? 0 : GetLastError();
156 else return 0;
157 }
158
159 //
160 // Threads.
161 //
162
163 void
164 _Jv_InitThreads (void)
165 {
166 _Jv_ThreadKey = TlsAlloc();
167 _Jv_ThreadDataKey = TlsAlloc();
168 daemon_mutex = CreateMutex(NULL, 0, NULL);
169 daemon_cond = CreateEvent(NULL, 0, 0, NULL);
170 non_daemon_count = 0;
171 }
172
173 _Jv_Thread_t *
174 _Jv_ThreadInitData (java::lang::Thread* obj)
175 {
176 _Jv_Thread_t *data = (_Jv_Thread_t*)_Jv_Malloc(sizeof(_Jv_Thread_t));
177 data->flags = 0;
178 data->thread_obj = obj;
179
180 return data;
181 }
182
183 void
184 _Jv_ThreadDestroyData (_Jv_Thread_t *data)
185 {
186 _Jv_Free(data);
187 }
188
189 void
190 _Jv_ThreadSetPriority (_Jv_Thread_t *data, jint prio)
191 {
192 int actual = THREAD_PRIORITY_NORMAL;
193
194 if (data->flags & FLAG_START)
195 {
196 switch (prio)
197 {
198 case 10:
199 actual = THREAD_PRIORITY_TIME_CRITICAL;
200 break;
201 case 9:
202 actual = THREAD_PRIORITY_HIGHEST;
203 break;
204 case 8:
205 case 7:
206 actual = THREAD_PRIORITY_ABOVE_NORMAL;
207 break;
208 case 6:
209 case 5:
210 actual = THREAD_PRIORITY_NORMAL;
211 break;
212 case 4:
213 case 3:
214 actual = THREAD_PRIORITY_BELOW_NORMAL;
215 break;
216 case 2:
217 actual = THREAD_PRIORITY_LOWEST;
218 break;
219 case 1:
220 actual = THREAD_PRIORITY_IDLE;
221 break;
222 }
223 SetThreadPriority(data->handle, actual);
224 }
225 }
226
227 void
228 _Jv_ThreadRegister (_Jv_Thread_t *data)
229 {
230 TlsSetValue (_Jv_ThreadKey, data->thread_obj);
231 TlsSetValue (_Jv_ThreadDataKey, data);
232 }
233
234 void
235 _Jv_ThreadUnRegister ()
236 {
237 TlsSetValue (_Jv_ThreadKey, NULL);
238 TlsSetValue (_Jv_ThreadDataKey, NULL);
239 }
240
241 // This function is called when a thread is started. We don't arrange
242 // to call the `run' method directly, because this function must
243 // return a value.
244 static DWORD WINAPI
245 really_start (void* x)
246 {
247 struct starter *info = (struct starter *) x;
248
249 _Jv_ThreadRegister (info->data);
250
251 info->method (info->data->thread_obj);
252
253 if (! (info->data->flags & FLAG_DAEMON))
254 {
255 WaitForSingleObject (daemon_mutex, INFINITE);
256 non_daemon_count--;
257 if (! non_daemon_count)
258 PulseEvent (daemon_cond);
259 ReleaseMutex (daemon_mutex);
260 }
261
262 return 0;
263 }
264
265 void
266 _Jv_ThreadStart (java::lang::Thread *thread, _Jv_Thread_t *data, _Jv_ThreadStartFunc *meth)
267 {
268 DWORD id;
269 struct starter *info;
270
271 // Do nothing if thread has already started
272 if (data->flags & FLAG_START)
273 return;
274 data->flags |= FLAG_START;
275
276 // FIXME: handle marking the info object for GC.
277 info = (struct starter *) _Jv_AllocBytes (sizeof (struct starter));
278 info->method = meth;
279 info->data = data;
280
281 if (! thread->isDaemon ())
282 {
283 WaitForSingleObject (daemon_mutex, INFINITE);
284 non_daemon_count++;
285 ReleaseMutex (daemon_mutex);
286 }
287 else
288 data->flags |= FLAG_DAEMON;
289
290 HANDLE h = GC_CreateThread(NULL, 0, really_start, info, 0, &id);
291 _Jv_ThreadSetPriority(data, thread->getPriority());
292
293 //if (!h)
294 //JvThrow ();
295 }
296
297 void
298 _Jv_ThreadWait (void)
299 {
300 WaitForSingleObject(daemon_mutex, INFINITE);
301 if(non_daemon_count)
302 SignalObjectAndWait(daemon_mutex, daemon_cond, INFINITE, 0);
303 ReleaseMutex(daemon_mutex);
304 }
305
306 void
307 _Jv_ThreadInterrupt (_Jv_Thread_t *data)
308 {
309 MessageBox(NULL, "Unimplemented", "win32-threads.cc:_Jv_ThreadInterrupt", MB_OK);
310 // FIXME:
311 }