Skip to content

Commit 619fe63

Browse files
committed
8362239: Reconcile enter_internal and reenter_internal in the ObjectMonitor code
Reviewed-by: dholmes, fbredberg, coleenp, pchilanomate, dcubed
1 parent a741e29 commit 619fe63

2 files changed

Lines changed: 71 additions & 126 deletions

File tree

src/hotspot/share/runtime/objectMonitor.cpp

Lines changed: 69 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -593,12 +593,15 @@ void ObjectMonitor::enter_with_contention_mark(JavaThread* current, ObjectMonito
593593
OSThreadContendState osts(current->osthread());
594594

595595
assert(current->thread_state() == _thread_in_vm, "invariant");
596+
ObjectWaiter node(current);
596597

597598
for (;;) {
598599
ExitOnSuspend eos(this);
599600
{
600601
ThreadBlockInVMPreprocess<ExitOnSuspend> tbivs(current, eos, true /* allow_suspend */);
601-
enter_internal(current);
602+
if (!try_enter_fast(current, &node)) {
603+
enter_internal(current, &node, false /* reenter_path */);
604+
}
602605
current->set_current_pending_monitor(nullptr);
603606
// We can go to a safepoint at the end of this block. If we
604607
// do a thread dump during that safepoint, then this thread will show
@@ -942,14 +945,17 @@ const char* ObjectMonitor::is_busy_to_string(stringStream* ss) {
942945
return ss->base();
943946
}
944947

945-
void ObjectMonitor::enter_internal(JavaThread* current) {
948+
bool ObjectMonitor::try_enter_fast(JavaThread* current, ObjectWaiter* current_node) {
949+
assert(current != nullptr, "invariant");
946950
assert(current->thread_state() == _thread_blocked, "invariant");
951+
assert(current_node != nullptr, "invariant");
952+
assert(current_node->_thread == current, "invariant");
947953

948954
// Try the lock - TATAS
949955
if (try_lock(current) == TryLockResult::Success) {
950956
assert(!has_successor(current), "invariant");
951957
assert(has_owner(current), "invariant");
952-
return;
958+
return true;
953959
}
954960

955961
assert(InitDone, "Unexpectedly not initialized");
@@ -964,7 +970,7 @@ void ObjectMonitor::enter_internal(JavaThread* current) {
964970
if (try_spin(current)) {
965971
assert(has_owner(current), "invariant");
966972
assert(!has_successor(current), "invariant");
967-
return;
973+
return true;
968974
}
969975

970976
// The Spin failed -- Enqueue and park the thread ...
@@ -973,54 +979,67 @@ void ObjectMonitor::enter_internal(JavaThread* current) {
973979

974980
// Enqueue "current" on ObjectMonitor's _entry_list.
975981
//
976-
// Node acts as a proxy for current.
982+
// current_node acts as a proxy for current.
977983
// As an aside, if were to ever rewrite the synchronization code mostly
978984
// in Java, WaitNodes, ObjectMonitors, and Events would become 1st-class
979985
// Java objects. This would avoid awkward lifecycle and liveness issues,
980986
// as well as eliminate a subset of ABA issues.
981987
// TODO: eliminate ObjectWaiter and enqueue either Threads or Events.
982988

983-
ObjectWaiter node(current);
984989
current->_ParkEvent->reset();
985990

986-
if (try_lock_or_add_to_entry_list(current, &node)) {
987-
return; // We got the lock.
991+
if (try_lock_or_add_to_entry_list(current, current_node)) {
992+
return true; // We got the lock.
988993
}
994+
989995
// This thread is now added to the _entry_list.
990996

991997
// The lock might have been released while this thread was occupied queueing
992998
// itself onto _entry_list. To close the race and avoid "stranding" and
993-
// progress-liveness failure we must resample-retry _owner before parking.
999+
// progress-liveness failure the caller must resample-retry _owner before parking.
9941000
// Note the Dekker/Lamport duality: ST _entry_list; MEMBAR; LD Owner.
995-
// In this case the ST-MEMBAR is accomplished with CAS().
996-
//
997-
// TODO: Defer all thread state transitions until park-time.
998-
// Since state transitions are heavy and inefficient we'd like
999-
// to defer the state transitions until absolutely necessary,
1000-
// and in doing so avoid some transitions ...
1001+
// In this case the ST-MEMBAR is accomplished with CAS() in try_lock_or_add_to_entry_list.
1002+
return false;
1003+
}
1004+
1005+
void ObjectMonitor::enter_internal(JavaThread* current, ObjectWaiter* current_node, bool reenter_path) {
1006+
assert(current != nullptr, "invariant");
1007+
assert(current->thread_state() == _thread_blocked, "invariant");
1008+
assert(current_node != nullptr, "invariant");
1009+
assert(current_node->_thread == current, "invariant");
10011010

10021011
// If there are unmounted virtual threads ahead in the _entry_list we want
10031012
// to do a timed-park instead to alleviate some deadlock cases where one
10041013
// of them is picked as the successor but cannot run due to having run out
10051014
// of carriers. This can happen, for example, if this is a pinned virtual
1006-
// thread currently loading or initializining a class, and all other carriers
1015+
// thread currently loading or initializing a class, and all other carriers
10071016
// have a pinned vthread waiting for said class to be loaded/initialized.
10081017
// Read counter *after* adding this thread to the _entry_list. Adding to
10091018
// _entry_list uses Atomic::cmpxchg() which already provides a fence that
1010-
// prevents this load from floating up previous store.
1019+
// prevents this load from floating up past a previous store.
10111020
// Note that we can have false positives where timed-park is not necessary.
1012-
bool do_timed_parked = has_unmounted_vthreads();
1021+
bool do_timed_park = has_unmounted_vthreads();
10131022
jlong recheck_interval = 1;
10141023

10151024
for (;;) {
1025+
ObjectWaiter::TStates v = current_node->TState;
1026+
guarantee(v == ObjectWaiter::TS_ENTER, "invariant");
10161027

10171028
if (try_lock(current) == TryLockResult::Success) {
10181029
break;
10191030
}
10201031
assert(!has_owner(current), "invariant");
10211032

1033+
if (reenter_path) {
1034+
// If try_lock failed, spin again - we expect the notifier to release the monitor quickly.
1035+
// Note that spin count may be zero so the above try_lock is necessary.
1036+
if (try_spin(current)) {
1037+
break;
1038+
}
1039+
}
1040+
10221041
// park self
1023-
if (do_timed_parked) {
1042+
if (do_timed_park) {
10241043
current->_ParkEvent->park(recheck_interval);
10251044
// Increase the recheck_interval, but clamp the value.
10261045
recheck_interval *= 8;
@@ -1031,18 +1050,23 @@ void ObjectMonitor::enter_internal(JavaThread* current) {
10311050
current->_ParkEvent->park();
10321051
}
10331052

1053+
// Try again, but just so we distinguish between futile wakeups and
1054+
// successful wakeups. The following test isn't algorithmically
1055+
// necessary, but it helps us maintain sensible statistics.
10341056
if (try_lock(current) == TryLockResult::Success) {
10351057
break;
10361058
}
10371059

10381060
// The lock is still contested.
10391061

1040-
// Assuming this is not a spurious wakeup we'll normally find _succ == current.
1041-
// We can defer clearing _succ until after the spin completes
1042-
// try_spin() must tolerate being called with _succ == current.
1043-
// Try yet another round of adaptive spinning.
1044-
if (try_spin(current)) {
1045-
break;
1062+
if (!reenter_path) {
1063+
// Assuming this is not a spurious wakeup we'll normally find _succ == current.
1064+
// We can defer clearing _succ until after the spin completes and
1065+
// try_spin() must tolerate being called with _succ == current.
1066+
// Try yet another round of adaptive spinning.
1067+
if (try_spin(current)) {
1068+
break;
1069+
}
10461070
}
10471071

10481072
// We can find that we were unpark()ed and redesignated _succ while
@@ -1051,15 +1075,22 @@ void ObjectMonitor::enter_internal(JavaThread* current) {
10511075
// just spin again. This pattern can repeat, leaving _succ to simply
10521076
// spin on a CPU.
10531077

1054-
if (has_successor(current)) clear_successor();
1078+
if (has_successor(current)) {
1079+
clear_successor();
1080+
}
10551081

10561082
// Invariant: after clearing _succ a thread *must* retry _owner before parking.
10571083
OrderAccess::fence();
1084+
1085+
// Will only potentially change on the reenter path - see comment in notify_internal.
1086+
do_timed_park |= current_node->_do_timed_park;
10581087
}
10591088

1089+
assert(has_owner(current), "invariant");
1090+
10601091
// Egress :
10611092
// Current has acquired the lock -- Unlink current from the _entry_list.
1062-
unlink_after_acquire(current, &node);
1093+
unlink_after_acquire(current, current_node);
10631094
if (has_successor(current)) {
10641095
clear_successor();
10651096
// Note that we don't need to do OrderAccess::fence() after clearing
@@ -1069,17 +1100,17 @@ void ObjectMonitor::enter_internal(JavaThread* current) {
10691100
// We've acquired ownership with CAS().
10701101
// CAS is serializing -- it has MEMBAR/FENCE-equivalent semantics.
10711102
// But since the CAS() this thread may have also stored into _succ
1072-
// or entry_list. These meta-data updates must be visible __before
1103+
// or entry_list. These meta-data updates must be visible __before
10731104
// this thread subsequently drops the lock.
10741105
// Consider what could occur if we didn't enforce this constraint --
10751106
// STs to monitor meta-data and user-data could reorder with (become
10761107
// visible after) the ST in exit that drops ownership of the lock.
10771108
// Some other thread could then acquire the lock, but observe inconsistent
1078-
// or old monitor meta-data and heap data. That violates the JMM.
1109+
// or old monitor meta-data and heap data. That violates the JMM.
10791110
// To that end, the exit() operation must have at least STST|LDST
1080-
// "release" barrier semantics. Specifically, there must be at least a
1111+
// "release" barrier semantics. Specifically, there must be at least a
10811112
// STST|LDST barrier in exit() before the ST of null into _owner that drops
1082-
// the lock. The barrier ensures that changes to monitor meta-data and data
1113+
// the lock. The barrier ensures that changes to monitor meta-data and data
10831114
// protected by the lock will be visible before we release the lock, and
10841115
// therefore before some other thread (CPU) has a chance to acquire the lock.
10851116
// See also: http://gee.cs.oswego.edu/dl/jmm/cookbook.html.
@@ -1088,98 +1119,10 @@ void ObjectMonitor::enter_internal(JavaThread* current) {
10881119
// the ST of null into _owner in the *subsequent* (following) corresponding
10891120
// monitorexit.
10901121

1122+
current_node->TState = ObjectWaiter::TS_RUN;
10911123
return;
10921124
}
10931125

1094-
// reenter_internal() is a specialized inline form of the latter half of the
1095-
// contended slow-path from enter_internal(). We use reenter_internal() only for
1096-
// monitor reentry in wait().
1097-
//
1098-
// In the future we should reconcile enter_internal() and reenter_internal().
1099-
1100-
void ObjectMonitor::reenter_internal(JavaThread* current, ObjectWaiter* currentNode) {
1101-
assert(current != nullptr, "invariant");
1102-
assert(current->thread_state() == _thread_blocked, "invariant");
1103-
assert(currentNode != nullptr, "invariant");
1104-
assert(currentNode->_thread == current, "invariant");
1105-
assert(_waiters > 0, "invariant");
1106-
1107-
// If there are unmounted virtual threads ahead in the _entry_list we want
1108-
// to do a timed-park instead to alleviate some deadlock cases where one
1109-
// of them is picked as the successor but cannot run due to having run out
1110-
// of carriers. This can happen, for example, if a mixed of unmounted and
1111-
// pinned vthreads taking up all the carriers are waiting for a class to be
1112-
// initialized, and the selected successor is one of the unmounted vthreads.
1113-
// Although this method is used for the "notification" case, it could be
1114-
// that this thread reached here without been added to the _entry_list yet.
1115-
// This can happen if it was interrupted or the wait timed-out at the same
1116-
// time. In that case we rely on currentNode->_do_timed_park, which will be
1117-
// read on the next loop iteration, after consuming the park permit set by
1118-
// the notifier in notify_internal.
1119-
// Note that we can have false positives where timed-park is not necessary.
1120-
bool do_timed_parked = has_unmounted_vthreads();
1121-
jlong recheck_interval = 1;
1122-
1123-
for (;;) {
1124-
ObjectWaiter::TStates v = currentNode->TState;
1125-
guarantee(v == ObjectWaiter::TS_ENTER, "invariant");
1126-
assert(!has_owner(current), "invariant");
1127-
1128-
// This thread has been notified so try to reacquire the lock.
1129-
if (try_lock(current) == TryLockResult::Success) {
1130-
break;
1131-
}
1132-
1133-
// If that fails, spin again. Note that spin count may be zero so the above TryLock
1134-
// is necessary.
1135-
if (try_spin(current)) {
1136-
break;
1137-
}
1138-
1139-
{
1140-
OSThreadContendState osts(current->osthread());
1141-
if (do_timed_parked) {
1142-
current->_ParkEvent->park(recheck_interval);
1143-
// Increase the recheck_interval, but clamp the value.
1144-
recheck_interval *= 8;
1145-
if (recheck_interval > MAX_RECHECK_INTERVAL) {
1146-
recheck_interval = MAX_RECHECK_INTERVAL;
1147-
}
1148-
} else {
1149-
current->_ParkEvent->park();
1150-
}
1151-
}
1152-
1153-
// Try again, but just so we distinguish between futile wakeups and
1154-
// successful wakeups. The following test isn't algorithmically
1155-
// necessary, but it helps us maintain sensible statistics.
1156-
if (try_lock(current) == TryLockResult::Success) {
1157-
break;
1158-
}
1159-
1160-
// The lock is still contested.
1161-
1162-
// Assuming this is not a spurious wakeup we'll normally
1163-
// find that _succ == current.
1164-
if (has_successor(current)) clear_successor();
1165-
1166-
// Invariant: after clearing _succ a contending thread
1167-
// *must* retry _owner before parking.
1168-
OrderAccess::fence();
1169-
1170-
// See comment in notify_internal
1171-
do_timed_parked |= currentNode->_do_timed_park;
1172-
}
1173-
1174-
// Current has acquired the lock -- Unlink current from the _entry_list.
1175-
assert(has_owner(current), "invariant");
1176-
unlink_after_acquire(current, currentNode);
1177-
if (has_successor(current)) clear_successor();
1178-
assert(!has_successor(current), "invariant");
1179-
currentNode->TState = ObjectWaiter::TS_RUN;
1180-
OrderAccess::fence(); // see comments at the end of enter_internal()
1181-
}
1182-
11831126
// This method is called from two places:
11841127
// - On monitorenter contention with a null waiter.
11851128
// - After Object.wait() times out or the target is interrupted to reenter the
@@ -1971,7 +1914,9 @@ void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) {
19711914
ExitOnSuspend eos(this);
19721915
{
19731916
ThreadBlockInVMPreprocess<ExitOnSuspend> tbivs(current, eos, true /* allow_suspend */);
1974-
reenter_internal(current, &node);
1917+
assert( _waiters > 0, "invariant");
1918+
OSThreadContendState osts(current->osthread());
1919+
enter_internal(current, &node, true /* reenter_path */);
19751920
// We can go to a safepoint at the end of this block. If we
19761921
// do a thread dump during that safepoint, then this thread will show
19771922
// as having "-locked" the monitor, but the OS and java.lang.Thread
@@ -2082,12 +2027,12 @@ bool ObjectMonitor::notify_internal(JavaThread* current) {
20822027
// Wake up the thread to alleviate some deadlock cases where the successor
20832028
// that will be picked up when this thread releases the monitor is an unmounted
20842029
// virtual thread that cannot run due to having run out of carriers. Upon waking
2085-
// up, the thread will call reenter_internal() which will use timed-park in case
2030+
// up, the thread will call enter_internal(..., true) which will use timed-park in case
20862031
// there is contention and there are still vthreads in the _entry_list.
20872032
// If the target was interrupted or the wait timed-out at the same time, it could
2088-
// have reached reenter_internal and read a false value of has_unmounted_vthreads()
2033+
// have reached enter_internal and read a false value of has_unmounted_vthreads()
20892034
// before we added it to the _entry_list above. To deal with that case, we set _do_timed_park
2090-
// which will be read by the target on the next loop iteration in reenter_internal.
2035+
// which will be read by the target on the next loop iteration in enter_internal.
20912036
iterator->_do_timed_park = true;
20922037
JavaThread* t = iterator->thread();
20932038
t->_ParkEvent->unpark();

src/hotspot/share/runtime/objectMonitor.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -394,8 +394,8 @@ class ObjectMonitor : public CHeapObj<mtObjectMonitor> {
394394
bool notify_internal(JavaThread* current);
395395
ObjectWaiter* dequeue_waiter();
396396
void dequeue_specific_waiter(ObjectWaiter* waiter);
397-
void enter_internal(JavaThread* current);
398-
void reenter_internal(JavaThread* current, ObjectWaiter* current_node);
397+
void enter_internal(JavaThread* current, ObjectWaiter* current_node, bool reenter_path);
398+
bool try_enter_fast(JavaThread* current, ObjectWaiter* current_node);
399399
void entry_list_build_dll(JavaThread* current);
400400
void unlink_after_acquire(JavaThread* current, ObjectWaiter* current_node);
401401
ObjectWaiter* entry_list_tail(JavaThread* current);

0 commit comments

Comments
 (0)