8199813: SIGSEGV in ThreadsList::includes()
authordcubed
Wed, 28 Mar 2018 12:04:33 -0400
changeset 49636 6d5bd76650df
parent 49635 e79bbf1635da
child 49637 ab0f93ba0507
8199813: SIGSEGV in ThreadsList::includes() Summary: ThreadsListHandles cannot be used by JavaThreads that are not on the Threads list. Reviewed-by: eosterlund, gthornbr, dholmes, rehn
src/hotspot/os/linux/os_linux.cpp
src/hotspot/share/runtime/thread.cpp
src/hotspot/share/runtime/threadSMR.cpp
src/hotspot/share/runtime/vm_operations.cpp
src/hotspot/share/runtime/vm_operations.hpp
--- a/src/hotspot/os/linux/os_linux.cpp	Wed Mar 28 16:39:32 2018 +0200
+++ b/src/hotspot/os/linux/os_linux.cpp	Wed Mar 28 12:04:33 2018 -0400
@@ -1644,10 +1644,7 @@
         //
         // Dynamic loader will make all stacks executable after
         // this function returns, and will not do that again.
-#ifdef ASSERT
-        ThreadsListHandle tlh;
-        assert(tlh.length() == 0, "no Java threads should exist yet.");
-#endif
+        assert(Threads::number_of_threads() == 0, "no Java threads should exist yet.");
       } else {
         warning("You have loaded library %s which might have disabled stack guard. "
                 "The VM will try to fix the stack guard now.\n"
--- a/src/hotspot/share/runtime/thread.cpp	Wed Mar 28 16:39:32 2018 +0200
+++ b/src/hotspot/share/runtime/thread.cpp	Wed Mar 28 12:04:33 2018 -0400
@@ -2392,11 +2392,13 @@
 }
 
 #ifdef ASSERT
-// verify the JavaThread has not yet been published in the Threads::list, and
-// hence doesn't need protection from concurrent access at this stage
+// Verify the JavaThread has not yet been published in the Threads::list, and
+// hence doesn't need protection from concurrent access at this stage.
 void JavaThread::verify_not_published() {
-  ThreadsListHandle tlh;
-  assert(!tlh.includes(this), "JavaThread shouldn't have been published yet!");
+  // Cannot create a ThreadsListHandle here and check !tlh.includes(this)
+  // since an unpublished JavaThread doesn't participate in the
+  // Thread-SMR protocol for keeping a ThreadsList alive.
+  assert(!on_thread_list(), "JavaThread shouldn't have been published yet!");
 }
 #endif
 
@@ -4262,11 +4264,6 @@
     VMThread::destroy();
   }
 
-  // clean up ideal graph printers
-#if defined(COMPILER2) && !defined(PRODUCT)
-  IdealGraphPrinter::clean_up();
-#endif
-
   // Now, all Java threads are gone except daemon threads. Daemon threads
   // running Java code or in VM are stopped by the Safepoint. However,
   // daemon threads executing native code are still running.  But they
@@ -4275,6 +4272,16 @@
 
   VM_Exit::set_vm_exited();
 
+  // Clean up ideal graph printers after the VMThread has started
+  // the final safepoint which will block all the Compiler threads.
+  // Note that this Thread has already logically exited so the
+  // clean_up() function's use of a JavaThreadIteratorWithHandle
+  // would be a problem except set_vm_exited() has remembered the
+  // shutdown thread which is granted a policy exception.
+#if defined(COMPILER2) && !defined(PRODUCT)
+  IdealGraphPrinter::clean_up();
+#endif
+
   notify_vm_shutdown();
 
   // We are after VM_Exit::set_vm_exited() so we can't call
--- a/src/hotspot/share/runtime/threadSMR.cpp	Wed Mar 28 16:39:32 2018 +0200
+++ b/src/hotspot/share/runtime/threadSMR.cpp	Wed Mar 28 12:04:33 2018 -0400
@@ -28,6 +28,7 @@
 #include "runtime/jniHandles.inline.hpp"
 #include "runtime/thread.inline.hpp"
 #include "runtime/threadSMR.inline.hpp"
+#include "runtime/vm_operations.hpp"
 #include "services/threadService.hpp"
 #include "utilities/copy.hpp"
 #include "utilities/globalDefinitions.hpp"
@@ -469,6 +470,16 @@
 
 ThreadsListHandle::ThreadsListHandle(Thread *self) : _list(ThreadsSMRSupport::acquire_stable_list(self, /* is_ThreadsListSetter */ false)), _self(self) {
   assert(self == Thread::current(), "sanity check");
+  // Threads::threads_do() is used by the Thread-SMR protocol to visit all
+  // Threads in the system which ensures the safety of the ThreadsList
+  // managed by this ThreadsListHandle, but JavaThreads that are not on
+  // the Threads list cannot be included in that visit. The JavaThread that
+  // calls Threads::destroy_vm() is exempt from this check because it has
+  // to logically exit as part of the shutdown procedure. This is safe
+  // because VM_Exit::_shutdown_thread is not set until after the VMThread
+  // has started the final safepoint which holds the Threads_lock for the
+  // remainder of the VM's life.
+  assert(!self->is_Java_thread() || self == VM_Exit::shutdown_thread() || (((JavaThread*)self)->on_thread_list() && !((JavaThread*)self)->is_terminated()), "JavaThread must be on the Threads list to use a ThreadsListHandle");
   if (EnableThreadSMRStatistics) {
     _timer.start();
   }
--- a/src/hotspot/share/runtime/vm_operations.cpp	Wed Mar 28 16:39:32 2018 +0200
+++ b/src/hotspot/share/runtime/vm_operations.cpp	Wed Mar 28 12:04:33 2018 -0400
@@ -417,7 +417,7 @@
 }
 
 volatile bool VM_Exit::_vm_exited = false;
-Thread * VM_Exit::_shutdown_thread = NULL;
+Thread * volatile VM_Exit::_shutdown_thread = NULL;
 
 int VM_Exit::set_vm_exited() {
 
--- a/src/hotspot/share/runtime/vm_operations.hpp	Wed Mar 28 16:39:32 2018 +0200
+++ b/src/hotspot/share/runtime/vm_operations.hpp	Wed Mar 28 12:04:33 2018 -0400
@@ -459,7 +459,7 @@
  private:
   int  _exit_code;
   static volatile bool _vm_exited;
-  static Thread * _shutdown_thread;
+  static Thread * volatile _shutdown_thread;
   static void wait_if_vm_exited();
  public:
   VM_Exit(int exit_code) {
@@ -468,6 +468,7 @@
   static int wait_for_threads_in_native_to_block();
   static int set_vm_exited();
   static bool vm_exited()                      { return _vm_exited; }
+  static Thread * shutdown_thread()            { return _shutdown_thread; }
   static void block_if_vm_exited() {
     if (_vm_exited) {
       wait_if_vm_exited();