提交 d335e7a0 编写于 作者: R rbackman

8020701: Avoid crashes in WatcherThread

Reviewed-by: acorn, dcubed, dsimms
上级 c74394d7
......@@ -259,3 +259,52 @@ const char* os::get_current_directory(char *buf, size_t buflen) {
FILE* os::open(int fd, const char* mode) {
return ::fdopen(fd, mode);
}
os::WatcherThreadCrashProtection::WatcherThreadCrashProtection() {
assert(Thread::current()->is_Watcher_thread(), "Must be WatcherThread");
}
/*
* See the caveats for this class in os_posix.hpp
* Protects the callback call so that SIGSEGV / SIGBUS jumps back into this
* 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) {
assert(Thread::current()->is_Watcher_thread(), "Only for WatcherThread");
assert(!WatcherThread::watcher_thread()->has_crash_protection(),
"crash_protection already set?");
if (sigsetjmp(_jmpbuf, 1) == 0) {
// make sure we can see in the signal handler that we have crash protection
// installed
WatcherThread::watcher_thread()->set_crash_protection(this);
cb.call();
// and clear the crash protection
WatcherThread::watcher_thread()->set_crash_protection(NULL);
return true;
}
// this happens when we siglongjmp() back
WatcherThread::watcher_thread()->set_crash_protection(NULL);
return false;
}
void os::WatcherThreadCrashProtection::restore() {
assert(WatcherThread::watcher_thread()->has_crash_protection(),
"must have crash protection");
siglongjmp(_jmpbuf, 1);
}
void os::WatcherThreadCrashProtection::check_crash_protection(int sig,
Thread* thread) {
if (thread != NULL &&
thread->is_Watcher_thread() &&
WatcherThread::watcher_thread()->has_crash_protection()) {
if (sig == SIGSEGV || sig == SIGBUS) {
WatcherThread::watcher_thread()->crash_protection()->restore();
}
}
}
......@@ -37,5 +37,24 @@ protected:
};
/*
* Crash protection for the watcher thread. Wrap the callback
* with a sigsetjmp and in case of a SIGSEGV/SIGBUS we siglongjmp
* back.
* To be able to use this - don't take locks, don't rely on destructors,
* don't make OS library calls, don't allocate memory, don't print,
* 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 {
public:
WatcherThreadCrashProtection();
bool call(os::CrashProtectionCallback& cb);
static void check_crash_protection(int signal, Thread* thread);
private:
void restore();
sigjmp_buf _jmpbuf;
};
#endif
......@@ -4684,6 +4684,34 @@ void os::pause() {
}
}
os::WatcherThreadCrashProtection::WatcherThreadCrashProtection() {
assert(Thread::current()->is_Watcher_thread(), "Must be WatcherThread");
}
/*
* See the caveats for this class in os_windows.hpp
* Protects the callback call so that raised OS EXCEPTIONS causes a jump back
* into this method and returns false. If no OS EXCEPTION was raised, returns
* 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 success = true;
__try {
WatcherThread::watcher_thread()->set_crash_protection(this);
cb.call();
} __except(EXCEPTION_EXECUTE_HANDLER) {
// only for protection, nothing to do
success = false;
}
WatcherThread::watcher_thread()->set_crash_protection(NULL);
return success;
}
// An Event wraps a win32 "CreateEvent" kernel handle.
//
// We have a number of choices regarding "CreateEvent" win32 handle leakage:
......
......@@ -102,6 +102,20 @@ class win32 {
static LONG WINAPI serialize_fault_filter(struct _EXCEPTION_POINTERS* e);
};
/*
* Crash protection for the watcher thread. Wrap the callback
* with a __try { call() }
* To be able to use this - don't take locks, don't rely on destructors,
* don't make OS library calls, don't allocate memory, don't print,
* 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 {
public:
WatcherThreadCrashProtection();
bool call(os::CrashProtectionCallback& cb);
};
class PlatformEvent : public CHeapObj<mtInternal> {
private:
double CachePad [4] ; // increase odds that _Event is sole occupant of cache line
......
......@@ -401,6 +401,10 @@ JVM_handle_bsd_signal(int sig,
Thread* t = ThreadLocalStorage::get_thread_slow();
// 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);
SignalHandlerMark shm(t);
// Note: it's not uncommon that JNI code uses signal/sigset to install
......
......@@ -553,6 +553,10 @@ JVM_handle_linux_signal(int sig,
Thread* t = ThreadLocalStorage::get_thread_slow();
// 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);
SignalHandlerMark shm(t);
// Note: it's not uncommon that JNI code uses signal/sigset to install
......
......@@ -225,6 +225,10 @@ JVM_handle_linux_signal(int sig,
Thread* t = ThreadLocalStorage::get_thread_slow();
// 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);
SignalHandlerMark shm(t);
// Note: it's not uncommon that JNI code uses signal/sigset to install
......
......@@ -315,6 +315,10 @@ JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid,
Thread* t = ThreadLocalStorage::get_thread_slow();
// 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);
SignalHandlerMark shm(t);
if(sig == SIGPIPE || sig == SIGXFSZ) {
......
......@@ -374,6 +374,10 @@ JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid,
Thread* t = ThreadLocalStorage::get_thread_slow(); // slow & steady
// 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);
SignalHandlerMark shm(t);
if(sig == SIGPIPE || sig == SIGXFSZ) {
......
......@@ -1370,6 +1370,10 @@ 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");
}
}
void Monitor::check_block_state(Thread *thread) {
......
......@@ -595,6 +595,22 @@ void* os::malloc(size_t size, MEMFLAGS memflags, address caller) {
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 = ThreadLocalStorage::get_thread_slow();
if (thread == wt) {
assert(!wt->has_crash_protection(),
"Can't malloc with crash protection from WatcherThread");
}
}
#endif
if (size == 0) {
// return a valid pointer if size is zero
// if NULL is returned the calling functions assume out of memory.
......
......@@ -32,15 +32,18 @@
#include "utilities/top.hpp"
#ifdef TARGET_OS_FAMILY_linux
# include "jvm_linux.h"
# include <setjmp.h>
#endif
#ifdef TARGET_OS_FAMILY_solaris
# include "jvm_solaris.h"
# include <setjmp.h>
#endif
#ifdef TARGET_OS_FAMILY_windows
# include "jvm_windows.h"
#endif
#ifdef TARGET_OS_FAMILY_bsd
# include "jvm_bsd.h"
# include <setjmp.h>
#endif
// os defines the interface to operating system; this includes traditional
......@@ -730,6 +733,10 @@ class os: AllStatic {
#include "runtime/os_ext.hpp"
public:
class CrashProtectionCallback : public StackObj {
public:
virtual void call() = 0;
};
// Platform dependent stuff
#ifdef TARGET_OS_FAMILY_linux
......@@ -908,6 +915,7 @@ class os: AllStatic {
char pathSep);
static bool set_boot_path(char fileSep, char pathSep);
static char** split_path(const char* path, int* n);
};
// Note that "PAUSE" is almost always used with synchronization
......
......@@ -1226,7 +1226,7 @@ WatcherThread* WatcherThread::_watcher_thread = NULL;
bool WatcherThread::_startable = false;
volatile bool WatcherThread::_should_terminate = false;
WatcherThread::WatcherThread() : Thread() {
WatcherThread::WatcherThread() : Thread(), _crash_protection(NULL) {
assert(watcher_thread() == NULL, "we can only allocate one WatcherThread");
if (os::create_thread(this, os::watcher_thread)) {
_watcher_thread = this;
......
......@@ -733,6 +733,8 @@ class WatcherThread: public Thread {
static bool _startable;
volatile static bool _should_terminate; // updated without holding lock
os::WatcherThreadCrashProtection* _crash_protection;
public:
enum SomeConstants {
delay_interval = 10 // interrupt delay in milliseconds
......@@ -760,6 +762,14 @@ class WatcherThread: public Thread {
// 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;
};
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册