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 id=default
26 * @bug 8284161 8286788 8321270
27 * @summary Test Thread API with virtual threads
28 * @modules java.base/java.lang:+open
29 * @library /test/lib
30 * @run junit/othervm --enable-native-access=ALL-UNNAMED ThreadAPI
31 */
32
33 /*
34 * @test id=no-vmcontinuations
35 * @requires vm.continuations
36 * @modules java.base/java.lang:+open
37 * @library /test/lib
38 * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:-VMContinuations
39 * --enable-native-access=ALL-UNNAMED ThreadAPI
40 */
41
42 import java.time.Duration;
43 import java.util.Arrays;
44 import java.util.ArrayList;
45 import java.util.List;
46 import java.util.Map;
47 import java.util.Set;
48 import java.util.concurrent.CopyOnWriteArrayList;
49 import java.util.concurrent.CountDownLatch;
50 import java.util.concurrent.ExecutorService;
51 import java.util.concurrent.Executor;
52 import java.util.concurrent.Executors;
53 import java.util.concurrent.ForkJoinPool;
54 import java.util.concurrent.ScheduledExecutorService;
55 import java.util.concurrent.ThreadFactory;
56 import java.util.concurrent.TimeUnit;
57 import java.util.concurrent.atomic.AtomicBoolean;
58 import java.util.concurrent.atomic.AtomicReference;
59 import java.util.concurrent.locks.LockSupport;
60 import java.util.concurrent.locks.ReentrantLock;
61 import java.util.stream.Stream;
62 import java.nio.channels.Selector;
63
64 import jdk.test.lib.thread.VThreadPinner;
65 import jdk.test.lib.thread.VThreadRunner;
66 import jdk.test.lib.thread.VThreadScheduler;
67 import org.junit.jupiter.api.Test;
68 import org.junit.jupiter.api.BeforeAll;
69 import org.junit.jupiter.api.AfterAll;
70 import org.junit.jupiter.api.Disabled;
71 import org.junit.jupiter.params.ParameterizedTest;
72 import org.junit.jupiter.params.provider.MethodSource;
73 import org.junit.jupiter.params.provider.ValueSource;
74 import static org.junit.jupiter.api.Assertions.*;
75 import static org.junit.jupiter.api.Assumptions.*;
76
77 class ThreadAPI {
78 private static final Object lock = new Object();
79
80 // used for scheduling thread interrupt
81 private static ScheduledExecutorService scheduler;
82
83 @BeforeAll
84 static void setup() {
85 ThreadFactory factory = Executors.defaultThreadFactory();
86 scheduler = Executors.newSingleThreadScheduledExecutor(factory);
87
88 // need >=2 carriers for testing pinning
89 VThreadRunner.ensureParallelism(2);
90 }
1065
1066 // running
1067 thread.start();
1068 try {
1069 assertTrue(thread.isDaemon());
1070 assertThrows(IllegalThreadStateException.class, () -> thread.setDaemon(true));
1071 assertThrows(IllegalArgumentException.class, () -> thread.setDaemon(false));
1072 } finally {
1073 LockSupport.unpark(thread);
1074 }
1075 thread.join();
1076
1077 // terminated
1078 assertTrue(thread.isDaemon());
1079 }
1080
1081 /**
1082 * Test Thread.yield releases carrier thread.
1083 */
1084 @Test
1085 void testYield1() throws Exception {
1086 assumeTrue(VThreadScheduler.supportsCustomScheduler(), "No support for custom schedulers");
1087 var list = new CopyOnWriteArrayList<String>();
1088 try (ExecutorService scheduler = Executors.newFixedThreadPool(1)) {
1089 ThreadFactory factory = VThreadScheduler.virtualThreadFactory(scheduler);
1090 var thread = factory.newThread(() -> {
1091 list.add("A");
1092 var child = factory.newThread(() -> {
1093 list.add("B");
1094 Thread.yield();
1095 list.add("B");
1096 });
1097 child.start();
1098 Thread.yield();
1099 list.add("A");
1100 try { child.join(); } catch (InterruptedException e) { }
1101 });
1102 thread.start();
1103 thread.join();
1104 }
1105 assertEquals(List.of("A", "B", "A", "B"), list);
1106 }
1107
1108 /**
1109 * Test Thread.yield when thread is pinned by native frame.
1110 */
1111 @Test
1112 void testYield2() throws Exception {
1113 assumeTrue(VThreadScheduler.supportsCustomScheduler(), "No support for custom schedulers");
1114 var list = new CopyOnWriteArrayList<String>();
1115 try (ExecutorService scheduler = Executors.newFixedThreadPool(1)) {
1116 ThreadFactory factory = VThreadScheduler.virtualThreadFactory(scheduler);
1117 var thread = factory.newThread(() -> {
1118 list.add("A");
1119 var child = factory.newThread(() -> {
1120 list.add("B");
1121 });
1122 child.start();
1123 VThreadPinner.runPinned(() -> {
1124 Thread.yield(); // pinned so will be a no-op
1125 list.add("A");
1126 });
1127 try { child.join(); } catch (InterruptedException e) { }
1128 });
1129 thread.start();
1130 thread.join();
1131 }
1132 assertEquals(List.of("A", "A", "B"), list);
1133 }
1134
1135 /**
1136 * Test Thread.yield does not consume the thread's parking permit.
1137 */
1138 @Test
1139 void testYield3() throws Exception {
1140 var thread = Thread.ofVirtual().start(() -> {
1141 LockSupport.unpark(Thread.currentThread());
1142 Thread.yield();
1143 LockSupport.park(); // should not park
1144 });
1145 thread.join();
1146 }
1147
1148 /**
1149 * Test Thread.yield does not make available the thread's parking permit.
1150 */
1151 @Test
1152 void testYield4() throws Exception {
1153 var thread = Thread.ofVirtual().start(() -> {
1154 Thread.yield();
1155 LockSupport.park(); // should park
1156 });
1157 try {
1158 await(thread, Thread.State.WAITING);
1159 } finally {
1160 LockSupport.unpark(thread);
1161 thread.join();
1162 }
1163 }
1164
1165 /**
1166 * Test Thread.onSpinWait.
1167 */
1168 @Test
1169 void testOnSpinWait() throws Exception {
1170 VThreadRunner.run(() -> {
1171 Thread me = Thread.currentThread();
1172 Thread.onSpinWait();
1954 void testHoldsLock1() throws Exception {
1955 VThreadRunner.run(() -> {
1956 var lock = new Object();
1957 assertFalse(Thread.holdsLock(lock));
1958 });
1959 }
1960
1961 /**
1962 * Test Thread.holdsLock when lock held.
1963 */
1964 @Test
1965 void testHoldsLock2() throws Exception {
1966 VThreadRunner.run(() -> {
1967 var lock = new Object();
1968 synchronized (lock) {
1969 assertTrue(Thread.holdsLock(lock));
1970 }
1971 });
1972 }
1973
1974 /**
1975 * Test Thread::getStackTrace on unstarted thread.
1976 */
1977 @Test
1978 void testGetStackTraceUnstarted() {
1979 var thread = Thread.ofVirtual().unstarted(() -> { });
1980 StackTraceElement[] stack = thread.getStackTrace();
1981 assertTrue(stack.length == 0);
1982 }
1983
1984 /**
1985 * Test Thread::getStackTrace on thread that has been started but has not run.
1986 */
1987 @Test
1988 void testGetStackTraceStarted() throws Exception {
1989 assumeTrue(VThreadScheduler.supportsCustomScheduler(), "No support for custom schedulers");
1990 Executor scheduler = task -> { };
1991 ThreadFactory factory = VThreadScheduler.virtualThreadFactory(scheduler);
1992 Thread thread = factory.newThread(() -> { });
1993 thread.start();
|
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 id=default
26 * @bug 8284161 8286788 8321270
27 * @summary Test Thread API with virtual threads
28 * @modules java.base/java.lang:+open jdk.management
29 * @library /test/lib
30 * @build LockingMode
31 * @run junit/othervm --enable-native-access=ALL-UNNAMED ThreadAPI
32 */
33
34 /*
35 * @test id=no-vmcontinuations
36 * @requires vm.continuations
37 * @modules java.base/java.lang:+open jdk.management
38 * @library /test/lib
39 * @build LockingMode
40 * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:-VMContinuations
41 * --enable-native-access=ALL-UNNAMED ThreadAPI
42 */
43
44 import java.time.Duration;
45 import java.util.Arrays;
46 import java.util.ArrayList;
47 import java.util.List;
48 import java.util.Map;
49 import java.util.Set;
50 import java.util.concurrent.CopyOnWriteArrayList;
51 import java.util.concurrent.CountDownLatch;
52 import java.util.concurrent.ExecutorService;
53 import java.util.concurrent.Executor;
54 import java.util.concurrent.Executors;
55 import java.util.concurrent.ForkJoinPool;
56 import java.util.concurrent.ScheduledExecutorService;
57 import java.util.concurrent.ThreadFactory;
58 import java.util.concurrent.TimeUnit;
59 import java.util.concurrent.atomic.AtomicBoolean;
60 import java.util.concurrent.atomic.AtomicReference;
61 import java.util.concurrent.locks.LockSupport;
62 import java.util.concurrent.locks.ReentrantLock;
63 import java.util.stream.Stream;
64 import java.nio.channels.Selector;
65
66 import jdk.test.lib.thread.VThreadPinner;
67 import jdk.test.lib.thread.VThreadRunner; // ensureParallelism requires jdk.management
68 import jdk.test.lib.thread.VThreadScheduler;
69 import org.junit.jupiter.api.Test;
70 import org.junit.jupiter.api.BeforeAll;
71 import org.junit.jupiter.api.AfterAll;
72 import org.junit.jupiter.api.Disabled;
73 import org.junit.jupiter.api.condition.DisabledIf;
74 import org.junit.jupiter.params.ParameterizedTest;
75 import org.junit.jupiter.params.provider.MethodSource;
76 import org.junit.jupiter.params.provider.ValueSource;
77 import static org.junit.jupiter.api.Assertions.*;
78 import static org.junit.jupiter.api.Assumptions.*;
79
80 class ThreadAPI {
81 private static final Object lock = new Object();
82
83 // used for scheduling thread interrupt
84 private static ScheduledExecutorService scheduler;
85
86 @BeforeAll
87 static void setup() {
88 ThreadFactory factory = Executors.defaultThreadFactory();
89 scheduler = Executors.newSingleThreadScheduledExecutor(factory);
90
91 // need >=2 carriers for testing pinning
92 VThreadRunner.ensureParallelism(2);
93 }
1068
1069 // running
1070 thread.start();
1071 try {
1072 assertTrue(thread.isDaemon());
1073 assertThrows(IllegalThreadStateException.class, () -> thread.setDaemon(true));
1074 assertThrows(IllegalArgumentException.class, () -> thread.setDaemon(false));
1075 } finally {
1076 LockSupport.unpark(thread);
1077 }
1078 thread.join();
1079
1080 // terminated
1081 assertTrue(thread.isDaemon());
1082 }
1083
1084 /**
1085 * Test Thread.yield releases carrier thread.
1086 */
1087 @Test
1088 void testYieldReleasesCarrier() throws Exception {
1089 assumeTrue(VThreadScheduler.supportsCustomScheduler(), "No support for custom schedulers");
1090 var list = new CopyOnWriteArrayList<String>();
1091 try (ExecutorService scheduler = Executors.newFixedThreadPool(1)) {
1092 ThreadFactory factory = VThreadScheduler.virtualThreadFactory(scheduler);
1093 var thread = factory.newThread(() -> {
1094 list.add("A");
1095 var child = factory.newThread(() -> {
1096 list.add("B");
1097 Thread.yield();
1098 list.add("B");
1099 });
1100 child.start();
1101 Thread.yield();
1102 list.add("A");
1103 try { child.join(); } catch (InterruptedException e) { }
1104 });
1105 thread.start();
1106 thread.join();
1107 }
1108 assertEquals(List.of("A", "B", "A", "B"), list);
1109 }
1110
1111 /**
1112 * Test Thread.yield releases carrier thread when virtual thread holds a monitor.
1113 */
1114 @Test
1115 @DisabledIf("LockingMode#isLegacy")
1116 void testYieldReleasesCarrierWhenHoldingMonitor() throws Exception {
1117 assumeTrue(VThreadScheduler.supportsCustomScheduler(), "No support for custom schedulers");
1118 var list = new CopyOnWriteArrayList<String>();
1119 try (ExecutorService scheduler = Executors.newFixedThreadPool(1)) {
1120 ThreadFactory factory = VThreadScheduler.virtualThreadFactory(scheduler);
1121 var lock = new Object();
1122 var thread = factory.newThread(() -> {
1123 list.add("A");
1124 var child = factory.newThread(() -> {
1125 list.add("B");
1126 synchronized (lock) {
1127 Thread.yield();
1128 }
1129 list.add("B");
1130 });
1131 child.start();
1132 Thread.yield();
1133 list.add("A");
1134 try { child.join(); } catch (InterruptedException e) { }
1135 });
1136 thread.start();
1137 thread.join();
1138 }
1139 assertEquals(List.of("A", "B", "A", "B"), list);
1140 }
1141
1142 /**
1143 * Test Thread.yield when thread is pinned.
1144 */
1145 @Test
1146 void testYieldWhenPinned() throws Exception {
1147 assumeTrue(VThreadScheduler.supportsCustomScheduler(), "No support for custom schedulers");
1148 var list = new CopyOnWriteArrayList<String>();
1149 try (ExecutorService scheduler = Executors.newFixedThreadPool(1)) {
1150 ThreadFactory factory = VThreadScheduler.virtualThreadFactory(scheduler);
1151 var thread = factory.newThread(() -> {
1152 list.add("A");
1153 var child = factory.newThread(() -> {
1154 list.add("B");
1155 });
1156 child.start();
1157 VThreadPinner.runPinned(() -> {
1158 Thread.yield(); // pinned so will be a no-op
1159 list.add("A");
1160 });
1161 try { child.join(); } catch (InterruptedException e) { }
1162 });
1163 thread.start();
1164 thread.join();
1165 }
1166 assertEquals(List.of("A", "A", "B"), list);
1167 }
1168
1169 /**
1170 * Test Thread.yield does not consume the thread's parking permit.
1171 */
1172 @Test
1173 void testYieldDoesNotConsumParkingPermit() throws Exception {
1174 var thread = Thread.ofVirtual().start(() -> {
1175 LockSupport.unpark(Thread.currentThread());
1176 Thread.yield();
1177 LockSupport.park(); // should not park
1178 });
1179 thread.join();
1180 }
1181
1182 /**
1183 * Test Thread.yield does not make available the thread's parking permit.
1184 */
1185 @Test
1186 void testYieldDoesNotOfferParkingPermit() throws Exception {
1187 var thread = Thread.ofVirtual().start(() -> {
1188 Thread.yield();
1189 LockSupport.park(); // should park
1190 });
1191 try {
1192 await(thread, Thread.State.WAITING);
1193 } finally {
1194 LockSupport.unpark(thread);
1195 thread.join();
1196 }
1197 }
1198
1199 /**
1200 * Test Thread.onSpinWait.
1201 */
1202 @Test
1203 void testOnSpinWait() throws Exception {
1204 VThreadRunner.run(() -> {
1205 Thread me = Thread.currentThread();
1206 Thread.onSpinWait();
1988 void testHoldsLock1() throws Exception {
1989 VThreadRunner.run(() -> {
1990 var lock = new Object();
1991 assertFalse(Thread.holdsLock(lock));
1992 });
1993 }
1994
1995 /**
1996 * Test Thread.holdsLock when lock held.
1997 */
1998 @Test
1999 void testHoldsLock2() throws Exception {
2000 VThreadRunner.run(() -> {
2001 var lock = new Object();
2002 synchronized (lock) {
2003 assertTrue(Thread.holdsLock(lock));
2004 }
2005 });
2006 }
2007
2008 /**
2009 * Test Thread.holdsLock when lock held by carrier thread.
2010 */
2011 @Disabled
2012 @Test
2013 void testHoldsLock3() throws Exception {
2014 assumeTrue(VThreadScheduler.supportsCustomScheduler(), "No support for custom schedulers");
2015
2016 Object lock = new Object();
2017
2018 // carrier thread runs all tasks while holding the lock
2019 ThreadFactory carrierThreadFactory = task -> Thread.ofPlatform().unstarted(() -> {
2020 synchronized (lock) {
2021 task.run();
2022 }
2023 });
2024 try (ExecutorService pool = Executors.newSingleThreadExecutor(carrierThreadFactory)) {
2025 Executor scheduler = task -> pool.submit(task::run);
2026 ThreadFactory factory = VThreadScheduler.virtualThreadFactory(scheduler);
2027
2028 // start virtual that tests if it holds the lock
2029 var result = new AtomicReference<Boolean>();
2030 Thread vthread = factory.newThread(() -> {
2031 result.set(Thread.holdsLock(lock));
2032 });
2033 vthread.start();
2034 vthread.join();
2035 boolean holdsLock = result.get();
2036 assertFalse(holdsLock, "Thread.holdsLock should return false");
2037 }
2038 }
2039
2040 /**
2041 * Test Thread::getStackTrace on unstarted thread.
2042 */
2043 @Test
2044 void testGetStackTraceUnstarted() {
2045 var thread = Thread.ofVirtual().unstarted(() -> { });
2046 StackTraceElement[] stack = thread.getStackTrace();
2047 assertTrue(stack.length == 0);
2048 }
2049
2050 /**
2051 * Test Thread::getStackTrace on thread that has been started but has not run.
2052 */
2053 @Test
2054 void testGetStackTraceStarted() throws Exception {
2055 assumeTrue(VThreadScheduler.supportsCustomScheduler(), "No support for custom schedulers");
2056 Executor scheduler = task -> { };
2057 ThreadFactory factory = VThreadScheduler.virtualThreadFactory(scheduler);
2058 Thread thread = factory.newThread(() -> { });
2059 thread.start();
|