src/share/vm/runtime/mutex.cpp

Print this page
rev 6249 : 8039458: Ensure consistency of Monitor/Mutex lock acquisitions in relation to safepoint protocol
Reviewed-by:

*** 898,907 **** --- 898,908 ---- if (TryFast()) { Exeunt: assert (ILocked(), "invariant") ; assert (owner() == NULL, "invariant"); + debug_only(_acquired_with_no_safepoint_check = false;) set_owner (Self); return ; } // The lock is contended ...
*** 943,952 **** --- 944,954 ---- void Monitor::lock_without_safepoint_check (Thread * Self) { assert (_owner != Self, "invariant") ; ILock (Self) ; assert (_owner == NULL, "invariant"); + debug_only(_acquired_with_no_safepoint_check = true;) set_owner (Self); } void Monitor::lock_without_safepoint_check () { lock_without_safepoint_check (Thread::current()) ;
*** 981,990 **** --- 983,993 ---- } void Monitor::unlock() { assert (_owner == Thread::current(), "invariant") ; assert (_OnDeck != Thread::current()->_MutexEvent , "invariant") ; + debug_only(_acquired_with_no_safepoint_check = false); set_owner (NULL) ; if (_snuck) { assert(SafepointSynchronize::is_at_safepoint() && Thread::current()->is_VM_thread(), "sneak"); _snuck = false; return ;
*** 1150,1159 **** --- 1153,1163 ---- m->_LockWord.FullWord = 0 ; m->_EntryList = NULL ; m->_OnDeck = NULL ; m->_WaitSet = NULL ; m->_WaitLock[0] = 0 ; + debug_only(m->_acquired_with_no_safepoint_check = false); } Monitor::Monitor() { ClearMonitor(this); } Monitor::Monitor (int Rank, const char * name, bool allow_vm_block) {
*** 1306,1315 **** --- 1310,1321 ---- fatal(err_msg("acquiring lock %s/%d out of order with lock %s/%d -- " "possible deadlock", this->name(), this->rank(), locks->name(), locks->rank())); } + debug_only(ensure_lock_acquisition_consistency(new_owner);) + this->_next = new_owner->_owned_locks; new_owner->_owned_locks = this; #endif } else {
*** 1345,1354 **** --- 1351,1407 ---- _next = NULL; #endif } } + /* + * Ensure consistency of Monitor/Mutex lock acquisitions + * for Java Threads running inside the VM. + * + * If a thread has already acquired lock(s) using + * "Mutex::_no_safepoint_check_flag" (effectively going outside the + * safepoint protocol), the thread should be disallowed to acquire any + * additional lock which _is_ participating in the safepoint protocol. + * + * If a "safepoint protocol aware" lock is contended, and the thread entering + * is unable to "fast acquire" the lock using cas/try_spin, + * it will need to block/park. Blocking on a contended lock involves a + * state transition and a potential SafepointSynchronize::block() call. + * Transitioning to a blocked state still holding "Mutex::_no_safepoint_check_flag" + * acquired locks is allowed, but is *very* deadlock prone. + * + * The effect of allowing this state to happen without checking is subtle + * and hard to debug since a problem might only appear under heavy load and + * only in situations with increased concurrency levels (product builds). + * + * This function will preempt this problematic state for earlier deadlock detection. + */ + void Monitor::ensure_lock_acquisition_consistency(const Thread* new_owner) const { + if (new_owner != NULL && new_owner->is_Java_thread()) { + const Monitor* const locks = new_owner->owned_locks(); + if (locks != NULL) { + if (!acquired_with_no_safepoint_check()) { + if (locks->acquired_with_no_safepoint_check()) { + new_owner->print_owned_locks(); + fatal(err_msg("Acquiring lock (%s) might " + "cause the thread to block.\n" + "The thread is also the owner " + "of a lock previously taken using " + "Mutex::_no_safepoint_check_flag (%s).\n" + "This pattern is not allowed since " + "it is *very* deadlock prone!", + this->name(), + locks->name())); + } + } + } + } + } + + bool Monitor::acquired_with_no_safepoint_check(void) const { + return _acquired_with_no_safepoint_check; + } // Factored out common sanity checks for locking mutex'es. Used by lock() and try_lock() void Monitor::check_prelock_state(Thread *thread) { assert((!thread->is_Java_thread() || ((JavaThread *)thread)->thread_state() == _thread_in_vm) || rank() == Mutex::special, "wrong thread state for using locks");