< prev index next >

test/jdk/java/lang/ScopedValue/StressStackOverflow.java

Print this page

 35  */
 36 
 37 /*
 38  * @test id=TieredStopAtLevel1
 39  * @enablePreview
 40  * @run main/othervm/timeout=300 -XX:TieredStopAtLevel=1 StressStackOverflow
 41  */
 42 
 43 /*
 44  * @test id=no-vmcontinuations
 45  * @requires vm.continuations
 46  * @enablePreview
 47  * @run main/othervm/timeout=300 -XX:+UnlockExperimentalVMOptions -XX:-VMContinuations StressStackOverflow
 48  */
 49 
 50 import java.lang.ScopedValue.CallableOp;
 51 import java.time.Duration;
 52 import java.util.concurrent.ThreadLocalRandom;
 53 import java.util.concurrent.StructureViolationException;
 54 import java.util.concurrent.StructuredTaskScope;

 55 import java.util.function.Supplier;
 56 
 57 public class StressStackOverflow {
 58     public static final ScopedValue<Integer> el = ScopedValue.newInstance();
 59 
 60     public static final ScopedValue<Integer> inheritedValue = ScopedValue.newInstance();
 61 
 62     static final TestFailureException testFailureException = new TestFailureException("Unexpected value for ScopedValue");
 63     int ITERS = 1_000_000;
 64 
 65     static class TestFailureException extends RuntimeException {
 66         TestFailureException(String s) { super(s); }
 67     }
 68 
 69     static final long DURATION_IN_NANOS = Duration.ofMinutes(1).toNanos();
 70 
 71     // Test the ScopedValue recovery mechanism for stack overflows. We implement both CallableOp
 72     // and Runnable interfaces. Which one gets tested depends on the constructor argument.
 73     class DeepRecursion implements CallableOp<Object, RuntimeException>, Supplier<Object>, Runnable {
 74 

152 
153     long fibonacci_pad(int n, Runnable op) {
154         final var last = el.get();
155         try {
156             return fibonacci_pad1(ThreadLocalRandom.current().nextInt(n), op);
157         } catch (StackOverflowError err) {
158             if (!inheritedValue.get().equals(I_42)) {
159                 throw testFailureException;
160             }
161             if (!last.equals(el.get())) {
162                 throw testFailureException;
163             }
164             throw err;
165         }
166     }
167 
168     // Run op in a new thread. Platform or virtual threads are chosen at random.
169     void runInNewThread(Runnable op) {
170         var threadFactory
171                 = (ThreadLocalRandom.current().nextBoolean() ? Thread.ofPlatform() : Thread.ofVirtual()).factory();
172         try (var scope = new StructuredTaskScope<>("", threadFactory)) {
173             var handle = scope.fork(() -> {
174                 op.run();
175                 return null;
176             });
177             scope.join();
178             handle.get();
179         } catch (TestFailureException e) {
180             throw e;
181         } catch (Exception e) {
182             throw new RuntimeException(e);
183         }
184     }
185 
186     public void run() {
187         try {
188             ScopedValue.where(inheritedValue, 42).where(el, 0).run(() -> {
189                 try (var scope = new StructuredTaskScope<>()) {
190                     try {
191                         if (ThreadLocalRandom.current().nextBoolean()) {
192                             // Repeatedly test Scoped Values set by ScopedValue::call(), get(), and run()
193                             final var deepRecursion
194                                 = new DeepRecursion(DeepRecursion.Behaviour.choose(ThreadLocalRandom.current()));
195                             deepRecursion.run();
196                         } else {
197                             // Recursively run ourself until we get a stack overflow
198                             // Catch the overflow and make sure the recovery path works
199                             // for values inherited from a StructuredTaskScope.
200                             Runnable op = new Runnable() {
201                                 public void run() {
202                                     try {
203                                         fibonacci_pad(20, this);
204                                     } catch (StackOverflowError e) {
205                                     } catch (TestFailureException e) {
206                                         throw e;
207                                     } catch (Throwable throwable) {
208                                         // StackOverflowErrors cause many different failures. These include
209                                         // StructureViolationExceptions and InvocationTargetExceptions. This test

 35  */
 36 
 37 /*
 38  * @test id=TieredStopAtLevel1
 39  * @enablePreview
 40  * @run main/othervm/timeout=300 -XX:TieredStopAtLevel=1 StressStackOverflow
 41  */
 42 
 43 /*
 44  * @test id=no-vmcontinuations
 45  * @requires vm.continuations
 46  * @enablePreview
 47  * @run main/othervm/timeout=300 -XX:+UnlockExperimentalVMOptions -XX:-VMContinuations StressStackOverflow
 48  */
 49 
 50 import java.lang.ScopedValue.CallableOp;
 51 import java.time.Duration;
 52 import java.util.concurrent.ThreadLocalRandom;
 53 import java.util.concurrent.StructureViolationException;
 54 import java.util.concurrent.StructuredTaskScope;
 55 import java.util.concurrent.StructuredTaskScope.Joiner;
 56 import java.util.function.Supplier;
 57 
 58 public class StressStackOverflow {
 59     public static final ScopedValue<Integer> el = ScopedValue.newInstance();
 60 
 61     public static final ScopedValue<Integer> inheritedValue = ScopedValue.newInstance();
 62 
 63     static final TestFailureException testFailureException = new TestFailureException("Unexpected value for ScopedValue");
 64     int ITERS = 1_000_000;
 65 
 66     static class TestFailureException extends RuntimeException {
 67         TestFailureException(String s) { super(s); }
 68     }
 69 
 70     static final long DURATION_IN_NANOS = Duration.ofMinutes(1).toNanos();
 71 
 72     // Test the ScopedValue recovery mechanism for stack overflows. We implement both CallableOp
 73     // and Runnable interfaces. Which one gets tested depends on the constructor argument.
 74     class DeepRecursion implements CallableOp<Object, RuntimeException>, Supplier<Object>, Runnable {
 75 

153 
154     long fibonacci_pad(int n, Runnable op) {
155         final var last = el.get();
156         try {
157             return fibonacci_pad1(ThreadLocalRandom.current().nextInt(n), op);
158         } catch (StackOverflowError err) {
159             if (!inheritedValue.get().equals(I_42)) {
160                 throw testFailureException;
161             }
162             if (!last.equals(el.get())) {
163                 throw testFailureException;
164             }
165             throw err;
166         }
167     }
168 
169     // Run op in a new thread. Platform or virtual threads are chosen at random.
170     void runInNewThread(Runnable op) {
171         var threadFactory
172                 = (ThreadLocalRandom.current().nextBoolean() ? Thread.ofPlatform() : Thread.ofVirtual()).factory();
173         try (var scope = StructuredTaskScope.open(Joiner.awaitAll(), cf -> cf.withThreadFactory(threadFactory))) {
174             var handle = scope.fork(() -> {
175                 op.run();
176                 return null;
177             });
178             scope.join();
179             handle.get();
180         } catch (TestFailureException e) {
181             throw e;
182         } catch (Exception e) {
183             throw new RuntimeException(e);
184         }
185     }
186 
187     public void run() {
188         try {
189             ScopedValue.where(inheritedValue, 42).where(el, 0).run(() -> {
190                 try (var scope = StructuredTaskScope.open(Joiner.awaitAll())) {
191                     try {
192                         if (ThreadLocalRandom.current().nextBoolean()) {
193                             // Repeatedly test Scoped Values set by ScopedValue::call(), get(), and run()
194                             final var deepRecursion
195                                 = new DeepRecursion(DeepRecursion.Behaviour.choose(ThreadLocalRandom.current()));
196                             deepRecursion.run();
197                         } else {
198                             // Recursively run ourself until we get a stack overflow
199                             // Catch the overflow and make sure the recovery path works
200                             // for values inherited from a StructuredTaskScope.
201                             Runnable op = new Runnable() {
202                                 public void run() {
203                                     try {
204                                         fibonacci_pad(20, this);
205                                     } catch (StackOverflowError e) {
206                                     } catch (TestFailureException e) {
207                                         throw e;
208                                     } catch (Throwable throwable) {
209                                         // StackOverflowErrors cause many different failures. These include
210                                         // StructureViolationExceptions and InvocationTargetExceptions. This test
< prev index next >