blob: 197185b68d5d7a7cdcb1ae15f2ed4853bf5bd424 [file] [log] [blame]
//===- ClasspathVMThread.cpp - GNU classpath java/lang/VMThread -----------===//
//
// The VMKit project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "types.h"
#include "Classpath.h"
#include "JavaArray.h"
#include "JavaClass.h"
#include "JavaObject.h"
#include "JavaThread.h"
#include "JavaUpcalls.h"
#include "Jnjvm.h"
using namespace j3;
extern "C" {
// Never throws.
// Never calls Java code.
JNIEXPORT JavaObject* JNICALL Java_java_lang_VMThread_currentThread(
#ifdef NATIVE_JNI
JNIEnv *env,
jclass clazz
#endif
) {
return JavaThread::get()->currentThread();
}
void start(JavaThread* thread) {
JavaObjectVMThread* vmThread = NULL;
JavaObject* javaThread = NULL;
llvm_gcroot(vmThread, 0);
llvm_gcroot(javaThread, 0);
Jnjvm* vm = thread->getJVM();
// Wait some time to let the creator initialise these fields.
while ((thread->javaThread == NULL) || (thread->vmThread == NULL)) {
vmkit::Thread::yield();
}
// Ok, now that the thread is created we can set the the value of vmdata,
// which is the JavaThread object.
vmThread = (JavaObjectVMThread*)thread->vmThread;
assert(vmThread && "Didn't fix the vmThread of a j3 thread");
assert(vmThread->getVirtualTable());
JavaObjectVMThread::setVmdata(vmThread, thread);
UserClass* vmthClass = (UserClass*)JavaObject::getClass(vmThread);
javaThread = thread->javaThread;
assert(javaThread && "Didn't fix the javaThread of a j3 thread");
assert(vmThread->getVirtualTable());
assert(javaThread->getVirtualTable());
// Run the VMThread::run function
vm->upcalls->runVMThread->invokeIntSpecial(vm, vmthClass, vmThread);
// Remove the thread from the list.
bool isDaemon = vm->upcalls->daemon->getInstanceInt8Field(javaThread);
if (!isDaemon) {
vm->threadSystem.leave();
}
}
JNIEXPORT void JNICALL Java_java_lang_VMThread_start(
#ifdef NATIVE_JNI
JNIEnv *env,
#endif
JavaObject* vmThread, sint64 stackSize) {
JavaObject* javaThread = 0;
llvm_gcroot(vmThread, 0);
llvm_gcroot(javaThread, 0);
BEGIN_NATIVE_EXCEPTION(0)
Jnjvm* vm = JavaThread::get()->getJVM();
// Classpath has set this field.
javaThread = vm->upcalls->assocThread->getInstanceObjectField(vmThread);
assert(javaThread && "VMThread with no Java equivalent");
JavaThread* th = new JavaThread(vm);
if (!th) vm->outOfMemoryError();
// If the thread is not a daemon, it is added to the list of threads to
// wait until exit.
bool isDaemon = vm->upcalls->daemon->getInstanceInt8Field(javaThread);
if (!isDaemon) {
vm->threadSystem.enter();
}
th->start((void (*)(vmkit::Thread*))start);
// Now that the thread has been created, initialise its object fields.
th->initialise(javaThread, vmThread);
END_NATIVE_EXCEPTION
}
JNIEXPORT void JNICALL Java_java_lang_VMThread_interrupt(
#ifdef NATIVE_JNI
JNIEnv *env,
#endif
JavaObject* vmthread) {
gc* obj = NULL;
llvm_gcroot(obj, 0);
llvm_gcroot(vmthread, 0);
BEGIN_NATIVE_EXCEPTION(0)
Jnjvm* vm = JavaThread::get()->getJVM();
JavaField* field = vm->upcalls->vmdataVMThread;
// It's possible that the thread to be interrupted has not finished
// its initialization. Wait until the initialization is done.
while (field->getInstanceObjectField(vmthread) == 0)
vmkit::Thread::yield();
JavaThread* th = (JavaThread*)field->getInstanceObjectField(vmthread);
th->lockingThread.interruptFlag = 1;
th->parkLock.interrupt();
//th->parkLock.unpark();
vmkit::FatLock* lock = th->lockingThread.waitsOn;
// If the thread is blocked on a wait. We also verify nextWaiting in case
// the thread has been notified.
if (lock && th->lockingThread.nextWaiting) {
th->lockingThread.state = vmkit::LockingThread::StateInterrupted;
// Make sure the thread is waiting.
uint32 locked = 0;
while (true) {
locked = (lock->tryAcquire() == 0);
if (locked || (lock->getOwner() != th && lock->getOwner() != 0))
break;
else vmkit::Thread::yield();
}
// Interrupt the thread.
th->lockingThread.varcond.signal();
// Release the lock if we acquired it.
if (locked) lock->release(obj = lock->getAssociatedObject(), vm->lockSystem);
}
// Here we could also raise a signal for interrupting I/O
END_NATIVE_EXCEPTION
}
// Never throws.
// Never calls Java code.
JNIEXPORT jboolean JNICALL Java_java_lang_VMThread_interrupted(
#ifdef NATIVE_JNI
JNIEnv *env,
jclass clazz,
#endif
) {
JavaThread* th = JavaThread::get();
uint32 interrupt = th->lockingThread.interruptFlag;
th->lockingThread.interruptFlag = 0;
return (jboolean)interrupt;
}
// Never throws.
// Never calls Java code.
JNIEXPORT jboolean JNICALL Java_java_lang_VMThread_isInterrupted(
#ifdef NATIVE_JNI
JNIEnv *env,
#endif
JavaObject* vmthread) {
llvm_gcroot(vmthread, 0);
Jnjvm* vm = JavaThread::get()->getJVM();
JavaField* field = vm->upcalls->vmdataVMThread;
JavaThread* th = (JavaThread*)field->getInstanceObjectField(vmthread);
return (jboolean)th->lockingThread.interruptFlag;
}
// Never throws.
// Never calls Java code.
JNIEXPORT void JNICALL Java_java_lang_VMThread_nativeSetPriority(
#ifdef NATIVE_JNI
JNIEnv *env,
#endif
JavaObject* vmthread, jint prio) {
// Currently not implemented
llvm_gcroot(vmthread, 0);
}
// Never throws.
// Never calls Java code.
JNIEXPORT void JNICALL Java_java_lang_VMThread_nativeStop(
#ifdef NATIVE_JNI
JNIEnv *env,
#endif
JavaObject* vmthread, JavaObject* exc) {
// Currently not implemented
llvm_gcroot(vmthread, 0);
llvm_gcroot(exc, 0);
}
// Never throws.
// Never calls Java code.
JNIEXPORT void JNICALL Java_java_lang_VMThread_yield(
#ifdef NATIVE_JNI
JNIEnv *env,
jclass clazz,
#endif
) {
vmkit::Thread::yield();
}
JNIEXPORT JavaObject* JNICALL Java_java_lang_VMThread_getState(
#ifdef NATIVE_JNI
JNIEnv *env,
#endif
JavaObject* vmthread) {
JavaString* obj = NULL;
llvm_gcroot(obj, 0);
llvm_gcroot(vmthread, 0);
BEGIN_NATIVE_EXCEPTION(0)
Jnjvm* vm = JavaThread::get()->getJVM();
JavaField* field = vm->upcalls->vmdataVMThread;
// It's possible that the thread to be interrupted has not finished
// its initialization. Wait until the initialization is done.
JavaThread* th = (JavaThread*)field->getInstanceObjectField(vmthread);
if (th == 0) {
obj = vm->asciizToStr("NEW");
return obj;
}
else {
switch (th->state) {
case vmkit::LockingThread::StateWaiting:
obj = vm->asciizToStr("WAITING");
return obj;
case vmkit::LockingThread::StateTimeWaiting:
obj = vm->asciizToStr("TIMED_WAITING");
return obj;
case vmkit::LockingThread::StateBlocked:
obj = vm->asciizToStr("BLOCKED");
return obj;
default: // both RUNNABLE and INTERRUPTED
obj = vm->asciizToStr("RUNNABLE");
return obj;
}
}
END_NATIVE_EXCEPTION
}
}