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;
}
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 @@ os::WatcherThreadCrashProtection::WatcherThreadCrashProtection() {
* 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 @@ bool os::WatcherThreadCrashProtection::call(os::CrashProtectionCallback& cb) {
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();
}
}
}

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,
* 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;
};

View File

@ -4822,8 +4822,11 @@ void os::pause() {
}
}
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 @@ os::WatcherThreadCrashProtection::WatcherThreadCrashProtection() {
// 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;
}

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.
*
* 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,
* 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> {

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
// (no destructors can be run)
os::WatcherThreadCrashProtection::check_crash_protection(sig, t);
os::ThreadCrashProtection::check_crash_protection(sig, 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.
* 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
// (no destructors can be run)
os::WatcherThreadCrashProtection::check_crash_protection(sig, t);
os::ThreadCrashProtection::check_crash_protection(sig, 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
// (no destructors can be run)
os::WatcherThreadCrashProtection::check_crash_protection(sig, t);
os::ThreadCrashProtection::check_crash_protection(sig, 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.
* 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
// (no destructors can be run).
os::WatcherThreadCrashProtection::check_crash_protection(sig, t);
os::ThreadCrashProtection::check_crash_protection(sig, 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.
*
* 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
// (no destructors can be run)
os::WatcherThreadCrashProtection::check_crash_protection(sig, t);
os::ThreadCrashProtection::check_crash_protection(sig, 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.
*
* 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
// (no destructors can be run)
os::WatcherThreadCrashProtection::check_crash_protection(sig, t);
os::ThreadCrashProtection::check_crash_protection(sig, 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
// (no destructors can be run)
os::WatcherThreadCrashProtection::check_crash_protection(sig, t);
os::ThreadCrashProtection::check_crash_protection(sig, 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
// (no destructors can be run)
os::WatcherThreadCrashProtection::check_crash_protection(sig, t);
os::ThreadCrashProtection::check_crash_protection(sig, 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.
*
* 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) \
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) {

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(&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

View File

@ -1200,7 +1200,7 @@ WatcherThread* WatcherThread::_watcher_thread = NULL;
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;

View File

@ -740,8 +740,6 @@ class WatcherThread: public Thread {
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 @@ class WatcherThread: public Thread {
// 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;
};