source: trunk/third/gcc/libjava/win32-threads.cc @ 18474

Revision 18474, 7.1 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18473, which included commits to RCS files with non-trunk default branches.
Line 
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
7This software is copyrighted work licensed under the terms of the
8Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
9details.  */
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
16extern "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.
36struct starter
37{
38  _Jv_ThreadStartFunc *method;
39  _Jv_Thread_t *data;
40};
41
42// Controls access to the variable below
43static HANDLE daemon_mutex;
44static HANDLE daemon_cond;
45// Number of non-daemon threads - _Jv_ThreadWait returns when this is 0
46static int non_daemon_count;
47
48// TLS key get Java object representing the thread
49DWORD _Jv_ThreadKey;
50// TLS key to get _Jv_Thread_t* representing the thread
51DWORD _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
70inline void
71ensure_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
85int
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
119void
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
128void
129_Jv_CondDestroy (_Jv_ConditionVariable_t *cv)
130{
131  if (cv->ev[0] != 0) CloseHandle(cv->ev[0]);
132  cv = NULL;
133}
134
135int
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
147int
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
163void
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
183void
184_Jv_ThreadDestroyData (_Jv_Thread_t *data)
185{
186  _Jv_Free(data);
187}
188
189void
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
227void
228_Jv_ThreadRegister (_Jv_Thread_t *data)
229{
230  TlsSetValue (_Jv_ThreadKey, data->thread_obj);
231  TlsSetValue (_Jv_ThreadDataKey, data);
232}
233
234void
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.
244static DWORD WINAPI
245really_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
265void
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
297void
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
306void
307_Jv_ThreadInterrupt (_Jv_Thread_t *data)
308{
309  MessageBox(NULL, "Unimplemented", "win32-threads.cc:_Jv_ThreadInterrupt", MB_OK);
310  // FIXME:
311}
Note: See TracBrowser for help on using the repository browser.