2002-11-21 Phil Edwards <pme@gcc.gnu.org>
[official-gcc.git] / libjava / win32-threads.cc
blobd31c1919a1e222e37f110861c7917df7eddd3176
1 // win32-threads.cc - interface between libjava and Win32 threads.
3 /* Copyright (C) 1998, 1999 Free Software Foundation, Inc.
5 This file is part of libgcj.
7 This software is copyrighted work licensed under the terms of the
8 Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
9 details. */
11 #include <config.h>
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"
18 #include <gc.h>
19 // <windows.h> #define's STRICT, which conflicts with Modifier.h
20 #undef STRICT
22 #endif /* HAVE_BOEHM_GC */
24 #include <gcj/cni.h>
25 #include <jvm.h>
26 #include <java/lang/Thread.h>
27 #include <java/lang/System.h>
29 #include <errno.h>
31 #ifndef ETIMEDOUT
32 #define ETIMEDOUT 116
33 #endif
35 // This is used to implement thread startup.
36 struct starter
38 _Jv_ThreadStartFunc *method;
39 _Jv_Thread_t *data;
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;
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;
54 // These are the flags that can appear in _Jv_Thread_t.
57 // Thread started.
58 #define FLAG_START 0x01
59 // Thread is daemon.
60 #define FLAG_DAEMON 0x02
63 // Condition variables.
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.
70 inline void
71 ensure_condvar_initialized(_Jv_ConditionVariable_t *cv)
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");
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).
85 int
86 _Jv_CondWait(_Jv_ConditionVariable_t *cv, _Jv_Mutex_t *mu, jlong millis, jint nanos)
89 EnterCriticalSection(&cv->count_mutex);
90 ensure_condvar_initialized(cv);
91 cv->blocked_count++;
92 LeaveCriticalSection(&cv->count_mutex);
94 DWORD time;
95 if ((millis == 0) && (nanos > 0)) time = 1;
96 else if (millis == 0) time = INFINITE;
97 else time = millis;
99 _Jv_MutexUnlock (mu);
101 DWORD rval = WaitForMultipleObjects (2, &(cv->ev[0]), 0, time);
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);
110 if (last_waiter) ResetEvent(&cv->ev[1]);
112 _Jv_MutexLock (mu);
114 if (rval == WAIT_FAILED) return GetLastError();
115 else if (rval == WAIT_TIMEOUT) return ETIMEDOUT;
116 else return 0;
119 void
120 _Jv_CondInit (_Jv_ConditionVariable_t *cv)
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;
128 void
129 _Jv_CondDestroy (_Jv_ConditionVariable_t *cv)
131 if (cv->ev[0] != 0) CloseHandle(cv->ev[0]);
132 cv = NULL;
136 _Jv_CondNotify (_Jv_ConditionVariable_t *cv, _Jv_Mutex_t *)
138 EnterCriticalSection(&cv->count_mutex);
139 ensure_condvar_initialized(cv);
140 int somebody_is_blocked = cv->blocked_count > 0;
141 LeaveCriticalSection(&cv->count_mutex);
143 if (somebody_is_blocked) return SetEvent (cv->ev[0]) ? 0 : GetLastError();
144 else return 0;
148 _Jv_CondNotifyAll (_Jv_ConditionVariable_t *cv, _Jv_Mutex_t *)
150 EnterCriticalSection(&cv->count_mutex);
151 ensure_condvar_initialized(cv);
152 int somebody_is_blocked = cv->blocked_count > 0;
153 LeaveCriticalSection(&cv->count_mutex);
155 if (somebody_is_blocked) return SetEvent (cv->ev[1]) ? 0 : GetLastError();
156 else return 0;
160 // Threads.
163 void
164 _Jv_InitThreads (void)
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;
173 _Jv_Thread_t *
174 _Jv_ThreadInitData (java::lang::Thread* obj)
176 _Jv_Thread_t *data = (_Jv_Thread_t*)_Jv_Malloc(sizeof(_Jv_Thread_t));
177 data->flags = 0;
178 data->thread_obj = obj;
180 return data;
183 void
184 _Jv_ThreadDestroyData (_Jv_Thread_t *data)
186 _Jv_Free(data);
189 void
190 _Jv_ThreadSetPriority (_Jv_Thread_t *data, jint prio)
192 int actual = THREAD_PRIORITY_NORMAL;
194 if (data->flags & FLAG_START)
196 switch (prio)
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;
223 SetThreadPriority(data->handle, actual);
227 void
228 _Jv_ThreadRegister (_Jv_Thread_t *data)
230 TlsSetValue (_Jv_ThreadKey, data->thread_obj);
231 TlsSetValue (_Jv_ThreadDataKey, data);
234 void
235 _Jv_ThreadUnRegister ()
237 TlsSetValue (_Jv_ThreadKey, NULL);
238 TlsSetValue (_Jv_ThreadDataKey, NULL);
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)
247 struct starter *info = (struct starter *) x;
249 _Jv_ThreadRegister (info->data);
251 info->method (info->data->thread_obj);
253 if (! (info->data->flags & FLAG_DAEMON))
255 WaitForSingleObject (daemon_mutex, INFINITE);
256 non_daemon_count--;
257 if (! non_daemon_count)
258 PulseEvent (daemon_cond);
259 ReleaseMutex (daemon_mutex);
262 return 0;
265 void
266 _Jv_ThreadStart (java::lang::Thread *thread, _Jv_Thread_t *data, _Jv_ThreadStartFunc *meth)
268 DWORD id;
269 struct starter *info;
271 // Do nothing if thread has already started
272 if (data->flags & FLAG_START)
273 return;
274 data->flags |= FLAG_START;
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;
281 if (! thread->isDaemon ())
283 WaitForSingleObject (daemon_mutex, INFINITE);
284 non_daemon_count++;
285 ReleaseMutex (daemon_mutex);
287 else
288 data->flags |= FLAG_DAEMON;
290 HANDLE h = GC_CreateThread(NULL, 0, really_start, info, 0, &id);
291 _Jv_ThreadSetPriority(data, thread->getPriority());
293 //if (!h)
294 //JvThrow ();
297 void
298 _Jv_ThreadWait (void)
300 WaitForSingleObject(daemon_mutex, INFINITE);
301 if(non_daemon_count)
302 SignalObjectAndWait(daemon_mutex, daemon_cond, INFINITE, 0);
303 ReleaseMutex(daemon_mutex);
306 void
307 _Jv_ThreadInterrupt (_Jv_Thread_t *data)
309 MessageBox(NULL, "Unimplemented", "win32-threads.cc:_Jv_ThreadInterrupt", MB_OK);
310 // FIXME: