OSDN Git Service

* sh.c (gen_shl_and): Don't create a zero_extend if the operand
[pf3gnuchains/gcc-fork.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 }