8183925: Decouple crash protection from watcher thread
Reviewed-by: dcubed, coleenp
This commit is contained in:
parent
41e729b386
commit
cc9648a8b8
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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> {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user