#include <config.h>
#ifdef HAVE_BOEHM_GC
extern "C"
{
#include <gc.h>
#undef STRICT
};
#endif
#include <gcj/cni.h>
#include <jvm.h>
#include <java/lang/Thread.h>
#include <java/lang/System.h>
#include <errno.h>
#ifndef ETIMEDOUT
#define ETIMEDOUT 116
#endif
struct starter
{
_Jv_ThreadStartFunc *method;
_Jv_Thread_t *data;
};
static HANDLE daemon_mutex;
static HANDLE daemon_cond;
static int non_daemon_count;
DWORD _Jv_ThreadKey;
DWORD _Jv_ThreadDataKey;
#define FLAG_START 0x01
#define FLAG_DAEMON 0x02
inline void
ensure_condvar_initialized(_Jv_ConditionVariable_t *cv)
{
if (cv->ev[0] == 0)
{
cv->ev[0] = CreateEvent (NULL, 0, 0, NULL);
if (cv->ev[0] == 0) JvFail("CreateEvent() failed");
cv->ev[1] = CreateEvent (NULL, 1, 0, NULL);
if (cv->ev[1] == 0) JvFail("CreateEvent() failed");
}
}
inline void
ensure_interrupt_event_initialized(HANDLE& rhEvent)
{
if (!rhEvent)
{
rhEvent = CreateEvent (NULL, 0, 0, NULL);
if (!rhEvent) JvFail("CreateEvent() failed");
}
}
int
_Jv_CondWait(_Jv_ConditionVariable_t *cv, _Jv_Mutex_t *mu, jlong millis, jint nanos)
{
if (mu->owner != GetCurrentThreadId ( ))
return _JV_NOT_OWNER;
_Jv_Thread_t *current = _Jv_ThreadCurrentData ();
java::lang::Thread *current_obj = _Jv_ThreadCurrent ();
EnterCriticalSection (¤t->interrupt_mutex);
ensure_interrupt_event_initialized (current->interrupt_event);
jboolean interrupted = current_obj->interrupt_flag;
LeaveCriticalSection (¤t->interrupt_mutex);
if (interrupted)
{
return _JV_INTERRUPTED;
}
EnterCriticalSection (&cv->count_mutex);
ensure_condvar_initialized (cv);
cv->blocked_count++;
LeaveCriticalSection (&cv->count_mutex);
DWORD time;
if ((millis == 0) && (nanos > 0)) time = 1;
else if (millis == 0) time = INFINITE;
else time = millis;
int count = mu->refcount;
int curcount = count;
while (curcount > 0)
{
_Jv_MutexUnlock (mu);
--curcount;
}
HANDLE arh[3];
arh[0] = cv->ev[0];
arh[1] = cv->ev[1];
arh[2] = current->interrupt_event;
DWORD rval = WaitForMultipleObjects (3, arh, 0, time);
EnterCriticalSection (¤t->interrupt_mutex);
if (rval == (WAIT_OBJECT_0 + 2))
current_obj->interrupt_flag = true;
interrupted = current_obj->interrupt_flag;
LeaveCriticalSection (¤t->interrupt_mutex);
EnterCriticalSection(&cv->count_mutex);
cv->blocked_count--;
int last_waiter = (rval == (WAIT_OBJECT_0 + 1)) && (cv->blocked_count == 0);
LeaveCriticalSection(&cv->count_mutex);
if (last_waiter)
ResetEvent (cv->ev[1]);
while (curcount < count)
{
_Jv_MutexLock (mu);
++curcount;
}
return interrupted ? _JV_INTERRUPTED : 0;
}
void
_Jv_CondInit (_Jv_ConditionVariable_t *cv)
{
cv->ev[0] = 0;
InitializeCriticalSection (&cv->count_mutex);
cv->blocked_count = 0;
}
void
_Jv_CondDestroy (_Jv_ConditionVariable_t *cv)
{
if (cv->ev[0] != 0)
{
CloseHandle (cv->ev[0]);
CloseHandle (cv->ev[1]);
cv->ev[0] = 0;
}
DeleteCriticalSection (&cv->count_mutex);
}
int
_Jv_CondNotify (_Jv_ConditionVariable_t *cv, _Jv_Mutex_t *mu)
{
if (mu->owner != GetCurrentThreadId ( ))
return _JV_NOT_OWNER;
EnterCriticalSection (&cv->count_mutex);
ensure_condvar_initialized (cv);
int somebody_is_blocked = cv->blocked_count > 0;
LeaveCriticalSection (&cv->count_mutex);
if (somebody_is_blocked)
SetEvent (cv->ev[0]);
return 0;
}
int
_Jv_CondNotifyAll (_Jv_ConditionVariable_t *cv, _Jv_Mutex_t *mu)
{
if (mu->owner != GetCurrentThreadId ( ))
return _JV_NOT_OWNER;
EnterCriticalSection (&cv->count_mutex);
ensure_condvar_initialized (cv);
int somebody_is_blocked = cv->blocked_count > 0;
LeaveCriticalSection (&cv->count_mutex);
if (somebody_is_blocked)
SetEvent (cv->ev[1]);
return 0;
}
void
_Jv_InitThreads (void)
{
_Jv_ThreadKey = TlsAlloc();
_Jv_ThreadDataKey = TlsAlloc();
daemon_mutex = CreateMutex (NULL, 0, NULL);
daemon_cond = CreateEvent (NULL, 1, 0, NULL);
non_daemon_count = 0;
}
_Jv_Thread_t *
_Jv_ThreadInitData (java::lang::Thread* obj)
{
_Jv_Thread_t *data = (_Jv_Thread_t*)_Jv_Malloc(sizeof(_Jv_Thread_t));
data->flags = 0;
data->handle = 0;
data->thread_obj = obj;
data->interrupt_event = 0;
InitializeCriticalSection (&data->interrupt_mutex);
return data;
}
void
_Jv_ThreadDestroyData (_Jv_Thread_t *data)
{
DeleteCriticalSection (&data->interrupt_mutex);
if (data->interrupt_event)
CloseHandle(data->interrupt_event);
CloseHandle(data->handle);
_Jv_Free(data);
}
void
_Jv_ThreadSetPriority (_Jv_Thread_t *data, jint prio)
{
int actual = THREAD_PRIORITY_NORMAL;
if (data->flags & FLAG_START)
{
switch (prio)
{
case 10:
actual = THREAD_PRIORITY_TIME_CRITICAL;
break;
case 9:
actual = THREAD_PRIORITY_HIGHEST;
break;
case 8:
case 7:
actual = THREAD_PRIORITY_ABOVE_NORMAL;
break;
case 6:
case 5:
actual = THREAD_PRIORITY_NORMAL;
break;
case 4:
case 3:
actual = THREAD_PRIORITY_BELOW_NORMAL;
break;
case 2:
actual = THREAD_PRIORITY_LOWEST;
break;
case 1:
actual = THREAD_PRIORITY_IDLE;
break;
}
SetThreadPriority(data->handle, actual);
}
}
void
_Jv_ThreadRegister (_Jv_Thread_t *data)
{
TlsSetValue (_Jv_ThreadKey, data->thread_obj);
TlsSetValue (_Jv_ThreadDataKey, data);
}
void
_Jv_ThreadUnRegister ()
{
TlsSetValue (_Jv_ThreadKey, NULL);
TlsSetValue (_Jv_ThreadDataKey, NULL);
}
static DWORD WINAPI
really_start (void* x)
{
struct starter *info = (struct starter *) x;
_Jv_ThreadRegister (info->data);
info->method (info->data->thread_obj);
if (! (info->data->flags & FLAG_DAEMON))
{
WaitForSingleObject (daemon_mutex, INFINITE);
non_daemon_count--;
if (! non_daemon_count)
SetEvent (daemon_cond);
ReleaseMutex (daemon_mutex);
}
return 0;
}
void
_Jv_ThreadStart (java::lang::Thread *thread, _Jv_Thread_t *data, _Jv_ThreadStartFunc *meth)
{
DWORD id;
struct starter *info;
if (data->flags & FLAG_START)
return;
data->flags |= FLAG_START;
info = (struct starter *) _Jv_AllocBytes (sizeof (struct starter));
info->method = meth;
info->data = data;
if (! thread->isDaemon ())
{
WaitForSingleObject (daemon_mutex, INFINITE);
non_daemon_count++;
ReleaseMutex (daemon_mutex);
}
else
data->flags |= FLAG_DAEMON;
data->handle = GC_CreateThread(NULL, 0, really_start, info, 0, &id);
_Jv_ThreadSetPriority(data, thread->getPriority());
}
void
_Jv_ThreadWait (void)
{
WaitForSingleObject (daemon_mutex, INFINITE);
if (non_daemon_count)
{
ReleaseMutex (daemon_mutex);
WaitForSingleObject (daemon_cond, INFINITE);
}
}
HANDLE
_Jv_Win32GetInterruptEvent (void)
{
_Jv_Thread_t *current = _Jv_ThreadCurrentData ();
EnterCriticalSection (¤t->interrupt_mutex);
ensure_interrupt_event_initialized (current->interrupt_event);
HANDLE hEvent = current->interrupt_event;
LeaveCriticalSection (¤t->interrupt_mutex);
return hEvent;
}
void
_Jv_ThreadInterrupt (_Jv_Thread_t *data)
{
EnterCriticalSection (&data->interrupt_mutex);
ensure_interrupt_event_initialized (data->interrupt_event);
data->thread_obj->interrupt_flag = true;
SetEvent (data->interrupt_event);
LeaveCriticalSection (&data->interrupt_mutex);
}