[foreign-memaccess] RFR: Alternative scalable MemoryScope

Peter Levart plevart at openjdk.java.net
Tue May 5 07:38:27 UTC 2020

On Mon, 4 May 2020 21:38:36 GMT, Paul Sandoz <psandoz at openjdk.org> wrote:

>> This is an alternative MemoryScope which is more scalable when used in a scenario where child scope is frequently
>> acquired and closed concurrently from multiple threads (for example in parallel Stream.findAny())
> src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/MemoryScope.java line 136:
>> 135:     private static final class Root extends MemoryScope {
>> 136:         private final LongAdder acquires;
>> 137:         private final LongAdder releases;
> Did you consider collapsing into just one `LongAdder` using `increment` (for acquiring), `decrement` (for releasing),
> and `sum` (checking a zero sum for closing)?  Perhaps it was discussed already, i lost track of all the discussion.

No, it was not discussed yet. I'm happy you brought it up. That would not work. LongAdder.sum() is not an atomic
operation. Consider the following scenario:
- precondition: adder.sum() == 0
- thread A1 successfully acquires child segment: adder.sum() == 1
- thread C calls close() on root segment
    * sets state = CLOSING
    * calls adder.sum() which starts summing LongAdder cells and just misses adder.increment() of thread A2...
- thread A2 tries to acquire child segment and so it 1st does adder.increment()
- thread A2 reads state == CLOSING and therefore undoes previous increment with adder.decrement() and fails, but...
- thread C that just missed A2's adder.increment() does see A2's adder.decrement() because it is performed on a different
  LongAdder cell which C reads after it is incremented, so what C gets as a result of adder.sum() is 0, it completes
  closing the root segment by setting state = CLOSED and executing cleanup, but thread A1 still has access to the child
  segment and BOOM!!!

Having two LongAdders (acquires, releases) and doing the sum() per-partes sequentially: 1st releases.sum(), then
acquires.sum() we guarantee that we never miss an acquiring thread's acquires.increment() but see the thread's
releases.increment(), so above scenario is not possible.


PR: https://git.openjdk.java.net/panama-foreign/pull/142

More information about the panama-dev mailing list