< prev index next >
src/hotspot/share/runtime/objectMonitor.cpp
Print this page
rev 54110 : Checkpoint latest preliminary review patches for full OpenJDK review.
*** 236,271 ****
}
// -----------------------------------------------------------------------------
// Enter support
! void ObjectMonitor::enter(TRAPS) {
// The following code is ordered to check the most common cases first
// and to reduce RTS->RTO cache line upgrades on SPARC and IA32 processors.
Thread * const Self = THREAD;
void * cur = Atomic::cmpxchg(Self, &_owner, (void*)NULL);
if (cur == NULL) {
// Either ASSERT _recursions == 0 or explicitly set _recursions = 0.
assert(_recursions == 0, "invariant");
assert(_owner == Self, "invariant");
! return;
}
if (cur == Self) {
// TODO-FIXME: check for integer overflow! BUGID 6557169.
_recursions++;
! return;
}
if (Self->is_lock_owned ((address)cur)) {
assert(_recursions == 0, "internal state error");
_recursions = 1;
// Commute owner from a thread-specific on-stack BasicLockObject address to
// a full-fledged "Thread *".
_owner = Self;
! return;
}
// We've encountered genuine contention.
assert(Self->_Stalled == 0, "invariant");
Self->_Stalled = intptr_t(this);
--- 236,271 ----
}
// -----------------------------------------------------------------------------
// Enter support
! bool ObjectMonitor::enter(TRAPS) {
// The following code is ordered to check the most common cases first
// and to reduce RTS->RTO cache line upgrades on SPARC and IA32 processors.
Thread * const Self = THREAD;
void * cur = Atomic::cmpxchg(Self, &_owner, (void*)NULL);
if (cur == NULL) {
// Either ASSERT _recursions == 0 or explicitly set _recursions = 0.
assert(_recursions == 0, "invariant");
assert(_owner == Self, "invariant");
! return true;
}
if (cur == Self) {
// TODO-FIXME: check for integer overflow! BUGID 6557169.
_recursions++;
! return true;
}
if (Self->is_lock_owned ((address)cur)) {
assert(_recursions == 0, "internal state error");
_recursions = 1;
// Commute owner from a thread-specific on-stack BasicLockObject address to
// a full-fledged "Thread *".
_owner = Self;
! return true;
}
// We've encountered genuine contention.
assert(Self->_Stalled == 0, "invariant");
Self->_Stalled = intptr_t(this);
*** 278,302 ****
if (TrySpin(Self) > 0) {
assert(_owner == Self, "invariant");
assert(_recursions == 0, "invariant");
assert(((oop)(object()))->mark() == markOopDesc::encode(this), "invariant");
Self->_Stalled = 0;
! return;
}
assert(_owner != Self, "invariant");
assert(_succ != Self, "invariant");
assert(Self->is_Java_thread(), "invariant");
JavaThread * jt = (JavaThread *) Self;
assert(!SafepointSynchronize::is_at_safepoint(), "invariant");
assert(jt->thread_state() != _thread_blocked, "invariant");
! assert(this->object() != NULL, "invariant");
! assert(_count >= 0, "invariant");
! // Prevent deflation at STW-time. See deflate_idle_monitors() and is_busy().
// Ensure the object-monitor relationship remains stable while there's contention.
! Atomic::inc(&_count);
JFR_ONLY(JfrConditionalFlushWithStacktrace<EventJavaMonitorEnter> flush(jt);)
EventJavaMonitorEnter event;
if (event.should_commit()) {
event.set_monitorClass(((oop)this->object())->klass());
--- 278,310 ----
if (TrySpin(Self) > 0) {
assert(_owner == Self, "invariant");
assert(_recursions == 0, "invariant");
assert(((oop)(object()))->mark() == markOopDesc::encode(this), "invariant");
Self->_Stalled = 0;
! return true;
}
assert(_owner != Self, "invariant");
assert(_succ != Self, "invariant");
assert(Self->is_Java_thread(), "invariant");
JavaThread * jt = (JavaThread *) Self;
assert(!SafepointSynchronize::is_at_safepoint(), "invariant");
assert(jt->thread_state() != _thread_blocked, "invariant");
! assert(AsyncDeflateIdleMonitors || this->object() != NULL, "invariant");
! assert(AsyncDeflateIdleMonitors || _count >= 0, "invariant");
! // Prevent deflation. See ObjectSynchronizer::deflate_monitor() and is_busy().
// Ensure the object-monitor relationship remains stable while there's contention.
! const jint count = Atomic::add(1, &_count);
! if (count <= 0 && _owner == DEFLATER_MARKER) {
! // Async deflation in progress. Help deflater thread install
! // the mark word (in case deflater thread is slow).
! install_displaced_markword_in_object();
! Self->_Stalled = 0;
! return false; // Caller should retry. Never mind about _count as this monitor has been deflated.
! }
! // The deflater thread will not deflate this monitor and the monitor is contended, continue.
JFR_ONLY(JfrConditionalFlushWithStacktrace<EventJavaMonitorEnter> flush(jt);)
EventJavaMonitorEnter event;
if (event.should_commit()) {
event.set_monitorClass(((oop)this->object())->klass());
*** 354,364 ****
// states will still report that the thread is blocked trying to
// acquire it.
}
Atomic::dec(&_count);
! assert(_count >= 0, "invariant");
Self->_Stalled = 0;
// Must either set _recursions = 0 or ASSERT _recursions == 0.
assert(_recursions == 0, "invariant");
assert(_owner == Self, "invariant");
--- 362,372 ----
// states will still report that the thread is blocked trying to
// acquire it.
}
Atomic::dec(&_count);
! assert(AsyncDeflateIdleMonitors || _count >= 0, "invariant");
Self->_Stalled = 0;
// Must either set _recursions = 0 or ASSERT _recursions == 0.
assert(_recursions == 0, "invariant");
assert(_owner == Self, "invariant");
*** 390,399 ****
--- 398,408 ----
if (event.should_commit()) {
event.set_previousOwner((uintptr_t)_previous_owner_tid);
event.commit();
}
OM_PERFDATA_OP(ContendedLockAttempts, inc());
+ return true;
}
// Caveat: TryLock() is not necessarily serializing if it returns failure.
// Callers must compensate as needed.
*** 411,420 ****
--- 420,490 ----
// We can either return -1 or retry.
// Retry doesn't make as much sense because the lock was just acquired.
return -1;
}
+ // Install the displaced markword of a deflated monitor into the object
+ // associated with the monitor.
+ // This method is idempotent and is executed by both mutators wanting to
+ // acquire a monitor for an object and the thread deflating monitors.
+ // A mutator trying to install a hash in the monitor's _header field can
+ // also run in parallel to this method.
+ void ObjectMonitor::install_displaced_markword_in_object() {
+ markOop dmw = header();
+ if (dmw == NULL) {
+ // The thread deflating monitors has won the race so we
+ // have nothing to do.
+ return;
+ }
+
+ // A non-NULL dmw has to be either neutral or is participating in
+ // this restoration protocol.
+ assert(dmw->is_neutral() || (dmw->is_marked() && dmw->hash() == 0),
+ "failed precondition: is_neutral=%d, is_marked=%d, hash="
+ INTPTR_FORMAT, dmw->is_neutral(), dmw->is_marked(), dmw->hash());
+
+ if (!dmw->is_marked() && dmw->hash() == 0) {
+ // This dmw is neutral and has not yet started the restoration
+ // protocol so we mark a copy of the dmw to begin the protocol.
+ markOop marked_dmw = dmw->set_marked();
+ assert(marked_dmw->is_marked() && marked_dmw->hash() == 0,
+ "sanity_check: is_marked=%d, hash=" INTPTR_FORMAT,
+ marked_dmw->is_marked(), marked_dmw->hash());
+
+ // There can be three different racers trying to update the _header
+ // field and the return dmw value will tell us what cleanup needs
+ // to be done (if any) after the race winner:
+ // 1) A mutator trying to install a hash in the object.
+ // Note: That mutator is not executing this code, but it is
+ // trying to update the _header field.
+ // If winner: dmw will contain the hash and be unmarked
+ // 2a) A mutator trying to acquire the monitor via enter():
+ // If winner: dmw is marked and hash() == 0
+ // 2b) The thread deflating the monitor via deflate_monitor_using_JT():
+ // If winner: dmw is marked and hash() == 0
+ dmw = (markOop) Atomic::cmpxchg(marked_dmw, &_header, dmw);
+ }
+
+ if (dmw->is_marked()) {
+ // The dmw copy is marked which means a hash was not set by a racing
+ // thread. Clear the mark from the copy in preparation for possible
+ // restoration from this thread.
+ assert(dmw->hash() == 0, "must be 0: hash=" INTPTR_FORMAT, dmw->hash());
+ dmw = dmw->set_unmarked();
+ }
+ assert(dmw->is_neutral(), "must be a neutral markword");
+
+ oop const obj = (oop) object();
+ // Install displaced markword if object markword still points to this
+ // monitor. Both the mutator trying to enter() and the thread deflating
+ // the monitor will reach this point, but only one can win.
+ // Note: If a mutator won the cmpxchg() race above and installed a hash
+ // in _header, then the updated dmw contains that hash and we'll install
+ // it in the object's markword here.
+ obj->cas_set_mark(dmw, markOopDesc::encode(this));
+ }
+
#define MAX_RECHECK_INTERVAL 1000
void ObjectMonitor::EnterI(TRAPS) {
Thread * const Self = THREAD;
assert(Self->is_Java_thread(), "invariant");
*** 426,435 ****
--- 496,517 ----
assert(_owner == Self, "invariant");
assert(_Responsible != Self, "invariant");
return;
}
+ if (_owner == DEFLATER_MARKER) {
+ guarantee(0 < _count, "_owner == DEFLATER_MARKER && _count <= 0 should have been handled by the caller");
+ // Deflater thread tried to lock this monitor, but it failed to make _count negative and gave up.
+ // Try to acquire monitor.
+ if (Atomic::cmpxchg(Self, &_owner, DEFLATER_MARKER) == DEFLATER_MARKER) {
+ assert(_succ != Self, "invariant");
+ assert(_owner == Self, "invariant");
+ assert(_Responsible != Self, "invariant");
+ return;
+ }
+ }
+
assert(InitDone, "Unexpectedly not initialized");
// We try one round of spinning *before* enqueueing Self.
//
// If the _owner is ready but OFFPROC we could use a YieldTo()
*** 542,551 ****
--- 624,642 ----
Self->_ParkEvent->park();
}
if (TryLock(Self) > 0) break;
+ if (_owner == DEFLATER_MARKER) {
+ guarantee(0 < _count, "_owner == DEFLATER_MARKER && _count <= 0 should have been handled by the caller");
+ // Deflater thread tried to lock this monitor, but it failed to make _count negative and gave up.
+ if (Atomic::cmpxchg(Self, &_owner, DEFLATER_MARKER) == DEFLATER_MARKER) {
+ // Acquired the monitor.
+ break;
+ }
+ }
+
// The lock is still contested.
// Keep a tally of the # of futile wakeups.
// Note that the counter is not protected by a lock or updated by atomics.
// That is by design - we trade "lossy" counters which are exposed to
// races during updates for a lower probe effect.
*** 663,672 ****
--- 754,771 ----
assert(_owner != Self, "invariant");
if (TryLock(Self) > 0) break;
if (TrySpin(Self) > 0) break;
+ if (_owner == DEFLATER_MARKER) {
+ guarantee(0 <= _count, "Impossible: _owner == DEFLATER_MARKER && _count < 0, monitor must not be owned by deflater thread here");
+ if (Atomic::cmpxchg(Self, &_owner, DEFLATER_MARKER) == DEFLATER_MARKER) {
+ // Acquired the monitor.
+ break;
+ }
+ }
+
// State transition wrappers around park() ...
// ReenterI() wisely defers state transitions until
// it's clear we must park the thread.
{
OSThreadContendState osts(Self->osthread());
*** 1120,1139 ****
return save;
}
// reenter() enters a lock and sets recursion count
// complete_exit/reenter operate as a wait without waiting
! void ObjectMonitor::reenter(intptr_t recursions, TRAPS) {
Thread * const Self = THREAD;
assert(Self->is_Java_thread(), "Must be Java thread!");
JavaThread *jt = (JavaThread *)THREAD;
guarantee(_owner != Self, "reenter already owner");
! enter(THREAD); // enter the monitor
guarantee(_recursions == 0, "reenter recursion");
_recursions = recursions;
! return;
}
// -----------------------------------------------------------------------------
// A macro is used below because there may already be a pending
--- 1219,1242 ----
return save;
}
// reenter() enters a lock and sets recursion count
// complete_exit/reenter operate as a wait without waiting
! bool ObjectMonitor::reenter(intptr_t recursions, TRAPS) {
Thread * const Self = THREAD;
assert(Self->is_Java_thread(), "Must be Java thread!");
JavaThread *jt = (JavaThread *)THREAD;
guarantee(_owner != Self, "reenter already owner");
! if (!enter(THREAD)) {
! // Failed to enter the monitor so return for a retry.
! return false;
! }
! // Entered the monitor.
guarantee(_recursions == 0, "reenter recursion");
_recursions = recursions;
! return true;
}
// -----------------------------------------------------------------------------
// A macro is used below because there may already be a pending
*** 1357,1367 ****
Self->_Stalled = 0;
assert(_owner != Self, "invariant");
ObjectWaiter::TStates v = node.TState;
if (v == ObjectWaiter::TS_RUN) {
! enter(Self);
} else {
guarantee(v == ObjectWaiter::TS_ENTER || v == ObjectWaiter::TS_CXQ, "invariant");
ReenterI(Self, &node);
node.wait_reenter_end(this);
}
--- 1460,1471 ----
Self->_Stalled = 0;
assert(_owner != Self, "invariant");
ObjectWaiter::TStates v = node.TState;
if (v == ObjectWaiter::TS_RUN) {
! const bool success = enter(Self);
! guarantee(success, "enter signaled for a retry, but monitor should not have been deflated as waiters > 0");
} else {
guarantee(v == ObjectWaiter::TS_ENTER || v == ObjectWaiter::TS_CXQ, "invariant");
ReenterI(Self, &node);
node.wait_reenter_end(this);
}
*** 1920,1924 ****
--- 2024,2095 ----
#undef NEWPERFVARIABLE
}
DEBUG_ONLY(InitDone = true;)
}
+
+ // For internal used by ObjectSynchronizer::monitors_iterate().
+ ObjectMonitorHandle::ObjectMonitorHandle(ObjectMonitor * om_ptr) {
+ om_ptr->inc_ref_count();
+ _om_ptr = om_ptr;
+ }
+
+ ObjectMonitorHandle::~ObjectMonitorHandle() {
+ if (_om_ptr != NULL) {
+ _om_ptr->dec_ref_count();
+ _om_ptr = NULL;
+ }
+ }
+
+ // Save the ObjectMonitor* associated with the specified markOop and
+ // increment the ref_count. This function should only be called if
+ // the caller has verified mark->has_monitor() == true. The object
+ // parameter is needed to verify that ObjectMonitor* has not been
+ // deflated and reused for another object.
+ //
+ // This function returns true if the ObjectMonitor* has been safely
+ // saved. This function returns false if we have lost a race with
+ // async deflation; the caller should retry as appropriate.
+ //
+ bool ObjectMonitorHandle::save_om_ptr(oop object, markOop mark) {
+ guarantee(mark->has_monitor(), "sanity check: mark=" INTPTR_FORMAT,
+ p2i((address)mark));
+
+ ObjectMonitor * om_ptr = mark->monitor();
+ om_ptr->inc_ref_count();
+
+ if (AsyncDeflateIdleMonitors) {
+ // Race here if monitor is not owned! The above ref_count bump
+ // will cause subsequent async deflation to skip it. However,
+ // previous or concurrent async deflation is a race.
+ if (om_ptr->_owner == DEFLATER_MARKER) {
+ // Async deflation won the race so we have to retry.
+ om_ptr->dec_ref_count();
+ return false;
+ }
+ // The ObjectMonitor could have been deflated and reused for
+ // another object before we bumped the ref_count so make sure
+ // our object still refers to this ObjectMonitor.
+ const markOop tmp = object->mark();
+ if (!tmp->has_monitor() || tmp->monitor() != om_ptr) {
+ // Async deflation and reuse won the race so we have to retry.
+ om_ptr->dec_ref_count();
+ return false;
+ }
+ }
+
+ guarantee(_om_ptr == NULL, "sanity check: _om_ptr=" INTPTR_FORMAT,
+ p2i(_om_ptr));
+ _om_ptr = om_ptr;
+ return true;
+ }
+
+ // For internal use by ObjectSynchronizer::inflate().
+ void ObjectMonitorHandle::set_om_ptr(ObjectMonitor * om_ptr) {
+ // Cannot guarantee() is_new() here. As soon as the ObjectMonitor*
+ // is attached to the object in inflate(), it can be used by other
+ // JavaThreads.
+ // guarantee(om_ptr->is_new(), "sanity check: allocation_state=%d",
+ // int(om_ptr->allocation_state()));
+ om_ptr->inc_ref_count();
+ _om_ptr = om_ptr;
+ }
< prev index next >