8183925: Decouple crash protection from watcher thread
authorrehn
Fri, 07 Jul 2017 23:11:33 +0200
changeset 46644 a5813fb66270
parent 46643 cb5f289ba033
child 46645 1a4335135ffd
8183925: Decouple crash protection from watcher thread Reviewed-by: dcubed, coleenp
hotspot/src/os/posix/vm/os_posix.cpp
hotspot/src/os/posix/vm/os_posix.hpp
hotspot/src/os/windows/vm/os_windows.cpp
hotspot/src/os/windows/vm/os_windows.hpp
hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp
hotspot/src/os_cpu/linux_aarch64/vm/os_linux_aarch64.cpp
hotspot/src/os_cpu/linux_arm/vm/os_linux_arm.cpp
hotspot/src/os_cpu/linux_s390/vm/os_linux_s390.cpp
hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp
hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp
hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp
hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp
hotspot/src/share/vm/runtime/mutex.cpp
hotspot/src/share/vm/runtime/os.cpp
hotspot/src/share/vm/runtime/thread.cpp
hotspot/src/share/vm/runtime/thread.hpp
--- a/hotspot/src/os/posix/vm/os_posix.cpp	Fri Jul 07 23:04:06 2017 +0200
+++ b/hotspot/src/os/posix/vm/os_posix.cpp	Fri Jul 07 23:11:33 2017 +0200
@@ -1285,8 +1285,11 @@
   return stack_size;
 }
 
