8183925: Decouple crash protection from watcher thread

Reviewed-by: dcubed, coleenp
This commit is contained in:
Robbin Ehn 2017-07-07 23:11:33 +02:00
parent 41e729b386
commit cc9648a8b8
16 changed files with 78 additions and 74 deletions

View File

@ -1285,8 +1285,11 @@ size_t os::Posix::get_initial_stack_size(ThreadType thr_type, size_t req_stack_s
return stack_size; return stack_size;
} }
os::WatcherThreadCrashProtection::WatcherThreadCrashProtection() { Thread* os::ThreadCrashProtection::_protected_thread = NULL;
assert(Thread::current()->is_Watcher_thread(), "Must be WatcherThread"); os::ThreadCrashProtection* os::ThreadCrashProtection::_crash_protection = NULL;
volatile intptr_t os::ThreadCrashProtection::_crash_mux = 0;
os::ThreadCrashProtection::ThreadCrashProtection() {
} }
/* /*
@ -1295,12 +1298,13 @@ os::WatcherThreadCrashProtection::WatcherThreadCrashProtection() {
* method and returns false. If none of the signals are raised, returns true. * 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. * 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; sigset_t saved_sig_mask;
assert(Thread::current()->is_Watcher_thread(), "Only for WatcherThread"); Thread::muxAcquire(&_crash_mux, "CrashProtection");
assert(!WatcherThread::watcher_thread()->has_crash_protection(),
"crash_protection already set?"); _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 // 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 // since on at least some systems (OS X) siglongjmp will restore the mask
@ -1309,34 +1313,36 @@ bool os::WatcherThreadCrashProtection::call(os::CrashProtectionCallback& cb) {
if (sigsetjmp(_jmpbuf, 0) == 0) { if (sigsetjmp(_jmpbuf, 0) == 0) {
// make sure we can see in the signal handler that we have crash protection // make sure we can see in the signal handler that we have crash protection
// installed // installed
WatcherThread::watcher_thread()->set_crash_protection(this); _crash_protection = this;
cb.call(); cb.call();
// and clear the crash protection // and clear the crash protection
WatcherThread::watcher_thread()->set_crash_protection(NULL); _crash_protection = NULL;
_protected_thread = NULL;
Thread::muxRelease(&_crash_mux);
return true; return true;
} }
// this happens when we siglongjmp() back // this happens when we siglongjmp() back
pthread_sigmask(SIG_SETMASK, &saved_sig_mask, NULL); 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; return false;
} }
void os::WatcherThreadCrashProtection::restore() { void os::ThreadCrashProtection::restore() {
assert(WatcherThread::watcher_thread()->has_crash_protection(), assert(_crash_protection != NULL, "must have crash protection");
"must have crash protection");
siglongjmp(_jmpbuf, 1); siglongjmp(_jmpbuf, 1);
} }
void os::WatcherThreadCrashProtection::check_crash_protection(int sig, void os::ThreadCrashProtection::check_crash_protection(int sig,
Thread* thread) { Thread* thread) {
if (thread != NULL && if (thread != NULL &&
thread->is_Watcher_thread() && thread == _protected_thread &&
WatcherThread::watcher_thread()->has_crash_protection()) { _crash_protection != NULL) {
if (sig == SIGSEGV || sig == SIGBUS) { if (sig == SIGSEGV || sig == SIGBUS) {
WatcherThread::watcher_thread()->crash_protection()->restore(); _crash_protection->restore();
} }
} }
} }

View File

@ -121,13 +121,20 @@ static void write_memory_serialize_page_with_handler(JavaThread* thread) {
* don't call code that could leave the heap / memory in an inconsistent state, * 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. * or anything else where we are not in control if we suddenly jump out.
*/ */
class WatcherThreadCrashProtection : public StackObj { class ThreadCrashProtection : public StackObj {
public: public:
WatcherThreadCrashProtection(); static bool is_crash_protected(Thread* thr) {
return _crash_protection != NULL && _protected_thread == thr;
}
ThreadCrashProtection();
bool call(os::CrashProtectionCallback& cb); bool call(os::CrashProtectionCallback& cb);
static void check_crash_protection(int signal, Thread* thread); static void check_crash_protection(int signal, Thread* thread);
private: private:
static Thread* _protected_thread;
static ThreadCrashProtection* _crash_protection;
static volatile intptr_t _crash_mux;
void restore(); void restore();
sigjmp_buf _jmpbuf; sigjmp_buf _jmpbuf;
}; };

View File

