< prev index next >

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

Print this page
*** 22,23 ***
   */
  
  /**
   * @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();
--- 22,22 ---
   */
  
  /**
   * @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();

*** 51,13 ***
          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;
          }
--- 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, 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;
          }

*** 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 ***
              }
  
              Thread.yield();
          }
  
!         public Object call() {
              run();
              return null;
          }
      }
  
      static final Runnable nop = new Runnable() {
          public void run() { }
      };
--- 102,18 ---
              }
  
              Thread.yield();
          }
  
!         public Object get() {
              run();
              return null;
          }
+ 
+         public Object call() {
+             return get();
+         }
      }
  
      static final Runnable nop = new Runnable() {
          public void run() { }
      };

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

*** 157,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()
                              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.
--- 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(), 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 >