8355646: Optimize ObjectMonitor::exit
Reviewed-by: pchilanomate, coleenp
This commit is contained in:
parent
a3afc9f7ce
commit
39a28ffe4e
@ -1507,7 +1507,34 @@ void ObjectMonitor::exit(JavaThread* current, bool not_suspended) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
assert(has_owner(current), "invariant");
|
// If there is a successor we should release the lock as soon as
|
||||||
|
// possible, so that the successor can acquire the lock. If there is
|
||||||
|
// no successor, we might need to wake up a waiting thread.
|
||||||
|
if (!has_successor()) {
|
||||||
|
ObjectWaiter* w = Atomic::load(&_entry_list);
|
||||||
|
if (w != nullptr) {
|
||||||
|
// Other threads are blocked trying to acquire the lock and
|
||||||
|
// there is no successor, so it appears that an heir-
|
||||||
|
// presumptive (successor) must be made ready. Since threads
|
||||||
|
// are woken up in FIFO order, we need to find the tail of the
|
||||||
|
// entry_list.
|
||||||
|
w = entry_list_tail(current);
|
||||||
|
// I'd like to write: guarantee (w->_thread != current).
|
||||||
|
// But in practice an exiting thread may find itself on the entry_list.
|
||||||
|
// Let's say thread T1 calls O.wait(). Wait() enqueues T1 on O's waitset and
|
||||||
|
// then calls exit(). Exit release the lock by setting O._owner to null.
|
||||||
|
// Let's say T1 then stalls. T2 acquires O and calls O.notify(). The
|
||||||
|
// notify() operation moves T1 from O's waitset to O's entry_list. T2 then
|
||||||
|
// release the lock "O". T1 resumes immediately after the ST of null into
|
||||||
|
// _owner, above. T1 notices that the entry_list is populated, so it
|
||||||
|
// reacquires the lock and then finds itself on the entry_list.
|
||||||
|
// Given all that, we have to tolerate the circumstance where "w" is
|
||||||
|
// associated with current.
|
||||||
|
assert(w->TState == ObjectWaiter::TS_ENTER, "invariant");
|
||||||
|
exit_epilog(current, w);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Drop the lock.
|
// Drop the lock.
|
||||||
// release semantics: prior loads and stores from within the critical section
|
// release semantics: prior loads and stores from within the critical section
|
||||||
@ -1547,11 +1574,9 @@ void ObjectMonitor::exit(JavaThread* current, bool not_suspended) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Other threads are blocked trying to acquire the lock and there
|
// Only the current lock owner can manipulate the entry_list
|
||||||
// is no successor, so it appears that an heir-presumptive
|
// (except for pushing new threads to the head), therefore we need
|
||||||
// (successor) must be made ready. Only the current lock owner can
|
// to reacquire the lock. If we fail to reacquire the lock the
|
||||||
// detach threads from the entry_list, therefore we need to
|
|
||||||
// reacquire the lock. If we fail to reacquire the lock the
|
|
||||||
// responsibility for ensuring succession falls to the new owner.
|
// responsibility for ensuring succession falls to the new owner.
|
||||||
|
|
||||||
if (try_lock(current) != TryLockResult::Success) {
|
if (try_lock(current) != TryLockResult::Success) {
|
||||||
@ -1561,27 +1586,6 @@ void ObjectMonitor::exit(JavaThread* current, bool not_suspended) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
guarantee(has_owner(current), "invariant");
|
guarantee(has_owner(current), "invariant");
|
||||||
|
|
||||||
ObjectWaiter* w = nullptr;
|
|
||||||
|
|
||||||
w = Atomic::load(&_entry_list);
|
|
||||||
if (w != nullptr) {
|
|
||||||
w = entry_list_tail(current);
|
|
||||||
// I'd like to write: guarantee (w->_thread != current).
|
|
||||||
// But in practice an exiting thread may find itself on the entry_list.
|
|
||||||
// Let's say thread T1 calls O.wait(). Wait() enqueues T1 on O's waitset and
|
|
||||||
// then calls exit(). Exit release the lock by setting O._owner to null.
|
|
||||||
// Let's say T1 then stalls. T2 acquires O and calls O.notify(). The
|
|
||||||
// notify() operation moves T1 from O's waitset to O's entry_list. T2 then
|
|
||||||
// release the lock "O". T1 resumes immediately after the ST of null into
|
|
||||||
// _owner, above. T1 notices that the entry_list is populated, so it
|
|
||||||
// reacquires the lock and then finds itself on the entry_list.
|
|
||||||
// Given all that, we have to tolerate the circumstance where "w" is
|
|
||||||
// associated with current.
|
|
||||||
assert(w->TState == ObjectWaiter::TS_ENTER, "invariant");
|
|
||||||
exit_epilog(current, w);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user