RFR (M) 8195099: Concurrent safe-memory-reclamation mechanism

David Holmes david.holmes at oracle.com
Wed Apr 11 12:03:01 UTC 2018


On 11/04/2018 9:38 PM, Robbin Ehn wrote:
> Hi,
> 
> On 04/11/2018 12:57 PM, David Holmes wrote:
>>
>> Sorry no, I don't understand what this counter is doing at all. I feel 
>> I need to see what is between the begin/end critical section for this 
>> to make any sense to me. And to see what the writer actually does.
> 
>  From gtest:

Thanks for that. Okay I have a better sense of how the access to the 
data completes the handshake.

Does the naming/terminology come from some existing mechanism? I find it 
somewhat odd and not really descriptive of the operation..

Thanks,
David

> Read side do:
>    49       GlobalCounter::critical_section_begin(this);
>    50       volatile TestData* test = OrderAccess::load_acquire(_test);
>    51       long value = OrderAccess::load_acquire(&test->test_value);
>    52       ASSERT_EQ(value, GOOD);
>    53       GlobalCounter::critical_section_end(this);
> Write side do:
>   101         volatile TestData* free_tmp = test;
>   102         tmp = new TestData();
>   103         tmp->test_value = GOOD;
>   104         OrderAccess::release_store(&test, tmp);
>   105         GlobalCounter::write_synchronize();
>   106         free_tmp->test_value = BAD;
>   107         delete free_tmp;
> 
> If a reader is context switch between line 50 and 51, it will have a 
> cached value of the pointer "_test", thus no one should free it.
> 
> Before freeing the writer calls write_synchronize which guarantees that 
> no reader can see the old pointer and can then free it.
> 
> If the reader is context switch inside critical_section_begin this does 
> not matter since the fence in critical_section_begin prohibits the load 
> of test pointer from floating up. If write_synchronize is done before 
> this reader gets back on CPU it will see the new value but have an 
> counter of an old generation.
> If it gets back on CPU before write_synchronize I will see the old pointer.
> 
> If we call the pointer values TEST_gen_1, TEST_gen_2, ...
> test_pointer starts equal to TEST_gen_1 and generation starts at 1.
> 
> Writer: tmp_pointer = test_pointer
> Writer: test_pointer = TEST_gen_2
> Reader: load global counter (fetches 1)
> Reader: context switched out
> Writer: write_synchronized generation = 2, and do not see the reader.
> Reader: store local counter to 1 // critical section begin
> Reader: load test_pointer (TEST_gen_2) // This load will always happen 
> *after* the store to local counter
> Writer: free tmp_pointer (TEST_gen_1) // ABA safe
> 
> Writer: tmp_pointer = test_pointer
> Writer: test_pointer = TEST_gen_3
> Writer: write_synchronized generation = 3, and _sees_ on old reader => 
> wait.
> Reader: store local counter OFF // critical section end
> Writer: write_synchronized now finishes.
> Writer: free tmp_pointer (TEST_gen_2) // ABA safe
> 
> /Robbin
> 
>>
>> David
>> -----


More information about the hotspot-dev mailing list