The discussions around and fix for JDK-8185278 had missed one case where two concurrent GC threads can update the list at the same time. Both the ConcurrentMarkThread and the G1YoungRemSetSamplingThread can end up doing remove_exported_entries() at the same time. In the fix for the previous bug we removed the lock protecting the list because we joined the SuspendibleThreadSet in the critical section in the ConcurrentMarkThread. Even thought both concurrent threads join the STS that doesn't stop them from running at the same time (just from running during a safepoint).
The assert I've run into looks like this:
# Internal Error (t:/workspace/open/src/hotspot/share/gc/g1/g1MMUTracker.cpp:98), pid=792, tid=5816
# assert(_head_index == _tail_index) failed: Because we have a full circular buffer
There are a few different ways to solve this, either we add back the lock and remove the STS and also add the lock to the add_pause() method. We can also remove the call to remove_expired_entries() in when_set() and that way avoid having multiple mutators of the list. The only time anyone would change the list would then be in add_pause(), which would first remove entries and than add the new one.
The assert I've run into looks like this:
# Internal Error (t:/workspace/open/src/hotspot/share/gc/g1/g1MMUTracker.cpp:98), pid=792, tid=5816
# assert(_head_index == _tail_index) failed: Because we have a full circular buffer
There are a few different ways to solve this, either we add back the lock and remove the STS and also add the lock to the add_pause() method. We can also remove the call to remove_expired_entries() in when_set() and that way avoid having multiple mutators of the list. The only time anyone would change the list would then be in add_pause(), which would first remove entries and than add the new one.