@ -4822,8 +4822,11 @@ void os::pause() {
} }
} }
os::WatcherThreadCrashProtection::WatcherThreadCrashProtection() { Thread* os::ThreadCrashProtection::_protected_thread = NULL;
assert(Thread::current()->is_Watcher_thread(), "Must be WatcherThread"); 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 // See the caveats for this class in os_windows.hpp
@ -4832,20 +4835,24 @@ os::WatcherThreadCrashProtection::WatcherThreadCrashProtection() {
// true. // true.
// The callback is supposed to provide the method that should be protected. // 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) {
assert(Thread::current()->is_Watcher_thread(), "Only for WatcherThread");
assert(!WatcherThread::watcher_thread()->has_crash_protection(), Thread::muxAcquire(&_crash_mux, "CrashProtection");
"crash_protection already set?");
_protected_thread = Thread::current_or_null();
assert(_protected_thread != NULL, "Cannot crash protect a NULL thread");
bool success = true; bool success = true;
__try { __try {
WatcherThread::watcher_thread()->set_crash_protection(this); _crash_protection = this;
cb.call(); cb.call();
} __except(EXCEPTION_EXECUTE_HANDLER) { } __except(EXCEPTION_EXECUTE_HANDLER) {
// only for protection, nothing to do // only for protection, nothing to do
success = false; success = false;
} }
WatcherThread::watcher_thread()->set_crash_protection(NULL); _crash_protection = NULL;
_protected_thread = NULL;
Thread::muxRelease(&_crash_mux);
return success; return success;
} }

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -146,10 +146,18 @@ static void write_memory_serialize_page_with_handler(JavaThread* thread) {
* don't call code that could leave the heap / memory in an inconsistent state, * 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. * or anything else where we are not in control if we suddenly jump out.
*/ */
class WatcherThreadCrashProtection : public StackObj { class ThreadCrashProtection : public StackObj {
public: public:
WatcherThreadCrashProtection(); static bool is_crash_protected(Thread* thr) {
return _crash_protection != NULL && _protected_thread == thr;
}
ThreadCrashProtection();
bool call(os::CrashProtectionCallback& cb); 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> { class PlatformEvent : public CHeapObj<mtInternal> {

View File

@ -463,7 +463,7 @@ JVM_handle_bsd_signal(int sig,
// Must do this before SignalHandlerMark, if crash protection installed we will longjmp away // Must do this before SignalHandlerMark, if crash protection installed we will longjmp away
// (no destructors can be run) // (no destructors can be run)
os::WatcherThreadCrashProtection::check_crash_protection(sig, t); os::ThreadCrashProtection::check_crash_protection(sig, t);
SignalHandlerMark shm(t); SignalHandlerMark shm(t);

View File

@ -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. * Copyright (c) 2014, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
@ -277,7 +277,7 @@ JVM_handle_linux_signal(int sig,
// Must do this before SignalHandlerMark, if crash protection installed we will longjmp away // Must do this before SignalHandlerMark, if crash protection installed we will longjmp away
// (no destructors can be run) // (no destructors can be run)
os::WatcherThreadCrashProtection::check_crash_protection(sig, t); os::ThreadCrashProtection::check_crash_protection(sig, t);
SignalHandlerMark shm(t); SignalHandlerMark shm(t);

View File

@ -280,7 +280,7 @@ extern "C" int JVM_handle_linux_signal(int sig, siginfo_t* info,
// Must do this before SignalHandlerMark, if crash protection installed we will longjmp away // Must do this before SignalHandlerMark, if crash protection installed we will longjmp away
// (no destructors can be run) // (no destructors can be run)
os::WatcherThreadCrashProtection::check_crash_protection(sig, t); os::ThreadCrashProtection::check_crash_protection(sig, t);
SignalHandlerMark shm(t); SignalHandlerMark shm(t);

View File

@ -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. * Copyright (c) 2016 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
@ -245,7 +245,7 @@ JVM_handle_linux_signal(int sig,
// Must do this before SignalHandlerMark, if crash protection installed we will longjmp away // Must do this before SignalHandlerMark, if crash protection installed we will longjmp away
// (no destructors can be run). // (no destructors can be run).
os::WatcherThreadCrashProtection::check_crash_protection(sig, t); os::ThreadCrashProtection::check_crash_protection(sig, t);
SignalHandlerMark shm(t); SignalHandlerMark shm(t);

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -493,7 +493,7 @@ JVM_handle_linux_signal(int sig,
// Must do this before SignalHandlerMark, if crash protection installed we will longjmp away // Must do this before SignalHandlerMark, if crash protection installed we will longjmp away
// (no destructors can be run) // (no destructors can be run)
os::WatcherThreadCrashProtection::check_crash_protection(sig, t); os::ThreadCrashProtection::check_crash_protection(sig, t);
SignalHandlerMark shm(t); SignalHandlerMark shm(t);

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -283,7 +283,7 @@ JVM_handle_linux_signal(int sig,
// Must do this before SignalHandlerMark, if crash protection installed we will longjmp away // Must do this before SignalHandlerMark, if crash protection installed we will longjmp away
// (no destructors can be run) // (no destructors can be run)
os::WatcherThreadCrashProtection::check_crash_protection(sig, t); os::ThreadCrashProtection::check_crash_protection(sig, t);
SignalHandlerMark shm(t); SignalHandlerMark shm(t);

View File

@ -328,7 +328,7 @@ JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid,
// Must do this before SignalHandlerMark, if crash protection installed we will longjmp away // Must do this before SignalHandlerMark, if crash protection installed we will longjmp away
// (no destructors can be run) // (no destructors can be run)
os::WatcherThreadCrashProtection::check_crash_protection(sig, t); os::ThreadCrashProtection::check_crash_protection(sig, t);
SignalHandlerMark shm(t); SignalHandlerMark shm(t);

View File

@ -411,7 +411,7 @@ JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid,
// Must do this before SignalHandlerMark, if crash protection installed we will longjmp away // Must do this before SignalHandlerMark, if crash protection installed we will longjmp away
// (no destructors can be run) // (no destructors can be run)
os::WatcherThreadCrashProtection::check_crash_protection(sig, t); os::ThreadCrashProtection::check_crash_protection(sig, t);
SignalHandlerMark shm(t); SignalHandlerMark shm(t);

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -1389,10 +1389,8 @@ void Monitor::check_prelock_state(Thread *thread) {
debug_only(if (rank() != Mutex::special) \ debug_only(if (rank() != Mutex::special) \
thread->check_for_valid_safepoint_state(false);) thread->check_for_valid_safepoint_state(false);)
} }
if (thread->is_Watcher_thread()) { assert(!os::ThreadCrashProtection::is_crash_protected(thread),
assert(!WatcherThread::watcher_thread()->has_crash_protection(), "locking not allowed when crash protection is set");
"locking not allowed when crash protection is set");
}
} }
void Monitor::check_block_state(Thread *thread) { void Monitor::check_block_state(Thread *thread) {

View File

@ -574,21 +574,10 @@ void* os::malloc(size_t size, MEMFLAGS memflags, const NativeCallStack& stack) {
NOT_PRODUCT(inc_stat_counter(&num_mallocs, 1)); NOT_PRODUCT(inc_stat_counter(&num_mallocs, 1));
NOT_PRODUCT(inc_stat_counter(&alloc_bytes, size)); NOT_PRODUCT(inc_stat_counter(&alloc_bytes, size));
#ifdef ASSERT // Since os::malloc can be called when the libjvm.{dll,so} is
// checking for the WatcherThread and crash_protection first // first loaded and we don't have a thread yet we must accept NULL also here.
// since os::malloc can be called when the libjvm.{dll,so} is assert(!os::ThreadCrashProtection::is_crash_protected(Thread::current_or_null()),
// first loaded and we don't have a thread yet. "malloc() not allowed when crash protection is set");
// 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
if (size == 0) { if (size == 0) {
// return a valid pointer if size is zero // return a valid pointer if size is zero

View File

@ -1200,7 +1200,7 @@ WatcherThread* WatcherThread::_watcher_thread = NULL;
bool WatcherThread::_startable = false; bool WatcherThread::_startable = false;
volatile bool WatcherThread::_should_terminate = 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"); assert(watcher_thread() == NULL, "we can only allocate one WatcherThread");
if (os::create_thread(this, os::watcher_thread)) { if (os::create_thread(this, os::watcher_thread)) {
_watcher_thread = this; _watcher_thread = this;

View File

@ -740,8 +740,6 @@ class WatcherThread: public Thread {
static bool _startable; static bool _startable;
// volatile due to at least one lock-free read // volatile due to at least one lock-free read
volatile static bool _should_terminate; volatile static bool _should_terminate;
os::WatcherThreadCrashProtection* _crash_protection;
public: public:
enum SomeConstants { enum SomeConstants {
delay_interval = 10 // interrupt delay in milliseconds delay_interval = 10 // interrupt delay in milliseconds
@ -772,15 +770,6 @@ class WatcherThread: public Thread {
// Only allow start once the VM is sufficiently initialized // Only allow start once the VM is sufficiently initialized
// Otherwise the first task to enroll will trigger the start // Otherwise the first task to enroll will trigger the start
static void make_startable(); 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: private:
int sleep() const; int sleep() const;
}; };