1 /* 2 * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test 26 * @bug 8311867 27 * @summary Stress test of StructuredTaskScope.shutdown with running and starting threads 28 * @enablePreview 29 * @run junit StressShutdown 30 */ 31 32 import java.time.Duration; 33 import java.util.concurrent.Callable; 34 import java.util.concurrent.StructuredTaskScope; 35 import java.util.concurrent.ThreadFactory; 36 import java.util.stream.IntStream; 37 import java.util.stream.Stream; 38 39 import org.junit.jupiter.params.ParameterizedTest; 40 import org.junit.jupiter.params.provider.Arguments; 41 import org.junit.jupiter.params.provider.MethodSource; 42 import static org.junit.jupiter.api.Assertions.*; 43 44 class StressShutdown { 45 46 static final Callable<Void> SLEEP_FOR_A_DAY = () -> { 47 Thread.sleep(Duration.ofDays(1)); 48 return null; 49 }; 50 51 static Stream<Arguments> testCases() { 52 Stream<ThreadFactory> factories = Stream.of( 53 Thread.ofPlatform().factory(), 54 Thread.ofVirtual().factory() 55 ); 56 // 0..15 forks before shutdown, 0..15 forks after shutdown 57 return factories.flatMap(f -> IntStream.range(0, 256) 58 .mapToObj(x -> Arguments.of(f, x & 0x0F, (x & 0xF0) >> 4))); 59 } 60 61 /** 62 * Test StructuredTaskScope.shutdown with running threads and concurrently with 63 * threads that are starting. The shutdown should interrupt all threads so that 64 * join wakes up. 65 * 66 * @param factory the ThreadFactory to use 67 * @param beforeShutdown the number of subtasks to fork before shutdown 68 * @param afterShutdown the number of subtasks to fork after shutdown 69 */ 70 @ParameterizedTest 71 @MethodSource("testCases") 72 void testShutdown(ThreadFactory factory, int beforeShutdown, int afterShutdown) 73 throws InterruptedException 74 { 75 try (var scope = new StructuredTaskScope<>(null, factory)) { 76 // fork subtasks 77 for (int i = 0; i < beforeShutdown; i++) { 78 scope.fork(SLEEP_FOR_A_DAY); 79 } 80 81 // fork subtask to shutdown 82 scope.fork(() -> { 83 scope.shutdown(); 84 return null; 85 }); 86 87 // fork after forking subtask to shutdown 88 for (int i = 0; i < afterShutdown; i++) { 89 scope.fork(SLEEP_FOR_A_DAY); 90 } 91 92 scope.join(); 93 } 94 } 95 }