diff --git a/src/hotspot/share/runtime/objectMonitor.cpp b/src/hotspot/share/runtime/objectMonitor.cpp index 44899225691..ceac0b42acf 100644 --- a/src/hotspot/share/runtime/objectMonitor.cpp +++ b/src/hotspot/share/runtime/objectMonitor.cpp @@ -1507,7 +1507,34 @@ void ObjectMonitor::exit(JavaThread* current, bool not_suspended) { #endif 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. // release semantics: prior loads and stores from within the critical section @@ -1547,11 +1574,9 @@ void ObjectMonitor::exit(JavaThread* current, bool not_suspended) { return; } - // 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. Only the current lock owner can - // detach threads from the entry_list, therefore we need to - // reacquire the lock. If we fail to reacquire the lock the + // Only the current lock owner can manipulate the entry_list + // (except for pushing new threads to the head), therefore we need + // to reacquire the lock. If we fail to reacquire the lock the // responsibility for ensuring succession falls to the new owner. if (try_lock(current) != TryLockResult::Success) { @@ -1561,27 +1586,6 @@ void ObjectMonitor::exit(JavaThread* current, bool not_suspended) { } 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; - } } }