source: trunk/src/gcc/libjava/win32-threads.cc@ 1595

Last change on this file since 1595 was 1392, checked in by bird, 21 years ago

This commit was generated by cvs2svn to compensate for changes in r1391,
which included commits to RCS files with non-trunk default branches.

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