6610420: Debug VM crashes during monitor lock rank checking
Make SerializePage lock as raw lock and add name for mutex locks Reviewed-by: never, dice, dholmes
This commit is contained in:
parent
f7eb451719
commit
f804a7e9f9
@ -1119,10 +1119,15 @@ Monitor::~Monitor() {
|
|||||||
assert ((UNS(_owner)|UNS(_LockWord.FullWord)|UNS(_EntryList)|UNS(_WaitSet)|UNS(_OnDeck)) == 0, "") ;
|
assert ((UNS(_owner)|UNS(_LockWord.FullWord)|UNS(_EntryList)|UNS(_WaitSet)|UNS(_OnDeck)) == 0, "") ;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Monitor::ClearMonitor (Monitor * m) {
|
void Monitor::ClearMonitor (Monitor * m, const char *name) {
|
||||||
m->_owner = NULL ;
|
m->_owner = NULL ;
|
||||||
m->_snuck = false ;
|
m->_snuck = false ;
|
||||||
m->_name = "UNKNOWN" ;
|
if (name == NULL) {
|
||||||
|
strcpy(m->_name, "UNKNOWN") ;
|
||||||
|
} else {
|
||||||
|
strncpy(m->_name, name, MONITOR_NAME_LEN - 1);
|
||||||
|
m->_name[MONITOR_NAME_LEN - 1] = '\0';
|
||||||
|
}
|
||||||
m->_LockWord.FullWord = 0 ;
|
m->_LockWord.FullWord = 0 ;
|
||||||
m->_EntryList = NULL ;
|
m->_EntryList = NULL ;
|
||||||
m->_OnDeck = NULL ;
|
m->_OnDeck = NULL ;
|
||||||
@ -1133,7 +1138,7 @@ void Monitor::ClearMonitor (Monitor * m) {
|
|||||||
Monitor::Monitor() { ClearMonitor(this); }
|
Monitor::Monitor() { ClearMonitor(this); }
|
||||||
|
|
||||||
Monitor::Monitor (int Rank, const char * name, bool allow_vm_block) {
|
Monitor::Monitor (int Rank, const char * name, bool allow_vm_block) {
|
||||||
ClearMonitor (this) ;
|
ClearMonitor (this, name) ;
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
_allow_vm_block = allow_vm_block;
|
_allow_vm_block = allow_vm_block;
|
||||||
_rank = Rank ;
|
_rank = Rank ;
|
||||||
@ -1145,7 +1150,7 @@ Mutex::~Mutex() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Mutex::Mutex (int Rank, const char * name, bool allow_vm_block) {
|
Mutex::Mutex (int Rank, const char * name, bool allow_vm_block) {
|
||||||
ClearMonitor ((Monitor *) this) ;
|
ClearMonitor ((Monitor *) this, name) ;
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
_allow_vm_block = allow_vm_block;
|
_allow_vm_block = allow_vm_block;
|
||||||
_rank = Rank ;
|
_rank = Rank ;
|
||||||
|
@ -82,6 +82,9 @@ class ParkEvent ;
|
|||||||
// *in that order*. If their implementations change such that these
|
// *in that order*. If their implementations change such that these
|
||||||
// assumptions are violated, a whole lot of code will break.
|
// assumptions are violated, a whole lot of code will break.
|
||||||
|
|
||||||
|
// The default length of monitor name is choosen to be 64 to avoid false sharing.
|
||||||
|
static const int MONITOR_NAME_LEN = 64;
|
||||||
|
|
||||||
class Monitor : public CHeapObj {
|
class Monitor : public CHeapObj {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -126,9 +129,8 @@ class Monitor : public CHeapObj {
|
|||||||
volatile intptr_t _WaitLock [1] ; // Protects _WaitSet
|
volatile intptr_t _WaitLock [1] ; // Protects _WaitSet
|
||||||
ParkEvent * volatile _WaitSet ; // LL of ParkEvents
|
ParkEvent * volatile _WaitSet ; // LL of ParkEvents
|
||||||
volatile bool _snuck; // Used for sneaky locking (evil).
|
volatile bool _snuck; // Used for sneaky locking (evil).
|
||||||
const char * _name; // Name of mutex
|
|
||||||
int NotifyCount ; // diagnostic assist
|
int NotifyCount ; // diagnostic assist
|
||||||
double pad [8] ; // avoid false sharing
|
char _name[MONITOR_NAME_LEN]; // Name of mutex
|
||||||
|
|
||||||
// Debugging fields for naming, deadlock detection, etc. (some only used in debug mode)
|
// Debugging fields for naming, deadlock detection, etc. (some only used in debug mode)
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
@ -170,7 +172,7 @@ class Monitor : public CHeapObj {
|
|||||||
int ILocked () ;
|
int ILocked () ;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static void ClearMonitor (Monitor * m) ;
|
static void ClearMonitor (Monitor * m, const char* name = NULL) ;
|
||||||
Monitor() ;
|
Monitor() ;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -188,10 +188,6 @@ void mutex_init() {
|
|||||||
|
|
||||||
def(Safepoint_lock , Monitor, safepoint, true ); // locks SnippetCache_lock/Threads_lock
|
def(Safepoint_lock , Monitor, safepoint, true ); // locks SnippetCache_lock/Threads_lock
|
||||||
|
|
||||||
if (!UseMembar) {
|
|
||||||
def(SerializePage_lock , Monitor, leaf, true );
|
|
||||||
}
|
|
||||||
|
|
||||||
def(Threads_lock , Monitor, barrier, true );
|
def(Threads_lock , Monitor, barrier, true );
|
||||||
|
|
||||||
def(VMOperationQueue_lock , Monitor, nonleaf, true ); // VM_thread allowed to block on these
|
def(VMOperationQueue_lock , Monitor, nonleaf, true ); // VM_thread allowed to block on these
|
||||||
|
@ -52,7 +52,6 @@ extern Mutex* DerivedPointerTableGC_lock; // a lock to protect the derive
|
|||||||
extern Monitor* VMOperationQueue_lock; // a lock on queue of vm_operations waiting to execute
|
extern Monitor* VMOperationQueue_lock; // a lock on queue of vm_operations waiting to execute
|
||||||
extern Monitor* VMOperationRequest_lock; // a lock on Threads waiting for a vm_operation to terminate
|
extern Monitor* VMOperationRequest_lock; // a lock on Threads waiting for a vm_operation to terminate
|
||||||
extern Monitor* Safepoint_lock; // a lock used by the safepoint abstraction
|
extern Monitor* Safepoint_lock; // a lock used by the safepoint abstraction
|
||||||
extern Monitor* SerializePage_lock; // a lock used when VMThread changing serialize memory page permission during safepoint
|
|
||||||
extern Monitor* Threads_lock; // a lock on the Threads table of active Java threads
|
extern Monitor* Threads_lock; // a lock on the Threads table of active Java threads
|
||||||
// (also used by Safepoints too to block threads creation/destruction)
|
// (also used by Safepoints too to block threads creation/destruction)
|
||||||
extern Monitor* CGC_lock; // used for coordination between
|
extern Monitor* CGC_lock; // used for coordination between
|
||||||
|
@ -956,7 +956,6 @@ bool os::set_boot_path(char fileSep, char pathSep) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void os::set_memory_serialize_page(address page) {
|
void os::set_memory_serialize_page(address page) {
|
||||||
int count = log2_intptr(sizeof(class JavaThread)) - log2_intptr(64);
|
int count = log2_intptr(sizeof(class JavaThread)) - log2_intptr(64);
|
||||||
_mem_serialize_page = (volatile int32_t *)page;
|
_mem_serialize_page = (volatile int32_t *)page;
|
||||||
@ -967,6 +966,8 @@ void os::set_memory_serialize_page(address page) {
|
|||||||
set_serialize_page_mask((uintptr_t)(vm_page_size() - sizeof(int32_t)));
|
set_serialize_page_mask((uintptr_t)(vm_page_size() - sizeof(int32_t)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static volatile intptr_t SerializePageLock = 0;
|
||||||
|
|
||||||
// This method is called from signal handler when SIGSEGV occurs while the current
|
// This method is called from signal handler when SIGSEGV occurs while the current
|
||||||
// thread tries to store to the "read-only" memory serialize page during state
|
// thread tries to store to the "read-only" memory serialize page during state
|
||||||
// transition.
|
// transition.
|
||||||
@ -974,15 +975,14 @@ void os::block_on_serialize_page_trap() {
|
|||||||
if (TraceSafepoint) {
|
if (TraceSafepoint) {
|
||||||
tty->print_cr("Block until the serialize page permission restored");
|
tty->print_cr("Block until the serialize page permission restored");
|
||||||
}
|
}
|
||||||
// When VMThread is holding the SerializePage_lock during modifying the
|
// When VMThread is holding the SerializePageLock during modifying the
|
||||||
// access permission of the memory serialize page, the following call
|
// access permission of the memory serialize page, the following call
|
||||||
// will block until the permission of that page is restored to rw.
|
// will block until the permission of that page is restored to rw.
|
||||||
// Generally, it is unsafe to manipulate locks in signal handlers, but in
|
// Generally, it is unsafe to manipulate locks in signal handlers, but in
|
||||||
// this case, it's OK as the signal is synchronous and we know precisely when
|
// this case, it's OK as the signal is synchronous and we know precisely when
|
||||||
// it can occur. SerializePage_lock is a transiently-held leaf lock, so
|
// it can occur.
|
||||||
// lock_without_safepoint_check should be safe.
|
Thread::muxAcquire(&SerializePageLock, "set_memory_serialize_page");
|
||||||
SerializePage_lock->lock_without_safepoint_check();
|
Thread::muxRelease(&SerializePageLock);
|
||||||
SerializePage_lock->unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serialize all thread state variables
|
// Serialize all thread state variables
|
||||||
@ -990,14 +990,12 @@ void os::serialize_thread_states() {
|
|||||||
// On some platforms such as Solaris & Linux, the time duration of the page
|
// On some platforms such as Solaris & Linux, the time duration of the page
|
||||||
// permission restoration is observed to be much longer than expected due to
|
// permission restoration is observed to be much longer than expected due to
|
||||||
// scheduler starvation problem etc. To avoid the long synchronization
|
// scheduler starvation problem etc. To avoid the long synchronization
|
||||||
// time and expensive page trap spinning, 'SerializePage_lock' is used to block
|
// time and expensive page trap spinning, 'SerializePageLock' is used to block
|
||||||
// the mutator thread if such case is encountered. Since this method is always
|
// the mutator thread if such case is encountered. See bug 6546278 for details.
|
||||||
// called by VMThread during safepoint, lock_without_safepoint_check is used
|
Thread::muxAcquire(&SerializePageLock, "serialize_thread_states");
|
||||||
// instead. See bug 6546278.
|
|
||||||
SerializePage_lock->lock_without_safepoint_check();
|
|
||||||
os::protect_memory( (char *)os::get_memory_serialize_page(), os::vm_page_size() );
|
os::protect_memory( (char *)os::get_memory_serialize_page(), os::vm_page_size() );
|
||||||
os::unguard_memory( (char *)os::get_memory_serialize_page(), os::vm_page_size() );
|
os::unguard_memory( (char *)os::get_memory_serialize_page(), os::vm_page_size() );
|
||||||
SerializePage_lock->unlock();
|
Thread::muxRelease(&SerializePageLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if the current stack pointer is above the stack shadow
|
// Returns true if the current stack pointer is above the stack shadow
|
||||||
|
Loading…
Reference in New Issue
Block a user