diff --git a/src/share/vm/prims/jvm.cpp b/src/share/vm/prims/jvm.cpp index 76dcd92cd3983e8eafcbddeba5205d2c4fba79fa..a9b96fe2149551c8875218c5de2e98c3f4c1ee6a 100644 --- a/src/share/vm/prims/jvm.cpp +++ b/src/share/vm/prims/jvm.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2651,12 +2651,18 @@ JVM_ENTRY(void, JVM_StartThread(JNIEnv* env, jobject jthread)) // we operate. MutexLocker mu(Threads_lock); - // Check to see if we're running a thread that's already exited or was - // stopped (is_stillborn) or is still active (thread is not NULL). - if (java_lang_Thread::is_stillborn(JNIHandles::resolve_non_null(jthread)) || - java_lang_Thread::thread(JNIHandles::resolve_non_null(jthread)) != NULL) { - throw_illegal_thread_state = true; + // Since JDK 5 the java.lang.Thread threadStatus is used to prevent + // re-starting an already started thread, so we should usually find + // that the JavaThread is null. However for a JNI attached thread + // there is a small window between the Thread object being created + // (with its JavaThread set) and the update to its threadStatus, so we + // have to check for this + if (java_lang_Thread::thread(JNIHandles::resolve_non_null(jthread)) != NULL) { + throw_illegal_thread_state = true; } else { + // We could also check the stillborn flag to see if this thread was already stopped, but + // for historical reasons we let the thread detect that itself when it starts running + jlong size = java_lang_Thread::stackSize(JNIHandles::resolve_non_null(jthread)); // Allocate the C++ Thread structure and create the native thread. The @@ -2704,7 +2710,7 @@ JVM_END // JVM_Stop is implemented using a VM_Operation, so threads are forced to safepoints // before the quasi-asynchronous exception is delivered. This is a little obtrusive, // but is thought to be reliable and simple. In the case, where the receiver is the -// save thread as the sender, no safepoint is needed. +// same thread as the sender, no safepoint is needed. JVM_ENTRY(void, JVM_StopThread(JNIEnv* env, jobject jthread, jobject throwable)) JVMWrapper("JVM_StopThread"); @@ -2715,26 +2721,27 @@ JVM_ENTRY(void, JVM_StopThread(JNIEnv* env, jobject jthread, jobject throwable)) oop java_thread = JNIHandles::resolve_non_null(jthread); JavaThread* receiver = java_lang_Thread::thread(java_thread); Events::log("JVM_StopThread thread JavaThread " INTPTR_FORMAT " as oop " INTPTR_FORMAT " [exception " INTPTR_FORMAT "]", receiver, (address)java_thread, throwable); - // First check if thread already exited + // First check if thread is alive if (receiver != NULL) { // Check if exception is getting thrown at self (use oop equality, since the // target object might exit) if (java_thread == thread->threadObj()) { - // This is a change from JDK 1.1, but JDK 1.2 will also do it: - // NOTE (from JDK 1.2): this is done solely to prevent stopped - // threads from being restarted. - // Fix for 4314342, 4145910, perhaps others: it now doesn't have - // any effect on the "liveness" of a thread; see - // JVM_IsThreadAlive, below. - if (java_throwable->is_a(SystemDictionary::ThreadDeath_klass())) { - java_lang_Thread::set_stillborn(java_thread); - } THROW_OOP(java_throwable); } else { // Enques a VM_Operation to stop all threads and then deliver the exception... Thread::send_async_exception(java_thread, JNIHandles::resolve(throwable)); } } + else { + // Either: + // - target thread has not been started before being stopped, or + // - target thread already terminated + // We could read the threadStatus to determine which case it is + // but that is overkill as it doesn't matter. We must set the + // stillborn flag for the first case, and if the thread has already + // exited setting this flag has no affect + java_lang_Thread::set_stillborn(java_thread); + } JVM_END diff --git a/src/share/vm/runtime/thread.cpp b/src/share/vm/runtime/thread.cpp index 0349c6584954b43143fcdb488eed79696241da7a..255ed0f973e7a9e0db151effa63901bfa3f10eaa 100644 --- a/src/share/vm/runtime/thread.cpp +++ b/src/share/vm/runtime/thread.cpp @@ -1510,11 +1510,11 @@ void JavaThread::thread_main_inner() { assert(JavaThread::current() == this, "sanity check"); assert(this->threadObj() != NULL, "just checking"); - // Execute thread entry point. If this thread is being asked to restart, - // or has been stopped before starting, do not reexecute entry point. + // Execute thread entry point unless this thread has a pending exception + // or has been stopped before starting. // Note: Due to JVM_StopThread we can have pending exceptions already! - if (!this->has_pending_exception() && !java_lang_Thread::is_stillborn(this->threadObj())) { - // enter the thread's entry point only if we have no pending exceptions + if (!this->has_pending_exception() && + !java_lang_Thread::is_stillborn(this->threadObj())) { HandleMark hm(this); this->entry_point()(this, this); } @@ -1533,13 +1533,10 @@ static void ensure_join(JavaThread* thread) { ObjectLocker lock(threadObj, thread); // Ignore pending exception (ThreadDeath), since we are exiting anyway thread->clear_pending_exception(); - // It is of profound importance that we set the stillborn bit and reset the thread object, - // before we do the notify. Since, changing these two variable will make JVM_IsAlive return - // false. So in case another thread is doing a join on this thread , it will detect that the thread - // is dead when it gets notified. - java_lang_Thread::set_stillborn(threadObj()); // Thread is exiting. So set thread_status field in java.lang.Thread class to TERMINATED. java_lang_Thread::set_thread_status(threadObj(), java_lang_Thread::TERMINATED); + // Clear the native thread instance - this makes isAlive return false and allows the join() + // to complete once we've done the notify_all below java_lang_Thread::set_thread(threadObj(), NULL); lock.notify_all(thread); // Ignore pending exception (ThreadDeath), since we are exiting anyway @@ -1996,11 +1993,6 @@ void JavaThread::send_thread_stop(oop java_throwable) { // (the compiler thread should not be a Java thread -- fix in 1.4.2) if (is_Compiler_thread()) return; - // This is a change from JDK 1.1, but JDK 1.2 will also do it: - if (java_throwable->is_a(SystemDictionary::ThreadDeath_klass())) { - java_lang_Thread::set_stillborn(threadObj()); - } - { // Actually throw the Throwable against the target Thread - however // only if there is no thread death exception installed already.