OSDN Git Service

Fix typos in previous.
[pf3gnuchains/gcc-fork.git] / libjava / win32-threads.cc
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
8 This software is copyrighted work licensed under the terms of the
9 Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
10 details.  */
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
17 extern "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.
37 struct starter
38 {
39   _Jv_ThreadStartFunc *method;
40   _Jv_Thread_t *data;
41 };
42
43 // Controls access to the variable below
44 static HANDLE daemon_mutex;
45 static HANDLE daemon_cond;
46 // Number of non-daemon threads - _Jv_ThreadWait returns when this is 0
47 static int non_daemon_count;
48
49 // TLS key get Java object representing the thread
50 DWORD _Jv_ThreadKey;
51 // TLS key to get _Jv_Thread_t* representing the thread
52 DWORD _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
71 inline void
72 ensure_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
88 int
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
123 void
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
132 void
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
146 int
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
163 int
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
184 void
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
204 void
205 _Jv_ThreadDestroyData (_Jv_Thread_t *data)
206 {
207   _Jv_Free(data);
208 }
209
210 void
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
248 void
249 _Jv_ThreadRegister (_Jv_Thread_t *data)
250 {
251   TlsSetValue (_Jv_ThreadKey, data->thread_obj);
252   TlsSetValue (_Jv_ThreadDataKey, data);
253 }
254
255 void
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.
265 static DWORD WINAPI
266 really_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
286 void
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
318 void
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
329 void
330 _Jv_ThreadInterrupt (_Jv_Thread_t *data)
331 {
332   MessageBox(NULL, "Unimplemented", "win32-threads.cc:_Jv_ThreadInterrupt", MB_OK);
333   // FIXME:
334 }