jlong rvmStartThread(Env* env, JavaThread* threadObj) { Env* newEnv = rvmCreateEnv(env->vm); if (!newEnv) { rvmThrowOutOfMemoryError(env); // rvmCreateEnv() doesn't throw OutOfMemoryError if allocation fails return 0; } rvmLockThreadsList(); if (threadObj->threadPtr != 0) { rvmThrowIllegalStateException(env, "thread has already been started"); rvmUnlockThreadsList(); return 0; } Thread* thread = allocThread(env); if (!thread) { rvmUnlockThreadsList(); return 0; } size_t stackSize = (size_t) threadObj->stackSize; if (stackSize == 0) { stackSize = THREAD_DEFAULT_STACK_SIZE; } else if (stackSize < THREAD_MIN_STACK_SIZE) { stackSize = THREAD_MIN_STACK_SIZE; } stackSize += THREAD_SIGNAL_STACK_SIZE; stackSize = (stackSize + THREAD_STACK_SIZE_MULTIPLE - 1) & ~(THREAD_STACK_SIZE_MULTIPLE - 1); pthread_attr_t threadAttr; pthread_attr_init(&threadAttr); pthread_attr_setdetachstate(&threadAttr, PTHREAD_CREATE_DETACHED); pthread_attr_setstacksize(&threadAttr, stackSize); pthread_attr_setguardsize(&threadAttr, THREAD_STACK_GUARD_SIZE); ThreadEntryPointArgs args = {0}; args.env = newEnv; args.thread = thread; args.threadObj = threadObj; int err = 0; if ((err = pthread_create(&thread->pThread, &threadAttr, startThreadEntryPoint, &args)) != 0) { rvmUnlockThreadsList(); rvmThrowInternalErrorErrno(env, err); return 0; } while (thread->status != THREAD_STARTING) { pthread_cond_wait(&threadStartCond, &threadsLock); } DL_PREPEND(threads, thread); pthread_cond_broadcast(&threadsChangedCond); thread->status = THREAD_VMWAIT; pthread_cond_broadcast(&threadStartCond); rvmUnlockThreadsList(); return PTR_TO_LONG(thread); }
void Java_java_lang_Thread_internalSetPriority(Env* env, Class* cls, JavaThread* threadObj, jint priority) { rvmLockThreadsList(); Thread* thread = (Thread*) LONG_TO_PTR(threadObj->threadPtr); if (thread) { rvmChangeThreadPriority(env, thread, priority); } rvmUnlockThreadsList(); }
void Java_java_lang_Thread_internalInterrupt(Env* env, Class* cls, JavaThread* threadObj) { rvmLockThreadsList(); Thread* thread = (Thread*) LONG_TO_PTR(threadObj->threadPtr); if (thread) { rvmThreadInterrupt(env, thread); } rvmUnlockThreadsList(); }
void Java_java_lang_Thread_internalSetName(Env* env, Class* cls, JavaThread* threadObj, Object* threadName) { rvmLockThreadsList(); Thread* thread = (Thread*) LONG_TO_PTR(threadObj->threadPtr); if (thread) { rvmThreadNameChanged(env, thread); } rvmUnlockThreadsList(); }
jint Java_java_lang_Thread_internalGetState(Env* env, Class* cls, JavaThread* threadObj) { rvmLockThreadsList(); Thread* thread = (Thread*) LONG_TO_PTR(threadObj->threadPtr); jint status = THREAD_ZOMBIE; // If thread==NULL we assume the thread has been finished if (thread) { status = thread->status; } rvmUnlockThreadsList(); return status; }
jboolean Java_java_lang_Thread_internalHoldsLock(Env* env, Class* cls, Object* obj) { if (!obj) { rvmThrowNullPointerException(env); return FALSE; } rvmLockThreadsList(); jboolean result = rvmHoldsLock(env, env->currentThread, obj); rvmUnlockThreadsList(); return result; }
jboolean Java_java_lang_Thread_internalIsInterrupted(Env* env, Class* cls, JavaThread* threadObj) { rvmLockThreadsList(); Thread* thread = (Thread*) LONG_TO_PTR(threadObj->threadPtr); jboolean interrupted = FALSE; if (thread) { interrupted = thread->interrupted; } rvmUnlockThreadsList(); return interrupted; }
static void* startThreadEntryPoint(void* _args) { ThreadEntryPointArgs* args = (ThreadEntryPointArgs*) _args; Env* env = args->env; Thread* thread = args->thread; JavaThread* threadObj = args->threadObj; rvmLockThreadsList(); jboolean failure = TRUE; setThreadEnv(env); if (!rvmExceptionOccurred(env)) { if (initThread(env, thread, threadObj)) { if (rvmSetupSignals(env)) { failure = FALSE; thread->stackAddr = getStackAddress(); } } } thread->status = THREAD_STARTING; pthread_cond_broadcast(&threadStartCond); while (thread->status != THREAD_VMWAIT) { pthread_cond_wait(&threadStartCond, &threadsLock); } rvmUnlockThreadsList(); if (!failure) { rvmChangeThreadStatus(env, thread, THREAD_RUNNING); rvmChangeThreadPriority(env, thread, thread->threadObj->priority); Method* run = rvmGetInstanceMethod2(env, java_lang_Thread, "run", "()V"); if (run) { jvalue emptyArgs[0]; rvmCallVoidInstanceMethodA(env, (Object*) threadObj, run, emptyArgs); } } detachThread(env, TRUE); return NULL; }
static jint detachThread(Env* env, jboolean ignoreAttachCount) { env->attachCount--; if (!ignoreAttachCount && env->attachCount > 0) { return JNI_OK; } if (env->gatewayFrames) { rvmAbort("Cannot detach thread when there are non native frames on the call stack"); } // TODO: Release all monitors still held by this thread (should only be monitors acquired from JNI code) Thread* thread = env->currentThread; if (rvmExceptionOccurred(env)) { threadExitUncaughtException(env, thread); } if (thread->threadObj->group) { rvmCallVoidInstanceMethod(env, thread->threadObj->group, removeThreadMethod, thread->threadObj); rvmExceptionClear(env); } // Set threadPtr to null rvmAtomicStoreLong(&thread->threadObj->threadPtr, 0); // Notify anyone waiting on this thread (using Thread.join()) rvmLockObject(env, thread->threadObj->lock); rvmObjectNotifyAll(env, thread->threadObj->lock); rvmUnlockObject(env, thread->threadObj->lock); rvmLockThreadsList(); thread->status = THREAD_ZOMBIE; DL_DELETE(threads, thread); pthread_cond_broadcast(&threadsChangedCond); rvmTearDownSignals(env); env->currentThread = NULL; pthread_setspecific(tlsEnvKey, NULL); rvmUnlockThreadsList(); return JNI_OK; }
static jint attachThread(VM* vm, Env** envPtr, char* name, Object* group, jboolean daemon) { Env* env = *envPtr; // env is NULL if rvmAttachCurrentThread() was called. If non NULL rvmInitThreads() was called. if (!env) { // If the thread was already attached there's an Env* associated with the thread. env = (Env*) pthread_getspecific(tlsEnvKey); if (env) { env->attachCount++; *envPtr = env; return JNI_OK; } } if (!env) { env = rvmCreateEnv(vm); if (!env) goto error; } setThreadEnv(env); if (rvmExceptionOccurred(env)) goto error; Thread* thread = allocThread(env); if (!thread) goto error; thread->stackAddr = getStackAddress(); thread->pThread = pthread_self(); env->currentThread = thread; rvmChangeThreadStatus(env, thread, THREAD_RUNNING); JavaThread* threadObj = (JavaThread*) rvmAllocateObject(env, java_lang_Thread); if (!threadObj) goto error; rvmLockThreadsList(); if (!initThread(env, thread, threadObj)) { rvmUnlockThreadsList(); goto error; } if (!rvmSetupSignals(env)) { rvmUnlockThreadsList(); goto error; } DL_PREPEND(threads, thread); pthread_cond_broadcast(&threadsChangedCond); rvmUnlockThreadsList(); Object* threadName = NULL; if (name) { threadName = rvmNewStringUTF(env, name, -1); if (!threadName) goto error_remove; } Method* threadConstructor = rvmGetInstanceMethod2(env, java_lang_Thread, "<init>", "(JLjava/lang/String;Ljava/lang/ThreadGroup;Z)V"); if (!threadConstructor) goto error_remove; rvmCallNonvirtualVoidInstanceMethod(env, (Object*) threadObj, threadConstructor, PTR_TO_LONG(thread), threadName, group, daemon); if (rvmExceptionOccurred(env)) goto error_remove; *envPtr = env; return JNI_OK; error_remove: rvmLockThreadsList(); DL_DELETE(threads, thread); pthread_cond_broadcast(&threadsChangedCond); rvmTearDownSignals(env); rvmUnlockThreadsList(); error: if (env) env->currentThread = NULL; clearThreadEnv(); return JNI_ERR; }