/* * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions.
*/
@Test(dataProvider = "sharedSessions") publicvoid testSharedSingleThread(SessionSupplier sessionSupplier) {
AtomicInteger acc = new AtomicInteger();
SegmentScope session = sessionSupplier.get(); for (int i = 0 ; i < N_THREADS ; i++) { int delta = i;
addCloseAction(session, () -> acc.addAndGet(delta));
}
assertEquals(acc.get(), 0);
if (!SessionSupplier.isImplicit(session)) {
SessionSupplier.close(session);
assertEquals(acc.get(), IntStream.range(0, N_THREADS).sum());
} else {
session = null; int expected = IntStream.range(0, N_THREADS).sum(); while (acc.get() != expected) {
kickGC();
}
}
}
@Test(dataProvider = "sharedSessions") publicvoid testSharedMultiThread(SessionSupplier sessionSupplier) {
AtomicInteger acc = new AtomicInteger();
List<Thread> threads = new ArrayList<>();
SegmentScope session = sessionSupplier.get();
AtomicReference<SegmentScope> sessionRef = new AtomicReference<>(session); for (int i = 0 ; i < N_THREADS ; i++) { int delta = i; Threadthread = newThread(() -> { try {
addCloseAction(sessionRef.get(), () -> {
acc.addAndGet(delta);
});
} catch (IllegalStateException ex) { // already closed - we need to call cleanup manually
acc.addAndGet(delta);
}
});
threads.add(thread);
}
assertEquals(acc.get(), 0);
threads.forEach(Thread::start);
// if no cleaner, close - not all segments might have been added to the session! // if cleaner, don't unset the session - after all, the session is kept alive by threads if (!SessionSupplier.isImplicit(session)) { while (true) { try {
SessionSupplier.close(session); break;
} catch (IllegalStateException ise) { // session is acquired (by add) - wait some more
}
}
}
@Test publicvoid 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++) {
keepAlive(SegmentScope.auto(), root.scope());
} // Now let's keep trying to close 'root' until we succeed. This is trickier than it seems: cleanup action // might be called from another thread (the Cleaner thread), so that the confined session lock count is updated racily. // If that happens, the loop below never terminates. while (true) { try {
root.close(); break; // success!
} catch (IllegalStateException ex) {
kickGC(); for (int i = 0 ; i < N_THREADS ; i++) { // add more races from current thread try (Arena arena = Arena.openConfined()) {
keepAlive(arena.scope(), root.scope()); // dummy
}
} // try again
}
}
}
@Test publicvoid testConfinedSessionWithSharedDependency() {
Arena root = Arena.openConfined();
List<Thread> threads = new ArrayList<>(); // Create many implicit sessions which depend on 'root', and let them become unreachable. for (int i = 0; i < N_THREADS; i++) {
Arena arena = Arena.openShared(); // create session inside same thread!
keepAlive(arena.scope(), root.scope()); Thread t = newThread(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 try (Arena arena = Arena.openConfined()) {
keepAlive(arena.scope(), root.scope()); // dummy
}
}
threads.forEach(t -> { try {
t.join();
} catch (InterruptedException ex) { // ok
}
}); // Now let's close 'root'. This is trickier than it seems: releases of the confined session happen in different // threads, so that the confined session lock count is updated racily. If that happens, the following close will blow up.
root.close();
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.