79 return values[tlr.nextInt(3)];
80 }
81 }
82
83 final Behaviour behaviour;
84
85 public DeepRecursion(Behaviour behaviour) {
86 this.behaviour = behaviour;
87 }
88
89 public void run() {
90 final var last = el.get();
91 while (ITERS-- > 0) {
92 if (System.nanoTime() - startTime > DURATION_IN_NANOS) {
93 return;
94 }
95
96 var nextRandomFloat = ThreadLocalRandom.current().nextFloat();
97 try {
98 switch (behaviour) {
99 case CALL -> ScopedValue.where(el, el.get() + 1).call(() -> fibonacci_pad(20, this));
100 case GET -> ScopedValue.where(el, el.get() + 1).get(() -> fibonacci_pad(20, this));
101 case RUN -> ScopedValue.where(el, el.get() + 1).run(() -> fibonacci_pad(20, this));
102 }
103 if (!last.equals(el.get())) {
104 throw testFailureException;
105 }
106 } catch (StackOverflowError e) {
107 if (nextRandomFloat <= 0.1) {
108 ScopedValue.where(el, el.get() + 1).run(this);
109 }
110 } catch (TestFailureException e) {
111 throw e;
112 } catch (Throwable throwable) {
113 // StackOverflowErrors cause many different failures. These include
114 // StructureViolationExceptions and InvocationTargetExceptions. This test
115 // checks that, no matter what the failure mode, scoped values are handled
116 // correctly.
117 } finally {
118 if (!last.equals(el.get())) {
119 throw testFailureException;
120 }
121 }
122
123 Thread.yield();
124 }
125 }
126
127 public Object get() {
128 run();
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 = new StructuredTaskScope<>("", 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 = new StructuredTaskScope<>()) {
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
|
79 return values[tlr.nextInt(3)];
80 }
81 }
82
83 final Behaviour behaviour;
84
85 public DeepRecursion(Behaviour behaviour) {
86 this.behaviour = behaviour;
87 }
88
89 public void run() {
90 final var last = el.get();
91 while (ITERS-- > 0) {
92 if (System.nanoTime() - startTime > DURATION_IN_NANOS) {
93 return;
94 }
95
96 var nextRandomFloat = ThreadLocalRandom.current().nextFloat();
97 try {
98 switch (behaviour) {
99 case CALL -> ScopedValue.callWhere(el, el.get() + 1, () -> fibonacci_pad(20, this));
100 case GET -> ScopedValue.getWhere(el, el.get() + 1, () -> fibonacci_pad(20, this));
101 case RUN -> ScopedValue.runWhere(el, el.get() + 1, () -> fibonacci_pad(20, this));
102 }
103 if (!last.equals(el.get())) {
104 throw testFailureException;
105 }
106 } catch (StackOverflowError e) {
107 if (nextRandomFloat <= 0.1) {
108 ScopedValue.runWhere(el, el.get() + 1, this);
109 }
110 } catch (TestFailureException e) {
111 throw e;
112 } catch (Throwable throwable) {
113 // StackOverflowErrors cause many different failures. These include
114 // StructureViolationExceptions and InvocationTargetExceptions. This test
115 // checks that, no matter what the failure mode, scoped values are handled
116 // correctly.
117 } finally {
118 if (!last.equals(el.get())) {
119 throw testFailureException;
120 }
121 }
122
123 Thread.yield();
124 }
125 }
126
127 public Object get() {
128 run();
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 = new StructuredTaskScope<>("", 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 var carrier = ScopedValue.where(inheritedValue, 42).where(el, 0);
190 ScopedValue.runWhere(carrier, () -> {
191 try (var scope = new StructuredTaskScope<>()) {
192 try {
193 if (ThreadLocalRandom.current().nextBoolean()) {
194 // Repeatedly test Scoped Values set by ScopedValue::call(), get(), and run()
195 final var deepRecursion
196 = new DeepRecursion(DeepRecursion.Behaviour.choose(ThreadLocalRandom.current()));
197 deepRecursion.run();
198 } else {
199 // Recursively run ourself until we get a stack overflow
200 // Catch the overflow and make sure the recovery path works
201 // for values inherited from a StructuredTaskScope.
202 Runnable op = new Runnable() {
203 public void run() {
204 try {
205 fibonacci_pad(20, this);
206 } catch (StackOverflowError e) {
207 } catch (TestFailureException e) {
208 throw e;
209 } catch (Throwable throwable) {
210 // StackOverflowErrors cause many different failures. These include
|