< prev index next > test/jdk/java/lang/ScopedValue/StressStackOverflow.java
Print this page
*/
/**
* @test
* @summary StressStackOverflow the recovery path for ScopedValue
! * @modules jdk.incubator.concurrent
- * @compile StressStackOverflow.java
* @run main/othervm/timeout=300 -XX:-TieredCompilation StressStackOverflow
* @run main/othervm/timeout=300 -XX:TieredStopAtLevel=1 StressStackOverflow
* @run main/othervm/timeout=300 StressStackOverflow
*/
import java.util.concurrent.Callable;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadLocalRandom;
! import jdk.incubator.concurrent.ScopedValue;
! import jdk.incubator.concurrent.StructureViolationException;
! import jdk.incubator.concurrent.StructuredTaskScope;
public class StressStackOverflow {
public static final ScopedValue<Integer> el = ScopedValue.newInstance();
public static final ScopedValue<Integer> inheritedValue = ScopedValue.newInstance();
*/
/**
* @test
* @summary StressStackOverflow the recovery path for ScopedValue
! * @enablePreview
* @run main/othervm/timeout=300 -XX:-TieredCompilation StressStackOverflow
* @run main/othervm/timeout=300 -XX:TieredStopAtLevel=1 StressStackOverflow
* @run main/othervm/timeout=300 StressStackOverflow
*/
import java.util.concurrent.Callable;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadLocalRandom;
! import java.util.concurrent.StructureViolationException;
! import java.util.concurrent.StructuredTaskScope;
! import java.util.function.Supplier;
public class StressStackOverflow {
public static final ScopedValue<Integer> el = ScopedValue.newInstance();
public static final ScopedValue<Integer> inheritedValue = ScopedValue.newInstance();
TestFailureException(String s) { super(s); }
}
// Test the ScopedValue recovery mechanism for stack overflows. We implement both Callable
// and Runnable interfaces. Which one gets tested depends on the constructor argument.
! class DeepRecursion implements Callable, Runnable {
- static enum Behaviour {CALL, RUN}
final Behaviour behaviour;
public DeepRecursion(Behaviour behaviour) {
this.behaviour = behaviour;
}
TestFailureException(String s) { super(s); }
}
// Test the ScopedValue recovery mechanism for stack overflows. We implement both Callable
// and Runnable interfaces. Which one gets tested depends on the constructor argument.
! class DeepRecursion implements Callable, Supplier, Runnable {
+
+ static enum Behaviour {
+ CALL, GET, RUN;
+ private static Behaviour[] values = values();
+ public static Behaviour choose(ThreadLocalRandom tlr) {
+ return values[tlr.nextInt(3)];
+ }
+ }
final Behaviour behaviour;
public DeepRecursion(Behaviour behaviour) {
this.behaviour = behaviour;
}
var nextRandomFloat = tlr.nextFloat();
try {
switch (behaviour) {
case CALL ->
ScopedValue.where(el, el.get() + 1).call(() -> fibonacci_pad(20, this));
+ case GET ->
+ ScopedValue.where(el, el.get() + 1).get(() -> fibonacci_pad(20, this));
case RUN ->
ScopedValue.where(el, el.get() + 1).run(() -> fibonacci_pad(20, this));
}
if (!last.equals(el.get())) {
throw testFailureException;
}
Thread.yield();
}
! public Object call() {
run();
return null;
}
}
static final Runnable nop = new Runnable() {
public void run() { }
};
}
Thread.yield();
}
! public Object get() {
run();
return null;
}
+
+ public Object call() {
+ return get();
+ }
}
static final Runnable nop = new Runnable() {
public void run() { }
};
// Run op in a new thread. Platform or virtual threads are chosen at random.
void runInNewThread(Runnable op) {
var threadFactory
= (tlr.nextBoolean() ? Thread.ofPlatform() : Thread.ofVirtual()).factory();
try (var scope = new StructuredTaskScope<Object>("", threadFactory)) {
! var future = scope.fork(() -> {
op.run();
return null;
});
- future.get();
scope.join();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
// Run op in a new thread. Platform or virtual threads are chosen at random.
void runInNewThread(Runnable op) {
var threadFactory
= (tlr.nextBoolean() ? Thread.ofPlatform() : Thread.ofVirtual()).factory();
try (var scope = new StructuredTaskScope<Object>("", threadFactory)) {
! var handle = scope.fork(() -> {
op.run();
return null;
});
scope.join();
+ handle.get();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
try {
ScopedValue.where(inheritedValue, 42).where(el, 0).run(() -> {
try (var scope = new StructuredTaskScope<Object>()) {
try {
if (tlr.nextBoolean()) {
! // Repeatedly test Scoped Values set by ScopedValue::call() and ScopedValue::run()
final var deepRecursion
! = new DeepRecursion(tlr.nextBoolean() ? DeepRecursion.Behaviour.CALL : DeepRecursion.Behaviour.RUN);
deepRecursion.run();
} else {
// Recursively run ourself until we get a stack overflow
// Catch the overflow and make sure the recovery path works
// for values inherited from a StructuredTaskScope.
try {
ScopedValue.where(inheritedValue, 42).where(el, 0).run(() -> {
try (var scope = new StructuredTaskScope<Object>()) {
try {
if (tlr.nextBoolean()) {
! // Repeatedly test Scoped Values set by ScopedValue::call(), get(), and run()
final var deepRecursion
! = new DeepRecursion(DeepRecursion.Behaviour.choose(tlr));
deepRecursion.run();
} else {
// Recursively run ourself until we get a stack overflow
// Catch the overflow and make sure the recovery path works
// for values inherited from a StructuredTaskScope.
< prev index next >