RFR(M): 8033552: Fix missing missing volatile specifiers in CAS operations in GC code

Kim Barrett kim.barrett at oracle.com
Wed Sep 14 20:49:24 UTC 2016

> On Sep 13, 2016, at 11:28 AM, Erik Österlund <erik.osterlund at oracle.com> wrote:
> Hi Kim,
> New webrev with your proposed changes:
> http://cr.openjdk.java.net/~eosterlund/8033552/webrev.05/

Looks good.

A few replies inline below.

> On 2016-09-13 00:20, Kim Barrett wrote:
>> src/share/vm/gc/shared/taskqueue.hpp
>>  129     void increment() volatile {
>>  130       _fields._top = increment_index(_fields._top);
>>  131       if (_fields._top == 0) ++_fields._tag;
>>  132     }
>> Perhaps this should be
>>   uint new_top = increment_index(_fields._top);
>>   _fields._top = new_top;
>>   if (new_top == 0) ++_fields._tag;
>> Although if it matters then we probably have other
>> problems... e.g. adding a volatile qualifier doesn't make this
>> thread-safe. And if it doesn't need to be thread-safe, then why add
>> the volatile qualifier?
> I do not have strong opinions on this one. It should not matter as you say, but it seemed more consistent when the other member functions above were implemented with volatile.
> I decided to withdraw that volatile specifier on this one as it seems you would prefer that.

The addition of the volatile qualifier suggests a need for
thread-safety, but the existing code isn't (nor is my suggested
change, though it's a step along the way).

So I looked at how increment() is used, and the volatile isn't needed.
It is only applied to a freshly made copy.

So I accept the withdrawal of that change.

>> -----------------------------------------------------------------------------
>> [This question from my initial review seems not covered anywhere.  I
>> don't know if there is actually a bug here.  If there is, it should be
>> a new CR.]
>> src/share/vm/gc/g1/sparsePRT.hpp
>>  -- no direct comments, however:
>> src/share/vm/gc/g1/sparsePRT.cpp
>> Can add_to_expanded_list be called by multiple threads with the same
>> argument at the same time?  If so, it doesn't look correct.  It has a
>> comment saying multiple expansions are possible, but should only be
>> put on list once.  But it's not clear whether that can happen from
>> multiple threads at the same time.  The check expanded / set expanded
>> dance is not thread safe.
> I did answer it, but sorry if I was not explicit enough that my comment was linked to this. Yes it can be called by multiple threads. However, I can not see what is wrong about that.
> If you are thinking about the classic ABA problem, I can not see how that would be triggered, because the list is operated on in split phases protected by a safepoint where it's either add-only (outside of safepoint, while adding sparsePRT data), or remove-only (inside of safepoint, before card scanning).
> Having multiple competing threads only adding or only removing from the list without explicit ABA-protection mechanisms should be safe.
> The only remaining problem is the variable _expanded. And it is changed only on the current sparsePRT, while under the per-region lock in OtherRegionsTable::add_reference() calling SparsePRT::add_card, calling SparsePRT::add_to_expanded_list, ultimately calling add_to_expanded_list that we are currently looking at.
> So the data for the specific SparsePRT is changed under a per-region lock, and it's added to a list (which can happen concurrent to other SparsePRTs being expanded), but that is fine as the ABA-problem can't occur as the entries do not get deleted until after a safepoint synchronization, when the list is consumed during cleanup before card scanning.

The point is that there's a comment that it should only be added to
the list once, but the mechanism for doing so is not thread-safe, so
unless there is a lock somewhere protecting the call (which Thomas
provided a pointer to - thanks Thomas), then the constraint described
by the comment may not be met.

More information about the hotspot-gc-dev mailing list