From 2e6f9652035b74dacc30cbc99c9a2f762e44a78d Mon Sep 17 00:00:00 2001 From: Per Minborg Date: Wed, 9 Nov 2022 19:34:53 +0100 Subject: [PATCH 1/5] Make isAlive() threadsafe for all session types --- .../jdk/internal/foreign/ConfinedSession.java | 53 -------------- .../internal/foreign/MemorySessionImpl.java | 70 +++++++++++++++---- .../jdk/internal/foreign/SharedSession.java | 43 ------------ 3 files changed, 56 insertions(+), 110 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/foreign/ConfinedSession.java b/src/java.base/share/classes/jdk/internal/foreign/ConfinedSession.java index 4961cecde5e1c..018f744c20ae6 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/ConfinedSession.java +++ b/src/java.base/share/classes/jdk/internal/foreign/ConfinedSession.java @@ -25,12 +25,6 @@ package jdk.internal.foreign; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.VarHandle; -import java.lang.ref.Cleaner; - -import jdk.internal.vm.annotation.ForceInline; - /** * A confined session, which features an owner thread. The liveness check features an additional * confinement check - that is, calling any operation on this session from a thread other than the @@ -39,57 +33,10 @@ */ final class ConfinedSession extends MemorySessionImpl { - private int asyncReleaseCount = 0; - - static final VarHandle ASYNC_RELEASE_COUNT; - - static { - try { - ASYNC_RELEASE_COUNT = MethodHandles.lookup().findVarHandle(ConfinedSession.class, "asyncReleaseCount", int.class); - } catch (Throwable ex) { - throw new ExceptionInInitializerError(ex); - } - } - public ConfinedSession(Thread owner) { super(owner, new ConfinedResourceList()); } - @Override - @ForceInline - public void acquire0() { - checkValidState(); - if (state == MAX_FORKS) { - throw tooManyAcquires(); - } - state++; - } - - @Override - @ForceInline - public void release0() { - if (Thread.currentThread() == owner) { - state--; - } else { - // It is possible to end up here in two cases: this session was kept alive by some other confined session - // which is implicitly released (in which case the release call comes from the cleaner thread). Or, - // this session might be kept alive by a shared session, which means the release call can come from any - // thread. - ASYNC_RELEASE_COUNT.getAndAdd(this, 1); - } - } - - void justClose() { - checkValidState(); - int asyncCount = (int)ASYNC_RELEASE_COUNT.getVolatile(this); - if ((state == 0 && asyncCount == 0) - || ((state - asyncCount) == 0)) { - state = CLOSED; - } else { - throw alreadyAcquired(state - asyncCount); - } - } - /** * A confined resource list; no races are possible here. */ diff --git a/src/java.base/share/classes/jdk/internal/foreign/MemorySessionImpl.java b/src/java.base/share/classes/jdk/internal/foreign/MemorySessionImpl.java index 745a07f538551..1e269fe281d96 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/MemorySessionImpl.java +++ b/src/java.base/share/classes/jdk/internal/foreign/MemorySessionImpl.java @@ -36,6 +36,8 @@ import jdk.internal.misc.ScopedMemoryAccess; import jdk.internal.vm.annotation.ForceInline; +import static jdk.internal.foreign.MappedMemorySegmentImpl.SCOPED_MEMORY_ACCESS; + /** * This class manages the temporal bounds associated with a memory segment as well * as thread confinement. A session has a liveness bit, which is updated when the session is closed @@ -76,7 +78,7 @@ public abstract sealed class MemorySessionImpl } } - public void addCloseAction(Runnable runnable) { + public final void addCloseAction(Runnable runnable) { Objects.requireNonNull(runnable); addInternal(ResourceList.ResourceCleanup.ofRunnable(runnable)); } @@ -91,7 +93,7 @@ public void addCloseAction(Runnable runnable) { * new segment to the client). For this reason, it's not worth adding extra complexity to the segment * initialization logic here - and using an optimistic logic works well in practice. */ - public void addOrCleanupIfFail(ResourceList.ResourceCleanup resource) { + public final void addOrCleanupIfFail(ResourceList.ResourceCleanup resource) { try { addInternal(resource); } catch (Throwable ex) { @@ -129,17 +131,40 @@ public static MemorySessionImpl createImplicit(Cleaner cleaner) { } @Override - public MemorySegment allocate(long byteSize, long byteAlignment) { + public final MemorySegment allocate(long byteSize, long byteAlignment) { Utils.checkAllocationSizeAndAlign(byteSize, byteAlignment); return NativeMemorySegmentImpl.makeNativeSegment(byteSize, byteAlignment, this); } - public abstract void release0(); + @ForceInline + public void release0() { + int value; + do { + value = (int)STATE.getVolatile(this); + if (value <= OPEN) { + //cannot get here - we can't close segment twice + throw alreadyClosed(); + } + } while (!STATE.compareAndSet(this, value, value - 1)); + } - public abstract void acquire0(); + @ForceInline + public void acquire0() { + int value; + do { + value = (int)STATE.getVolatile(this); + if (value < OPEN) { + //segment is not open! + throw alreadyClosed(); + } else if (value == MAX_FORKS) { + //overflow + throw tooManyAcquires(); + } + } while (!STATE.compareAndSet(this, value, value + 1)); + } @Override - public void whileAlive(Runnable action) { + public final void whileAlive(Runnable action) { Objects.requireNonNull(action); acquire0(); try { @@ -168,8 +193,9 @@ public final boolean isAccessibleBy(Thread thread) { * Returns true, if this session is still open. This method may be called in any thread. * @return {@code true} if this session is not closed yet. */ - public boolean isAlive() { - return state >= OPEN; + @Override + public final boolean isAlive() { + return state() >= OPEN; } /** @@ -181,11 +207,11 @@ public boolean isAlive() { * please use {@link #checkValidState()}. */ @ForceInline - public void checkValidStateRaw() { + public final void checkValidStateRaw() { if (owner != null && owner != Thread.currentThread()) { throw WRONG_THREAD; } - if (state < OPEN) { + if (!isAlive()) { throw ALREADY_CLOSED; } } @@ -195,7 +221,7 @@ public void checkValidStateRaw() { * @throws IllegalStateException if this session is already closed or if this is * a confined session and this method is called outside of the owner thread. */ - public void checkValidState() { + public final void checkValidState() { try { checkValidStateRaw(); } catch (ScopedMemoryAccess.ScopedAccessError error) { @@ -204,7 +230,7 @@ public void checkValidState() { } @Override - protected Object clone() throws CloneNotSupportedException { + protected final Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException(); } @@ -217,12 +243,28 @@ public boolean isCloseable() { * @throws IllegalStateException if this session is already closed or if this is * a confined session and this method is called outside of the owner thread. */ - public void close() { + public final void close() { justClose(); resourceList.cleanup(); } - abstract void justClose(); + void justClose() { + int prevState = (int) STATE.compareAndExchange(this, OPEN, CLOSING); + if (prevState < 0) { + throw alreadyClosed(); + } else if (prevState != OPEN) { + throw alreadyAcquired(prevState); + } + boolean success = SCOPED_MEMORY_ACCESS.closeScope(this); + STATE.setVolatile(this, success ? CLOSED : OPEN); + if (!success) { + throw alreadyAcquired(1); + } + } + + private int state() { + return (int)STATE.get(this); + } public static MemorySessionImpl heapSession(Object ref) { return new GlobalSession(ref); diff --git a/src/java.base/share/classes/jdk/internal/foreign/SharedSession.java b/src/java.base/share/classes/jdk/internal/foreign/SharedSession.java index 984d9d9992161..4174627868bbf 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/SharedSession.java +++ b/src/java.base/share/classes/jdk/internal/foreign/SharedSession.java @@ -48,49 +48,6 @@ sealed class SharedSession extends MemorySessionImpl permits ImplicitSession { super(null, new SharedResourceList()); } - @Override - @ForceInline - public void acquire0() { - int value; - do { - value = (int) STATE.getVolatile(this); - if (value < OPEN) { - //segment is not open! - throw alreadyClosed(); - } else if (value == MAX_FORKS) { - //overflow - throw tooManyAcquires(); - } - } while (!STATE.compareAndSet(this, value, value + 1)); - } - - @Override - @ForceInline - public void release0() { - int value; - do { - value = (int) STATE.getVolatile(this); - if (value <= OPEN) { - //cannot get here - we can't close segment twice - throw alreadyClosed(); - } - } while (!STATE.compareAndSet(this, value, value - 1)); - } - - void justClose() { - int prevState = (int) STATE.compareAndExchange(this, OPEN, CLOSING); - if (prevState < 0) { - throw alreadyClosed(); - } else if (prevState != OPEN) { - throw alreadyAcquired(prevState); - } - boolean success = SCOPED_MEMORY_ACCESS.closeScope(this); - STATE.setVolatile(this, success ? CLOSED : OPEN); - if (!success) { - throw alreadyAcquired(1); - } - } - /** * A shared resource list; this implementation has to handle add vs. add races, as well as add vs. cleanup races. */ From c39eadd85a959f645dd44f020e246ae14e3f6f70 Mon Sep 17 00:00:00 2001 From: Per Minborg Date: Thu, 10 Nov 2022 12:23:34 +0100 Subject: [PATCH 2/5] Add thread guarding --- .../jdk/internal/foreign/ConfinedSession.java | 17 +++++++++++++++++ .../jdk/internal/foreign/MemorySessionImpl.java | 6 ++++++ test/jdk/java/foreign/TestMemorySession.java | 8 ++++++++ 3 files changed, 31 insertions(+) diff --git a/src/java.base/share/classes/jdk/internal/foreign/ConfinedSession.java b/src/java.base/share/classes/jdk/internal/foreign/ConfinedSession.java index 018f744c20ae6..532151cfcbca3 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/ConfinedSession.java +++ b/src/java.base/share/classes/jdk/internal/foreign/ConfinedSession.java @@ -37,6 +37,23 @@ public ConfinedSession(Thread owner) { super(owner, new ConfinedResourceList()); } + @Override + public void acquire0() { + assertIsAccessibleByCurrentThread(); + super.acquire0(); + } + + // It is possible to that release0 is called by another thread: this session was kept alive by some other confined session + // which is implicitly released (in which case the release call comes from the cleaner thread). Or, + // this session might be kept alive by a shared session, which means the release call can come from any + // thread. Hence, release0() is not checked for thread usage + + @Override + void justClose() { + assertIsAccessibleByCurrentThread(); + super.justClose(); + } + /** * A confined resource list; no races are possible here. */ diff --git a/src/java.base/share/classes/jdk/internal/foreign/MemorySessionImpl.java b/src/java.base/share/classes/jdk/internal/foreign/MemorySessionImpl.java index 1e269fe281d96..a44552634c33c 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/MemorySessionImpl.java +++ b/src/java.base/share/classes/jdk/internal/foreign/MemorySessionImpl.java @@ -216,6 +216,12 @@ public final void checkValidStateRaw() { } } + void assertIsAccessibleByCurrentThread() { + if (owner != null && owner != Thread.currentThread()) { + throw wrongThread(); + } + } + /** * Checks that this session is still alive (see {@link #isAlive()}). * @throws IllegalStateException if this session is already closed or if this is diff --git a/test/jdk/java/foreign/TestMemorySession.java b/test/jdk/java/foreign/TestMemorySession.java index 266d904a19259..65f09142a316b 100644 --- a/test/jdk/java/foreign/TestMemorySession.java +++ b/test/jdk/java/foreign/TestMemorySession.java @@ -201,6 +201,14 @@ public void testCloseEmptySharedSession() { Arena.openShared().close(); } + @Test + public void testCloseConfinedLockInSameThread() { + Arena arena = Arena.openConfined(); + Arena handle = Arena.openConfined(); + keepAlive(handle.session(), arena.session()); + handle.close(); + } + @Test public void testCloseConfinedLock() { Arena arena = Arena.openConfined(); From 72b83fd93ae9d104bb985f3f9a6eb1ac3d647f00 Mon Sep 17 00:00:00 2001 From: Per Minborg Date: Thu, 10 Nov 2022 13:41:42 +0100 Subject: [PATCH 3/5] Add thread test --- test/jdk/java/foreign/TestMemorySession.java | 79 +++++++++++++++----- 1 file changed, 59 insertions(+), 20 deletions(-) diff --git a/test/jdk/java/foreign/TestMemorySession.java b/test/jdk/java/foreign/TestMemorySession.java index 65f09142a316b..b8c666cefa468 100644 --- a/test/jdk/java/foreign/TestMemorySession.java +++ b/test/jdk/java/foreign/TestMemorySession.java @@ -35,10 +35,15 @@ import jdk.internal.foreign.MemorySessionImpl; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; + import static org.testng.Assert.*; +import java.lang.management.MemoryPoolMXBean; +import java.time.Duration; +import java.time.Instant; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; @@ -52,7 +57,7 @@ public class TestMemorySession { public void testConfined() { AtomicInteger acc = new AtomicInteger(); Arena arena = Arena.openConfined(); - for (int i = 0 ; i < N_THREADS ; i++) { + for (int i = 0; i < N_THREADS; i++) { int delta = i; addCloseAction(arena.session(), () -> acc.addAndGet(delta)); } @@ -66,7 +71,7 @@ public void testConfined() { public void testSharedSingleThread(SessionSupplier sessionSupplier) { AtomicInteger acc = new AtomicInteger(); MemorySession session = sessionSupplier.get(); - for (int i = 0 ; i < N_THREADS ; i++) { + for (int i = 0; i < N_THREADS; i++) { int delta = i; addCloseAction(session, () -> acc.addAndGet(delta)); } @@ -90,7 +95,7 @@ public void testSharedMultiThread(SessionSupplier sessionSupplier) { List threads = new ArrayList<>(); MemorySession session = sessionSupplier.get(); AtomicReference sessionRef = new AtomicReference<>(session); - for (int i = 0 ; i < N_THREADS ; i++) { + for (int i = 0; i < N_THREADS; i++) { int delta = i; Thread thread = new Thread(() -> { try { @@ -144,7 +149,7 @@ public void testSharedMultiThread(SessionSupplier sessionSupplier) { public void testLockSingleThread() { Arena arena = Arena.openConfined(); List handles = new ArrayList<>(); - for (int i = 0 ; i < N_THREADS ; i++) { + for (int i = 0; i < N_THREADS; i++) { Arena handle = Arena.openConfined(); keepAlive(handle.session(), arena.session()); handles.add(handle); @@ -167,7 +172,7 @@ public void testLockSingleThread() { public void testLockSharedMultiThread() { Arena arena = Arena.openShared(); AtomicInteger lockCount = new AtomicInteger(); - for (int i = 0 ; i < N_THREADS ; i++) { + for (int i = 0; i < N_THREADS; i++) { new Thread(() -> { try (Arena handle = Arena.openConfined()) { keepAlive(handle.session(), arena.session()); @@ -269,7 +274,7 @@ public void testConfinedSessionWithImplicitDependency() { break; // success! } catch (IllegalStateException ex) { kickGC(); - for (int i = 0 ; i < N_THREADS ; i++) { // add more races from current thread + for (int i = 0; i < N_THREADS; i++) { // add more races from current thread try (Arena arena = Arena.openConfined()) { keepAlive(arena.session(), root.session()); // dummy @@ -292,7 +297,7 @@ public void testConfinedSessionWithSharedDependency() { threads.add(t); t.start(); } - for (int i = 0 ; i < N_THREADS ; i++) { // add more races from current thread + for (int i = 0; i < N_THREADS; i++) { // add more races from current thread try (Arena arena = Arena.openConfined()) { keepAlive(arena.session(), root.session()); // dummy @@ -310,6 +315,40 @@ public void testConfinedSessionWithSharedDependency() { root.close(); } + + // This tests that close operations are visible to other threads even though the original + // session is confined as per the .isAlive() contract. + @Test + public void testConfinedSessionIsAliveObservableFromAnotherThread() throws InterruptedException { + var begin = Instant.now(); + for (int i = 0; i < 1_000; i++) { + var latch = new CountDownLatch(2); + Thread otherThread; + try (var arena = Arena.openConfined()) { + otherThread = new Thread(() -> { + MemorySession session = arena.session(); + assertTrue(session.isAlive()); + latch.countDown(); + try { + latch.await(); + } catch (InterruptedException e) { + throw new AssertionError(e); + } + boolean alive = session.isAlive(); + assertFalse(alive); + }); + otherThread.start(); + while (latch.getCount() == 2) { + Thread.onSpinWait(); + } + } // <- arena.close() invoked here + latch.countDown(); + otherThread.join(); + } + var end = Instant.now(); + System.out.println("Completed in " + Duration.between(begin, end)); + } + private void waitSomeTime() { try { Thread.sleep(10); @@ -319,7 +358,7 @@ private void waitSomeTime() { } private void kickGC() { - for (int i = 0 ; i < 100 ; i++) { + for (int i = 0; i < 100; i++) { byte[] b = new byte[100]; System.gc(); Thread.onSpinWait(); @@ -328,9 +367,9 @@ private void kickGC() { @DataProvider static Object[][] drops() { - return new Object[][] { - { (Supplier) Arena::openConfined}, - { (Supplier) Arena::openShared}, + return new Object[][]{ + {(Supplier) Arena::openConfined}, + {(Supplier) Arena::openShared}, }; } @@ -348,11 +387,11 @@ private void addCloseAction(MemorySession session, Runnable action) { interface SessionSupplier extends Supplier { static void close(MemorySession session) { - ((MemorySessionImpl)session).close(); + ((MemorySessionImpl) session).close(); } static boolean isImplicit(MemorySession session) { - return !((MemorySessionImpl)session).isCloseable(); + return !((MemorySessionImpl) session).isCloseable(); } static SessionSupplier ofImplicit() { @@ -366,18 +405,18 @@ static SessionSupplier ofArena(Supplier arenaSupplier) { @DataProvider(name = "sharedSessions") static Object[][] sharedSessions() { - return new Object[][] { - { SessionSupplier.ofArena(Arena::openShared) }, - { SessionSupplier.ofImplicit() }, + return new Object[][]{ + {SessionSupplier.ofArena(Arena::openShared)}, + {SessionSupplier.ofImplicit()}, }; } @DataProvider(name = "allSessions") static Object[][] allSessions() { - return new Object[][] { - { SessionSupplier.ofArena(Arena::openConfined) }, - { SessionSupplier.ofArena(Arena::openShared) }, - { SessionSupplier.ofImplicit() }, + return new Object[][]{ + {SessionSupplier.ofArena(Arena::openConfined)}, + {SessionSupplier.ofArena(Arena::openShared)}, + {SessionSupplier.ofImplicit()}, }; } } From c3de7777dc967e1e758fb7cd621746b752d9b72b Mon Sep 17 00:00:00 2001 From: Per Minborg Date: Thu, 10 Nov 2022 16:17:32 +0100 Subject: [PATCH 4/5] Undo reformatting --- test/jdk/java/foreign/TestMemorySession.java | 40 ++++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/test/jdk/java/foreign/TestMemorySession.java b/test/jdk/java/foreign/TestMemorySession.java index b8c666cefa468..5c237c54d6c0c 100644 --- a/test/jdk/java/foreign/TestMemorySession.java +++ b/test/jdk/java/foreign/TestMemorySession.java @@ -57,7 +57,7 @@ public class TestMemorySession { public void testConfined() { AtomicInteger acc = new AtomicInteger(); Arena arena = Arena.openConfined(); - for (int i = 0; i < N_THREADS; i++) { + for (int i = 0 ; i < N_THREADS ; i++) { int delta = i; addCloseAction(arena.session(), () -> acc.addAndGet(delta)); } @@ -71,7 +71,7 @@ public void testConfined() { public void testSharedSingleThread(SessionSupplier sessionSupplier) { AtomicInteger acc = new AtomicInteger(); MemorySession session = sessionSupplier.get(); - for (int i = 0; i < N_THREADS; i++) { + for (int i = 0 ; i < N_THREADS ; i++) { int delta = i; addCloseAction(session, () -> acc.addAndGet(delta)); } @@ -95,7 +95,7 @@ public void testSharedMultiThread(SessionSupplier sessionSupplier) { List threads = new ArrayList<>(); MemorySession session = sessionSupplier.get(); AtomicReference sessionRef = new AtomicReference<>(session); - for (int i = 0; i < N_THREADS; i++) { + for (int i = 0 ; i < N_THREADS ; i++) { int delta = i; Thread thread = new Thread(() -> { try { @@ -149,7 +149,7 @@ public void testSharedMultiThread(SessionSupplier sessionSupplier) { public void testLockSingleThread() { Arena arena = Arena.openConfined(); List handles = new ArrayList<>(); - for (int i = 0; i < N_THREADS; i++) { + for (int i = 0 ; i < N_THREADS ; i++) { Arena handle = Arena.openConfined(); keepAlive(handle.session(), arena.session()); handles.add(handle); @@ -172,7 +172,7 @@ public void testLockSingleThread() { public void testLockSharedMultiThread() { Arena arena = Arena.openShared(); AtomicInteger lockCount = new AtomicInteger(); - for (int i = 0; i < N_THREADS; i++) { + for (int i = 0 ; i < N_THREADS ; i++) { new Thread(() -> { try (Arena handle = Arena.openConfined()) { keepAlive(handle.session(), arena.session()); @@ -262,7 +262,7 @@ private void acquireRecursive(MemorySession session, int acquireCount) { public void testConfinedSessionWithImplicitDependency() { Arena root = Arena.openConfined(); // Create many implicit sessions which depend on 'root', and let them become unreachable. - for (int i = 0; i < N_THREADS; i++) { + for (int i = 0 ; i < N_THREADS ; i++) { keepAlive(MemorySession.implicit(), root.session()); } // Now let's keep trying to close 'root' until we succeed. This is trickier than it seems: cleanup action @@ -290,7 +290,7 @@ public void testConfinedSessionWithSharedDependency() { Arena root = Arena.openConfined(); List threads = new ArrayList<>(); // Create many implicit sessions which depend on 'root', and let them become unreachable. - for (int i = 0; i < N_THREADS; i++) { + for (int i = 0 ; i < N_THREADS ; i++) { Arena arena = Arena.openShared(); // create session inside same thread! keepAlive(arena.session(), root.session()); Thread t = new Thread(arena::close); // close from another thread! @@ -358,7 +358,7 @@ private void waitSomeTime() { } private void kickGC() { - for (int i = 0; i < 100; i++) { + for (int i = 0 ; i < 100 ; i++) { byte[] b = new byte[100]; System.gc(); Thread.onSpinWait(); @@ -367,9 +367,9 @@ private void kickGC() { @DataProvider static Object[][] drops() { - return new Object[][]{ - {(Supplier) Arena::openConfined}, - {(Supplier) Arena::openShared}, + return new Object[][] { + { (Supplier) Arena::openConfined}, + { (Supplier) Arena::openShared}, }; } @@ -387,11 +387,11 @@ private void addCloseAction(MemorySession session, Runnable action) { interface SessionSupplier extends Supplier { static void close(MemorySession session) { - ((MemorySessionImpl) session).close(); + ((MemorySessionImpl)session).close(); } static boolean isImplicit(MemorySession session) { - return !((MemorySessionImpl) session).isCloseable(); + return !((MemorySessionImpl)session).isCloseable(); } static SessionSupplier ofImplicit() { @@ -405,18 +405,18 @@ static SessionSupplier ofArena(Supplier arenaSupplier) { @DataProvider(name = "sharedSessions") static Object[][] sharedSessions() { - return new Object[][]{ - {SessionSupplier.ofArena(Arena::openShared)}, - {SessionSupplier.ofImplicit()}, + return new Object[][] { + { SessionSupplier.ofArena(Arena::openShared) }, + { SessionSupplier.ofImplicit() }, }; } @DataProvider(name = "allSessions") static Object[][] allSessions() { - return new Object[][]{ - {SessionSupplier.ofArena(Arena::openConfined)}, - {SessionSupplier.ofArena(Arena::openShared)}, - {SessionSupplier.ofImplicit()}, + return new Object[][] { + { SessionSupplier.ofArena(Arena::openConfined) }, + { SessionSupplier.ofArena(Arena::openShared) }, + { SessionSupplier.ofImplicit() }, }; } } From 40f62126421adef4e13f0f72874f180cb3728112 Mon Sep 17 00:00:00 2001 From: Per Minborg Date: Thu, 10 Nov 2022 16:21:48 +0100 Subject: [PATCH 5/5] Undo more reformatting --- test/jdk/java/foreign/TestMemorySession.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/jdk/java/foreign/TestMemorySession.java b/test/jdk/java/foreign/TestMemorySession.java index 5c237c54d6c0c..09b19c20a85bc 100644 --- a/test/jdk/java/foreign/TestMemorySession.java +++ b/test/jdk/java/foreign/TestMemorySession.java @@ -262,7 +262,7 @@ private void acquireRecursive(MemorySession session, int acquireCount) { public void testConfinedSessionWithImplicitDependency() { Arena root = Arena.openConfined(); // Create many implicit sessions which depend on 'root', and let them become unreachable. - for (int i = 0 ; i < N_THREADS ; i++) { + for (int i = 0; i < N_THREADS; i++) { keepAlive(MemorySession.implicit(), root.session()); } // Now let's keep trying to close 'root' until we succeed. This is trickier than it seems: cleanup action @@ -274,7 +274,7 @@ public void testConfinedSessionWithImplicitDependency() { break; // success! } catch (IllegalStateException ex) { kickGC(); - for (int i = 0; i < N_THREADS; i++) { // add more races from current thread + for (int i = 0 ; i < N_THREADS ; i++) { // add more races from current thread try (Arena arena = Arena.openConfined()) { keepAlive(arena.session(), root.session()); // dummy @@ -290,14 +290,14 @@ public void testConfinedSessionWithSharedDependency() { Arena root = Arena.openConfined(); List threads = new ArrayList<>(); // Create many implicit sessions which depend on 'root', and let them become unreachable. - for (int i = 0 ; i < N_THREADS ; i++) { + for (int i = 0; i < N_THREADS; i++) { Arena arena = Arena.openShared(); // create session inside same thread! keepAlive(arena.session(), root.session()); Thread t = new Thread(arena::close); // close from another thread! threads.add(t); t.start(); } - for (int i = 0; i < N_THREADS; i++) { // add more races from current thread + for (int i = 0 ; i < N_THREADS ; i++) { // add more races from current thread try (Arena arena = Arena.openConfined()) { keepAlive(arena.session(), root.session()); // dummy