< prev index next >

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

Print this page
@@ -22,23 +22,22 @@
   */
  
  /**
   * @test
   * @summary StressStackOverflow the recovery path for ScopedValue
-  * @modules jdk.incubator.concurrent
-  * @compile StressStackOverflow.java
+  * @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 jdk.incubator.concurrent.ScopedValue;
- import jdk.incubator.concurrent.StructureViolationException;
- import jdk.incubator.concurrent.StructuredTaskScope;
+ 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();

@@ -51,13 +50,20 @@
          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 {
+     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)];
+             }
+         }
  
-         static enum Behaviour {CALL, RUN}
          final Behaviour behaviour;
  
          public DeepRecursion(Behaviour behaviour) {
              this.behaviour = behaviour;
          }

@@ -68,10 +74,12 @@
              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;

@@ -94,14 +102,18 @@
              }
  
              Thread.yield();
          }
  
-         public Object call() {
+         public Object get() {
              run();
              return null;
          }
+ 
+         public Object call() {
+             return get();
+         }
      }
  
      static final Runnable nop = new Runnable() {
          public void run() { }
      };

@@ -140,16 +152,16 @@
      // 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(() -> {
+             var handle = scope.fork(() -> {
                  op.run();
                  return null;
              });
-             future.get();
              scope.join();
+             handle.get();
          } catch (Exception e) {
              throw new RuntimeException(e);
          }
      }
  

@@ -157,13 +169,13 @@
          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()
+                             // Repeatedly test Scoped Values set by ScopedValue::call(), get(), and run()
                              final var deepRecursion
-                                     = new DeepRecursion(tlr.nextBoolean() ? DeepRecursion.Behaviour.CALL : DeepRecursion.Behaviour.RUN);
+                                 = 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 >