6566340: Restore use of stillborn flag to signify a thread that was stopped before it started
authordholmes
Tue, 25 Jan 2011 00:14:21 -0500
changeset 8061 07585870d15f
parent 7928 c2f2ee35ff81
child 8062 dae5a09060f4
6566340: Restore use of stillborn flag to signify a thread that was stopped before it started Summary: Restore use of stillborn flag Reviewed-by: acorn, alanb
hotspot/src/share/vm/prims/jvm.cpp
hotspot/src/share/vm/runtime/thread.cpp
--- a/hotspot/src/share/vm/prims/jvm.cpp	Fri Jan 21 02:07:11 2011 -0800
+++ b/hotspot/src/share/vm/prims/jvm.cpp	Tue Jan 25 00:14:21 2011 -0500
@@ -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 @@
     // 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_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 @@
   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
 
 
--- a/hotspot/src/share/vm/runtime/thread.cpp	Fri Jan 21 02:07:11 2011 -0800
+++ b/hotspot/src/share/vm/runtime/thread.cpp	Tue Jan 25 00:14:21 2011 -0500
@@ -1510,11 +1510,11 @@
   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 @@
   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 @@
   // (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.