RFR: 8166197: assert(RelaxAssert || w != Thread::current()->_MutexEvent) failed: invariant
David Holmes
david.holmes at oracle.com
Wed Oct 12 05:08:38 UTC 2016
Bug: https://bugs.openjdk.java.net/browse/JDK-8166197
webrev: http://cr.openjdk.java.net/~dholmes/8166197/webrev/
In IUnlock we have the following succession code to wakeup the "onDeck"
thread:
ParkEvent * List = _EntryList;
if (List != NULL) {
// Transfer the head of the EntryList to the OnDeck position.
// Once OnDeck, a thread stays OnDeck until it acquires the lock.
// For a given lock there is at most OnDeck thread at any one instant.
WakeOne:
assert(List == _EntryList, "invariant");
ParkEvent * const w = List;
assert(RelaxAssert || w != Thread::current()->_MutexEvent,
"invariant");
_EntryList = w->ListNext;
// as a diagnostic measure consider setting w->_ListNext = BAD
assert(UNS(_OnDeck) == _LBIT, "invariant");
_OnDeck = w; // pass OnDeck to w.
It is critical that the update to _EntryList happens before we set
_OnDeck, as as soon as _OnDeck is set the selected thread (which need
not yet have parked) can acquire the mutex, complete its critical
section and proceed to unlock the mutex, and so execute IUnlock in
parallel with the original thread. If the write to _EntryList has not
yet happened that second thread finds itself still at the head of
_EntryList and so the assert fires. If the write to _EntryList happens
after the load "List = _EntryList", then the first assert can also fire.
Preferred fix today is to use OrderAccess::release_store(&_OnDeck, w)
with a matching load_acquire(&_OnDeck) in the ILock code:
while (_OnDeck != ESelf) {
ParkCommon(ESelf, 0);
}
and corresponding "raw" lock code. Also fixed a couple of typos.
Thanks,
David
More information about the hotspot-runtime-dev
mailing list