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
13 // If we're using the Boehm GC, then we need to override some of the
14 // thread primitives. This is fairly gross.
19 // <windows.h> #define's STRICT, which conflicts with Modifier.h
22 #endif /* HAVE_BOEHM_GC */
26 #include <java/lang/Thread.h>
27 #include <java/lang/System.h>
35 // This is used to implement thread startup.
38 _Jv_ThreadStartFunc
*method
;
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
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.
58 #define FLAG_START 0x01
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.
71 ensure_condvar_initialized(_Jv_ConditionVariable_t
*cv
)
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).
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
);
92 LeaveCriticalSection(&cv
->count_mutex
);
95 if ((millis
== 0) && (nanos
> 0)) time
= 1;
96 else if (millis
== 0) time
= INFINITE
;
101 DWORD rval
= WaitForMultipleObjects (2, &(cv
->ev
[0]), 0, time
);
103 EnterCriticalSection(&cv
->count_mutex
);
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]);
114 if (rval
== WAIT_FAILED
) return GetLastError();
115 else if (rval
== WAIT_TIMEOUT
) return ETIMEDOUT
;
120 _Jv_CondInit (_Jv_ConditionVariable_t
*cv
)
122 // we do lazy creation of Events since CreateEvent() is insanely expensive
124 InitializeCriticalSection(&cv
->count_mutex
);
125 cv
->blocked_count
= 0;
129 _Jv_CondDestroy (_Jv_ConditionVariable_t
*cv
)
131 if (cv
->ev
[0] != 0) CloseHandle(cv
->ev
[0]);
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();
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();
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;
174 _Jv_ThreadInitData (java::lang::Thread
* obj
)
176 _Jv_Thread_t
*data
= (_Jv_Thread_t
*)_Jv_Malloc(sizeof(_Jv_Thread_t
));
178 data
->thread_obj
= obj
;
184 _Jv_ThreadDestroyData (_Jv_Thread_t
*data
)
190 _Jv_ThreadSetPriority (_Jv_Thread_t
*data
, jint prio
)
192 int actual
= THREAD_PRIORITY_NORMAL
;
194 if (data
->flags
& FLAG_START
)
199 actual
= THREAD_PRIORITY_TIME_CRITICAL
;
202 actual
= THREAD_PRIORITY_HIGHEST
;
206 actual
= THREAD_PRIORITY_ABOVE_NORMAL
;
210 actual
= THREAD_PRIORITY_NORMAL
;
214 actual
= THREAD_PRIORITY_BELOW_NORMAL
;
217 actual
= THREAD_PRIORITY_LOWEST
;
220 actual
= THREAD_PRIORITY_IDLE
;
223 SetThreadPriority(data
->handle
, actual
);
228 _Jv_ThreadRegister (_Jv_Thread_t
*data
)
230 TlsSetValue (_Jv_ThreadKey
, data
->thread_obj
);
231 TlsSetValue (_Jv_ThreadDataKey
, data
);
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
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
);
257 if (! non_daemon_count
)
258 PulseEvent (daemon_cond
);
259 ReleaseMutex (daemon_mutex
);
266 _Jv_ThreadStart (java::lang::Thread
*thread
, _Jv_Thread_t
*data
, _Jv_ThreadStartFunc
*meth
)
269 struct starter
*info
;
271 // Do nothing if thread has already started
272 if (data
->flags
& FLAG_START
)
274 data
->flags
|= FLAG_START
;
276 // FIXME: handle marking the info object for GC.
277 info
= (struct starter
*) _Jv_AllocBytes (sizeof (struct starter
));
281 if (! thread
->isDaemon ())
283 WaitForSingleObject (daemon_mutex
, INFINITE
);
285 ReleaseMutex (daemon_mutex
);
288 data
->flags
|= FLAG_DAEMON
;
290 HANDLE h
= GC_CreateThread(NULL
, 0, really_start
, info
, 0, &id
);
291 _Jv_ThreadSetPriority(data
, thread
->getPriority());
298 _Jv_ThreadWait (void)
300 WaitForSingleObject(daemon_mutex
, INFINITE
);
302 SignalObjectAndWait(daemon_mutex
, daemon_cond
, INFINITE
, 0);
303 ReleaseMutex(daemon_mutex
);
307 _Jv_ThreadInterrupt (_Jv_Thread_t
*data
)
309 MessageBox(NULL
, "Unimplemented", "win32-threads.cc:_Jv_ThreadInterrupt", MB_OK
);