-os::WatcherThreadCrashProtection::WatcherThreadCrashProtection() {
-  assert(Thread::current()->is_Watcher_thread(), "Must be WatcherThread");
+Thread* os::ThreadCrashProtection::_protected_thread = NULL;
+os::ThreadCrashProtection* os::ThreadCrashProtection::_crash_protection = NULL;
+volatile intptr_t os::ThreadCrashProtection::_crash_mux = 0;
+
+os::ThreadCrashProtection::ThreadCrashProtection() {
 }
 
 /*
@@ -1295,12 +1298,13 @@
  * method and returns false. If none of the signals are raised, returns true.
  * The callback is supposed to provide the method that should be protected.
  */
-bool os::WatcherThreadCrashProtection::call(os::CrashProtectionCallback& cb) {
+bool os::ThreadCrashProtection::call(os::CrashProtectionCallback& cb) {
   sigset_t saved_sig_mask;
 
-  assert(Thread::current()->is_Watcher_thread(), "Only for WatcherThread");
-  assert(!WatcherThread::watcher_thread()->has_crash_protection(),
-      "crash_protection already set?");
+  Thread::muxAcquire(&_crash_mux, "CrashProtection");
+
+  _protected_thread = Thread::current_or_null();
+  assert(_protected_thread != NULL, "Cannot crash protect a NULL thread");
 
   // we cannot rely on sigsetjmp/siglongjmp to save/restore the signal mask
   // since on at least some systems (OS X) siglongjmp will restore the mask
@@ -1309,34 +1313,36 @@
   if (sigsetjmp(_jmpbuf, 0) == 0) {
     // make sure we can see in the signal handler that we have crash protection
     // installed
-    WatcherThread::watcher_thread()->set_crash_protection(this);
+    _crash_protection = this;
     cb.call();
     // and clear the crash protection
-    WatcherThread::watcher_thread()->set_crash_protection(NULL);
+    _crash_protection = NULL;
+    _protected_thread = NULL;
+    Thread::muxRelease(&_crash_mux);
     return true;
   }
   // this happens when we siglongjmp() back
   pthread_sigmask(SIG_SETMASK, &saved_sig_mask, NULL);
-  WatcherThread::watcher_thread()->set_crash_protection(NULL);
+  _crash_protection = NULL;
+  _protected_thread = NULL;
+  Thread::muxRelease(&_crash_mux);
   return false;
 }
 
-void os::WatcherThreadCrashProtection::restore() {
-  assert(WatcherThread::watcher_thread()->has_crash_protection(),
-      "must have crash protection");
-
+void os::ThreadCrashProtection::restore() {
+  assert(_crash_protection != NULL, "must have crash protection");
   siglongjmp(_jmpbuf, 1);
 }
 
-void os::WatcherThreadCrashProtection::check_crash_protection(int sig,
+void os::ThreadCrashProtection::check_crash_protection(int sig,
     Thread* thread) {
 
   if (thread != NULL &&
-      thread->is_Watcher_thread() &&
-      WatcherThread::watcher_thread()->has_crash_protection()) {
+      thread == _protected_thread &&
+      _crash_protection != NULL) {
 
     if (sig == SIGSEGV || sig == SIGBUS) {
-      WatcherThread::watcher_thread()->crash_protection()->restore();
+      _crash_protection->restore();
     }
   }
 }
--- a/hotspot/src/os/posix/vm/os_posix.hpp	Fri Jul 07 23:04:06 2017 +0200
+++ b/hotspot/src/os/posix/vm/os_posix.hpp	Fri Jul 07 23:11:33 2017 +0200
@@ -121,13 +121,20 @@
  * don't call code that could leave the heap / memory in an inconsistent state,
  * or anything else where we are not in control if we suddenly jump out.
  */
-class WatcherThreadCrashProtection : public StackObj {
+class ThreadCrashProtection : public StackObj {
 public:
-  WatcherThreadCrashProtection();
+  static bool is_crash_protected(Thread* thr) {
+    return _crash_protection != NULL && _protected_thread == thr;
+  }
+
+  ThreadCrashProtection();
   bool call(os::CrashProtectionCallback& cb);
 
   static void check_crash_protection(int signal, Thread* thread);
 private:
+  static Thread* _protected_thread;
+  static ThreadCrashProtection* _crash_protection;
+  static volatile intptr_t _crash_mux;
   void restore();
   sigjmp_buf _jmpbuf;
 };
--- a/hotspot/src/os/windows/vm/os_windows.cpp	Fri Jul 07 23:04:06 2017 +0200
+++ b/hotspot/src/os/windows/vm/os_windows.cpp	Fri Jul 07 23:11:33 2017 +0200
@@ -4822,8 +4822,11 @@
   }
 }
 
-os::WatcherThreadCrashProtection::WatcherThreadCrashProtection() {
-  assert(Thread::current()->is_Watcher_thread(), "Must be WatcherThread");
+Thread* os::ThreadCrashProtection::_protected_thread = NULL;
+os::ThreadCrashProtection* os::ThreadCrashProtection::_crash_protection = NULL;
+volatile intptr_t os::ThreadCrashProtection::_crash_mux = 0;
+
+os::ThreadCrashProtection::ThreadCrashProtection() {
 }
 
 // See the caveats for this class in os_windows.hpp
@@ -4832,20 +4835,24 @@
 // true.
 // The callback is supposed to provide the method that should be protected.
 //
-bool os::WatcherThreadCrashProtection::call(os::CrashProtectionCallback& cb) {
-  assert(Thread::current()->is_Watcher_thread(), "Only for WatcherThread");
-  assert(!WatcherThread::watcher_thread()->has_crash_protection(),
-         "crash_protection already set?");
+bool os::ThreadCrashProtection::call(os::CrashProtectionCallback& cb) {
+
+  Thread::muxAcquire(&_crash_mux, "CrashProtection");
+
+  _protected_thread = Thread::current_or_null();
+  assert(_protected_thread != NULL, "Cannot crash protect a NULL thread");
 
   bool success = true;
   __try {
-    WatcherThread::watcher_thread()->set_crash_protection(this);
+    _crash_protection = this;
     cb.call();
   } __except(EXCEPTION_EXECUTE_HANDLER) {
     // only for protection, nothing to do
     success = false;
   }
-  WatcherThread::watcher_thread()->set_crash_protection(NULL);
+  _crash_protection = NULL;
+  _protected_thread = NULL;
+  Thread::muxRelease(&_crash_mux);
   return success;
 }
 
--- a/hotspot/src/os/windows/vm/os_windows.hpp	Fri Jul 07 23:04:06 2017 +0200
+++ b/hotspot/src/os/windows/vm/os_windows.hpp	Fri Jul 07 23:11:33 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, 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
@@ -146,10 +146,18 @@
  * don't call code that could leave the heap / memory in an inconsistent state,
  * or anything else where we are not in control if we suddenly jump out.
  */
-class WatcherThreadCrashProtection : public StackObj {
+class ThreadCrashProtection : public StackObj {
 public:
-  WatcherThreadCrashProtection();
+  static bool is_crash_protected(Thread* thr) {
+    return _crash_protection != NULL && _protected_thread == thr;
+  }
+
+  ThreadCrashProtection();
   bool call(os::CrashProtectionCallback& cb);
+private:
+  static Thread* _protected_thread;
+  static ThreadCrashProtection* _crash_protection;
+  static volatile intptr_t _crash_mux;
 };
 
 class PlatformEvent : public CHeapObj<mtInternal> {
--- a/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp	Fri Jul 07 23:04:06 2017 +0200
+++ b/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp	Fri Jul 07 23:11:33 2017 +0200
@@ -463,7 +463,7 @@
 
   // Must do this before SignalHandlerMark, if crash protection installed we will longjmp away
   // (no destructors can be run)
-  os::WatcherThreadCrashProtection::check_crash_protection(sig, t);
+  os::ThreadCrashProtection::check_crash_protection(sig, t);
 
   SignalHandlerMark shm(t);
 
--- a/hotspot/src/os_cpu/linux_aarch64/vm/os_linux_aarch64.cpp	Fri Jul 07 23:04:06 2017 +0200
+++ b/hotspot/src/os_cpu/linux_aarch64/vm/os_linux_aarch64.cpp	Fri Jul 07 23:11:33 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2014, Red Hat Inc. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
@@ -277,7 +277,7 @@
 
   // Must do this before SignalHandlerMark, if crash protection installed we will longjmp away
   // (no destructors can be run)
-  os::WatcherThreadCrashProtection::check_crash_protection(sig, t);
+  os::ThreadCrashProtection::check_crash_protection(sig, t);
 
   SignalHandlerMark shm(t);
 
--- a/hotspot/src/os_cpu/linux_arm/vm/os_linux_arm.cpp	Fri Jul 07 23:04:06 2017 +0200
+++ b/hotspot/src/os_cpu/linux_arm/vm/os_linux_arm.cpp	Fri Jul 07 23:11:33 2017 +0200
@@ -280,7 +280,7 @@
 
   // Must do this before SignalHandlerMark, if crash protection installed we will longjmp away
   // (no destructors can be run)
-  os::WatcherThreadCrashProtection::check_crash_protection(sig, t);
+  os::ThreadCrashProtection::check_crash_protection(sig, t);
 
   SignalHandlerMark shm(t);
 
--- a/hotspot/src/os_cpu/linux_s390/vm/os_linux_s390.cpp	Fri Jul 07 23:04:06 2017 +0200
+++ b/hotspot/src/os_cpu/linux_s390/vm/os_linux_s390.cpp	Fri Jul 07 23:11:33 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2016 SAP SE. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
@@ -245,7 +245,7 @@
 
   // Must do this before SignalHandlerMark, if crash protection installed we will longjmp away
   // (no destructors can be run).
-  os::WatcherThreadCrashProtection::check_crash_protection(sig, t);
+  os::ThreadCrashProtection::check_crash_protection(sig, t);
 
   SignalHandlerMark shm(t);
 
--- a/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp	Fri Jul 07 23:04:06 2017 +0200
+++ b/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp	Fri Jul 07 23:11:33 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2017, 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
@@ -493,7 +493,7 @@
 
   // Must do this before SignalHandlerMark, if crash protection installed we will longjmp away
   // (no destructors can be run)
-  os::WatcherThreadCrashProtection::check_crash_protection(sig, t);
+  os::ThreadCrashProtection::check_crash_protection(sig, t);
 
   SignalHandlerMark shm(t);
 
--- a/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp	Fri Jul 07 23:04:06 2017 +0200
+++ b/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp	Fri Jul 07 23:11:33 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2017, 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
@@ -283,7 +283,7 @@
 
   // Must do this before SignalHandlerMark, if crash protection installed we will longjmp away
   // (no destructors can be run)
-  os::WatcherThreadCrashProtection::check_crash_protection(sig, t);
+  os::ThreadCrashProtection::check_crash_protection(sig, t);
 
   SignalHandlerMark shm(t);
 
--- a/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp	Fri Jul 07 23:04:06 2017 +0200
+++ b/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp	Fri Jul 07 23:11:33 2017 +0200
@@ -328,7 +328,7 @@
 
   // Must do this before SignalHandlerMark, if crash protection installed we will longjmp away
   // (no destructors can be run)
-  os::WatcherThreadCrashProtection::check_crash_protection(sig, t);
+  os::ThreadCrashProtection::check_crash_protection(sig, t);
 
   SignalHandlerMark shm(t);
 
--- a/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp	Fri Jul 07 23:04:06 2017 +0200
+++ b/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp	Fri Jul 07 23:11:33 2017 +0200
@@ -411,7 +411,7 @@
 
   // Must do this before SignalHandlerMark, if crash protection installed we will longjmp away
   // (no destructors can be run)
-  os::WatcherThreadCrashProtection::check_crash_protection(sig, t);
+  os::ThreadCrashProtection::check_crash_protection(sig, t);
 
   SignalHandlerMark shm(t);
 
--- a/hotspot/src/share/vm/runtime/mutex.cpp	Fri Jul 07 23:04:06 2017 +0200
+++ b/hotspot/src/share/vm/runtime/mutex.cpp	Fri Jul 07 23:11:33 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2017, 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
@@ -1389,10 +1389,8 @@
     debug_only(if (rank() != Mutex::special) \
                thread->check_for_valid_safepoint_state(false);)
   }
-  if (thread->is_Watcher_thread()) {
-    assert(!WatcherThread::watcher_thread()->has_crash_protection(),
-           "locking not allowed when crash protection is set");
-  }
+  assert(!os::ThreadCrashProtection::is_crash_protected(thread),
+         "locking not allowed when crash protection is set");
 }
 
 void Monitor::check_block_state(Thread *thread) {
--- a/hotspot/src/share/vm/runtime/os.cpp	Fri Jul 07 23:04:06 2017 +0200
+++ b/hotspot/src/share/vm/runtime/os.cpp	Fri Jul 07 23:11:33 2017 +0200
@@ -574,21 +574,10 @@
   NOT_PRODUCT(inc_stat_counter(&num_mallocs, 1));
   NOT_PRODUCT(inc_stat_counter(&alloc_bytes, size));
 
-#ifdef ASSERT
-  // checking for the WatcherThread and crash_protection first
-  // since os::malloc can be called when the libjvm.{dll,so} is
-  // first loaded and we don't have a thread yet.
-  // try to find the thread after we see that the watcher thread
-  // exists and has crash protection.
-  WatcherThread *wt = WatcherThread::watcher_thread();
-  if (wt != NULL && wt->has_crash_protection()) {
-    Thread* thread = Thread::current_or_null();
-    if (thread == wt) {
-      assert(!wt->has_crash_protection(),
-          "Can't malloc with crash protection from WatcherThread");
-    }
-  }
-#endif
+  // Since os::malloc can be called when the libjvm.{dll,so} is
+  // first loaded and we don't have a thread yet we must accept NULL also here.
+  assert(!os::ThreadCrashProtection::is_crash_protected(Thread::current_or_null()),
+         "malloc() not allowed when crash protection is set");
 
   if (size == 0) {
     // return a valid pointer if size is zero
--- a/hotspot/src/share/vm/runtime/thread.cpp	Fri Jul 07 23:04:06 2017 +0200
+++ b/hotspot/src/share/vm/runtime/thread.cpp	Fri Jul 07 23:11:33 2017 +0200
@@ -1200,7 +1200,7 @@
 bool WatcherThread::_startable = false;
 volatile bool  WatcherThread::_should_terminate = false;
 
-WatcherThread::WatcherThread() : Thread(), _crash_protection(NULL) {
+WatcherThread::WatcherThread() : Thread() {
   assert(watcher_thread() == NULL, "we can only allocate one WatcherThread");
   if (os::create_thread(this, os::watcher_thread)) {
     _watcher_thread = this;
--- a/hotspot/src/share/vm/runtime/thread.hpp	Fri Jul 07 23:04:06 2017 +0200
+++ b/hotspot/src/share/vm/runtime/thread.hpp	Fri Jul 07 23:11:33 2017 +0200
@@ -740,8 +740,6 @@
   static bool _startable;
   // volatile due to at least one lock-free read
   volatile static bool _should_terminate;
-
-  os::WatcherThreadCrashProtection* _crash_protection;
  public:
   enum SomeConstants {
     delay_interval = 10                          // interrupt delay in milliseconds
@@ -772,15 +770,6 @@
   // Only allow start once the VM is sufficiently initialized
   // Otherwise the first task to enroll will trigger the start
   static void make_startable();
-
-  void set_crash_protection(os::WatcherThreadCrashProtection* crash_protection) {
-    assert(Thread::current()->is_Watcher_thread(), "Can only be set by WatcherThread");
-    _crash_protection = crash_protection;
-  }
-
-  bool has_crash_protection() const { return _crash_protection != NULL; }
-  os::WatcherThreadCrashProtection* crash_protection() const { return _crash_protection; }
-
  private:
   int sleep() const;
 };