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 * @summary Verifies JVMTI StopThread support for virtual threads.
27 * @requires vm.continuations
28 * @run main/othervm/native -agentlib:StopThreadTest StopThreadTest
29 */
30
31 /*
32 * @test id=no-vmcontinuations
33 * @summary Verifies JVMTI StopThread support for bound virtual threads.
34 * @run main/othervm/native -agentlib:StopThreadTest -XX:+UnlockExperimentalVMOptions -XX:-VMContinuations StopThreadTest
35 */
36
37 /*
38 * @test id=platform
39 * @summary Verifies JVMTI StopThread support for platform threads.
40 * @run main/othervm/native -agentlib:StopThreadTest StopThreadTest platform
41 */
42
43 import java.lang.AssertionError;
44
45 /*
46 * The test exercises the JVMTI function: StopThread(jthread).
47 * The test creates a new virtual or platform thread.
48 * Its method run() invokes the following methods:
49 * - method A() that is blocked on a monitor
50 * - method B() that is stopped at a breakpoint
51 * - method C() that forces agent to send AssertionError exception to its own thread
52 * All cases are using JVMTI StopThread to send an AssertionError object.
53 */
54 public class StopThreadTest {
55 private static final String agentLib = "StopThreadTest";
56 static final int JVMTI_ERROR_NONE = 0;
57 static final int THREAD_NOT_SUSPENDED = 13;
58 static final int PASSED = 0;
59 static final int FAILED = 2;
60
61 static void log(String str) { System.out.println(str); }
62
63 static native void prepareAgent(Class taskClass, Object exceptionObject);
64 static native void suspendThread(Thread thread);
65 static native void resumeThread(Thread thread);
66 static native void ensureAtBreakpoint();
67 static native void notifyAtBreakpoint();
68 static native int stopThread(Thread thread);
69
70 static int status = PASSED;
71 static boolean is_virtual = true;
72
73 static void setFailed(String msg) {
74 log("\nFAILED: " + msg);
75 status = FAILED;
76 }
87 throwFailed("StopThreadTest!");
88 }
89 log("\nStopThreadTest passed");
90 }
91
92 public static void run() {
93 TestTask testTask = new TestTask();
94 Thread testTaskThread = null;
95 AssertionError excObject = new AssertionError();
96 int retCode;
97
98 prepareAgent(TestTask.class, excObject);
99
100 log("\nMain #A: method A() must be blocked on entering a synchronized statement");
101 synchronized (TestTask.lock) {
102 if (is_virtual) {
103 testTaskThread = Thread.ofVirtual().name("TestTaskThread").start(testTask);
104 } else {
105 testTaskThread = Thread.ofPlatform().name("TestTaskThread").start(testTask);
106 }
107 TestTask.ensureAtPointA();
108
109 if (is_virtual) { // this check is for virtual target thread only
110 log("\nMain #A.1: unsuspended");
111 retCode = stopThread(testTaskThread);
112 if (retCode != THREAD_NOT_SUSPENDED) {
113 throwFailed("Main #A.1: expected THREAD_NOT_SUSPENDED instead of: " + retCode);
114 } else {
115 log("Main #A.1: got expected THREAD_NOT_SUSPENDED");
116 }
117 }
118
119 log("\nMain #A.2: suspended");
120 suspendThread(testTaskThread);
121 retCode = stopThread(testTaskThread);
122 if (retCode != JVMTI_ERROR_NONE) {
123 throwFailed("Main #A.2: expected JVMTI_ERROR_NONE instead of: " + retCode);
124 } else {
125 log("Main #A.2: got expected JVMTI_ERROR_NONE");
126 }
127 resumeThread(testTaskThread);
128 }
129 log("\nMain #B: method B() must be blocked in a breakpoint event handler");
130 {
131 ensureAtBreakpoint();
132
133 if (is_virtual) { // this check is for virtual target thread only
134 log("\nMain #B.1: unsuspended");
135 retCode = stopThread(testTaskThread);
136 if (retCode != THREAD_NOT_SUSPENDED) {
137 throwFailed("Main #B.1: expected THREAD_NOT_SUSPENDED instead of: " + retCode);
138 }
139 }
140
141 log("\nMain #B.2: suspended");
142 suspendThread(testTaskThread);
143 retCode = stopThread(testTaskThread);
144 if (retCode != JVMTI_ERROR_NONE) {
145 throwFailed("Main #B.2: expected JVMTI_ERROR_NONE");
162 throwFailed("Unexpected " + ex);
163 }
164 }
165
166
167 static class TestTask implements Runnable {
168 static Object lock = new Object();
169 static void log(String str) { System.out.println(str); }
170
171 static volatile boolean atPointA = false;
172 static volatile boolean finished = false;
173
174 static void sleep(long millis) {
175 try {
176 Thread.sleep(millis);
177 } catch (InterruptedException e) {
178 throw new RuntimeException("Interruption in TestTask.sleep: \n\t" + e);
179 }
180 }
181
182 static void ensureAtPointA() {
183 while (!atPointA) {
184 sleep(1);
185 }
186 }
187
188 // Ensure thread is finished.
189 static void ensureFinished() {
190 while (!finished) {
191 sleep(1);
192 }
193 }
194
195 public void run() {
196 log("TestTask.run: started");
197
198 boolean seenExceptionFromA = false;
199 try {
200 A();
201 } catch (AssertionError ex) {
202 log("TestTask.run: caught expected AssertionError from method A()");
203 seenExceptionFromA = true;
204 }
205 Thread.interrupted();
206 if (!seenExceptionFromA) {
207 StopThreadTest.setFailed("TestTask.run: expected AssertionError from method A()");
208 }
209 sleep(1); // to cause yield
210
211 boolean seenExceptionFromB = false;
212 try {
213 B();
214 } catch (AssertionError ex) {
215 log("TestTask.run: caught expected AssertionError from method B()");
216 seenExceptionFromB = true;
217 }
218 Thread.interrupted();
219 if (!seenExceptionFromB) {
220 StopThreadTest.setFailed("TestTask.run: expected AssertionError from method B()");
221 }
222 sleep(1); // to cause yield
223
224 boolean seenExceptionFromC = false;
225 try {
226 C();
227 } catch (AssertionError ex) {
228 log("TestTask.run: caught expected AssertionError from method C()");
229 seenExceptionFromC = true;
230 }
231 Thread.interrupted();
232 if (!seenExceptionFromC) {
233 StopThreadTest.setFailed("TestTask.run: expected AssertionError from method C()");
234 }
235 finished = true;
236 }
237
238 // Method is blocked on entering a synchronized statement.
239 // StopThread is used to send an AssertionError object two times:
240 // - when not suspended: THREAD_NOT_SUSPENDED is expected
241 // - when suspended: JVMTI_ERROR_NONE is expected
242 static void A() {
243 log("TestTask.A: started");
244 atPointA = true;
245 synchronized (lock) {
246 }
247 log("TestTask.A: finished");
248 }
249
250 // A breakpoint is set at start of this method.
251 // StopThread is used to send an AssertionError object two times:
252 // - when not suspended: THREAD_NOT_SUSPENDED is expected
253 // - when suspended: expected to succeed
254 static void B() {
255 log("TestTask.B: started");
256 }
257
258 // This method uses StopThread to send an AssertionError object to
259 // its own thread. It is expected to succeed.
260 static void C() {
261 log("TestTask.C: started");
262 StopThreadTest.stopThread(Thread.currentThread());
263 log("TestTask.C: finished");
264 }
|
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 * @summary Verifies JVMTI StopThread support for virtual threads.
27 * @requires vm.continuations
28 * @library /test/lib
29 * @run main/othervm/native -agentlib:StopThreadTest StopThreadTest
30 */
31
32 /*
33 * @test id=no-vmcontinuations
34 * @summary Verifies JVMTI StopThread support for bound virtual threads.
35 * @library /test/lib
36 * @run main/othervm/native -agentlib:StopThreadTest -XX:+UnlockExperimentalVMOptions -XX:-VMContinuations -DboundVThread=true StopThreadTest
37 */
38
39 /*
40 * @test id=platform
41 * @summary Verifies JVMTI StopThread support for platform threads.
42 * @library /test/lib
43 * @run main/othervm/native -agentlib:StopThreadTest StopThreadTest platform
44 */
45
46 import jdk.test.lib.Platform;
47 import java.lang.AssertionError;
48
49 /*
50 * The test exercises the JVMTI function: StopThread(jthread).
51 * The test creates a new virtual or platform thread.
52 * Its method run() invokes the following methods:
53 * - method A() that is blocked on a monitor
54 * - method B() that is stopped at a breakpoint
55 * - method C() that forces agent to send AssertionError exception to its own thread
56 * All cases are using JVMTI StopThread to send an AssertionError object.
57 */
58 public class StopThreadTest {
59 private static final String agentLib = "StopThreadTest";
60 static final boolean isBoundVThread = Boolean.getBoolean("boundVThread");
61 static final int JVMTI_ERROR_NONE = 0;
62 static final int JVMTI_ERROR_OPAQUE_FRAME = 32;
63 static final int THREAD_NOT_SUSPENDED = 13;
64 static final int PASSED = 0;
65 static final int FAILED = 2;
66
67 static void log(String str) { System.out.println(str); }
68
69 static native void prepareAgent(Class taskClass, Object exceptionObject);
70 static native void suspendThread(Thread thread);
71 static native void resumeThread(Thread thread);
72 static native void ensureAtBreakpoint();
73 static native void notifyAtBreakpoint();
74 static native int stopThread(Thread thread);
75
76 static int status = PASSED;
77 static boolean is_virtual = true;
78
79 static void setFailed(String msg) {
80 log("\nFAILED: " + msg);
81 status = FAILED;
82 }
93 throwFailed("StopThreadTest!");
94 }
95 log("\nStopThreadTest passed");
96 }
97
98 public static void run() {
99 TestTask testTask = new TestTask();
100 Thread testTaskThread = null;
101 AssertionError excObject = new AssertionError();
102 int retCode;
103
104 prepareAgent(TestTask.class, excObject);
105
106 log("\nMain #A: method A() must be blocked on entering a synchronized statement");
107 synchronized (TestTask.lock) {
108 if (is_virtual) {
109 testTaskThread = Thread.ofVirtual().name("TestTaskThread").start(testTask);
110 } else {
111 testTaskThread = Thread.ofPlatform().name("TestTaskThread").start(testTask);
112 }
113 TestTask.ensureAtPointA(testTaskThread);
114
115 if (is_virtual) { // this check is for virtual target thread only
116 log("\nMain #A.1: unsuspended");
117 retCode = stopThread(testTaskThread);
118 if (retCode != THREAD_NOT_SUSPENDED) {
119 throwFailed("Main #A.1: expected THREAD_NOT_SUSPENDED instead of: " + retCode);
120 } else {
121 log("Main #A.1: got expected THREAD_NOT_SUSPENDED");
122 }
123 }
124
125 log("\nMain #A.2: suspended");
126 suspendThread(testTaskThread);
127 retCode = stopThread(testTaskThread);
128 int expectedRetCode = (is_virtual && !isBoundVThread && (Platform.isX64() || Platform.isAArch64())) ? JVMTI_ERROR_OPAQUE_FRAME : JVMTI_ERROR_NONE;
129 String expectedRetCodeName = (is_virtual && !isBoundVThread && (Platform.isX64() || Platform.isAArch64())) ?
130 "JVMTI_ERROR_OPAQUE_FRAME" : "JVMTI_ERROR_NONE";
131 if (retCode != expectedRetCode) {
132 throwFailed("Main #A.2: expected " + expectedRetCodeName + " instead of: " + retCode);
133 } else {
134 log("Main #A.2: got expected " + expectedRetCodeName);
135 }
136 resumeThread(testTaskThread);
137 }
138 log("\nMain #B: method B() must be blocked in a breakpoint event handler");
139 {
140 ensureAtBreakpoint();
141
142 if (is_virtual) { // this check is for virtual target thread only
143 log("\nMain #B.1: unsuspended");
144 retCode = stopThread(testTaskThread);
145 if (retCode != THREAD_NOT_SUSPENDED) {
146 throwFailed("Main #B.1: expected THREAD_NOT_SUSPENDED instead of: " + retCode);
147 }
148 }
149
150 log("\nMain #B.2: suspended");
151 suspendThread(testTaskThread);
152 retCode = stopThread(testTaskThread);
153 if (retCode != JVMTI_ERROR_NONE) {
154 throwFailed("Main #B.2: expected JVMTI_ERROR_NONE");
171 throwFailed("Unexpected " + ex);
172 }
173 }
174
175
176 static class TestTask implements Runnable {
177 static Object lock = new Object();
178 static void log(String str) { System.out.println(str); }
179
180 static volatile boolean atPointA = false;
181 static volatile boolean finished = false;
182
183 static void sleep(long millis) {
184 try {
185 Thread.sleep(millis);
186 } catch (InterruptedException e) {
187 throw new RuntimeException("Interruption in TestTask.sleep: \n\t" + e);
188 }
189 }
190
191 static void ensureAtPointA(Thread vt) {
192 // wait while the thread state is not the expected one
193 while (vt.getState() != Thread.State.BLOCKED) {
194 sleep(1);
195 }
196 }
197
198 // Ensure thread is finished.
199 static void ensureFinished() {
200 while (!finished) {
201 sleep(1);
202 }
203 }
204
205 public void run() {
206 log("TestTask.run: started");
207
208 boolean seenExceptionFromA = false;
209 try {
210 A();
211 } catch (AssertionError ex) {
212 log("TestTask.run: caught expected AssertionError from method A()");
213 seenExceptionFromA = true;
214 }
215 Thread.interrupted();
216 if (!seenExceptionFromA
217 && !(is_virtual
218 && !isBoundVThread
219 && (Platform.isX64() || (Platform.isAArch64())) )) {
220 StopThreadTest.setFailed("TestTask.run: expected AssertionError from method A()");
221 }
222 sleep(1); // to cause yield
223
224 boolean seenExceptionFromB = false;
225 try {
226 B();
227 } catch (AssertionError ex) {
228 log("TestTask.run: caught expected AssertionError from method B()");
229 seenExceptionFromB = true;
230 }
231 Thread.interrupted();
232 if (!seenExceptionFromB) {
233 StopThreadTest.setFailed("TestTask.run: expected AssertionError from method B()");
234 }
235 sleep(1); // to cause yield
236
237 boolean seenExceptionFromC = false;
238 try {
239 C();
240 } catch (AssertionError ex) {
241 log("TestTask.run: caught expected AssertionError from method C()");
242 seenExceptionFromC = true;
243 }
244 Thread.interrupted();
245 if (!seenExceptionFromC) {
246 StopThreadTest.setFailed("TestTask.run: expected AssertionError from method C()");
247 }
248 finished = true;
249 }
250
251 // Method is blocked on entering a synchronized statement.
252 // StopThread is used to send an AssertionError object two times:
253 // - when not suspended: THREAD_NOT_SUSPENDED is expected
254 // - when suspended: JVMTI_ERROR_NONE is expected
255 static void A() {
256 log("TestTask.A: started");
257 synchronized (lock) {
258 }
259 log("TestTask.A: finished");
260 }
261
262 // A breakpoint is set at start of this method.
263 // StopThread is used to send an AssertionError object two times:
264 // - when not suspended: THREAD_NOT_SUSPENDED is expected
265 // - when suspended: expected to succeed
266 static void B() {
267 log("TestTask.B: started");
268 }
269
270 // This method uses StopThread to send an AssertionError object to
271 // its own thread. It is expected to succeed.
272 static void C() {
273 log("TestTask.C: started");
274 StopThreadTest.stopThread(Thread.currentThread());
275 log("TestTask.C: finished");
276 }
|