| //===- 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 |
| } |
| |
| |
| } |