Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/hotspot/jtreg/serviceability/jvmti/SuspendWithRawMonitorEnter/SuspendWithRawMonitorEnter.java
41153 views
1
/*
2
* Copyright (c) 2001, 2021, 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 4413752
27
* @summary Test SuspendThread with RawMonitor enter.
28
* @requires vm.jvmti
29
* @library /test/lib
30
* @compile SuspendWithRawMonitorEnter.java
31
* @run main/othervm/native -agentlib:SuspendWithRawMonitorEnter SuspendWithRawMonitorEnter
32
*/
33
34
import java.io.PrintStream;
35
36
//
37
// main blocker contender resumer
38
// ================= ================ =================== ================
39
// launch blocker
40
// <launch returns> blocker running
41
// launch contender enter threadLock
42
// <launch returns> wait for notify contender running
43
// launch resumer : block on threadLock
44
// <launch returns> : : resumer running
45
// suspend contender : <suspended> wait for notify
46
// <ready to test> : : :
47
// : : : :
48
// notify blocker wait finishes : :
49
// notify resumer exit threadLock : wait finishes
50
// join blocker : : enter threadLock
51
// <join returns> blocker exits <resumed> resume contender
52
// join resumer : exit threadLock
53
// <join returns> enter threadLock resumer exits
54
// join contender exit threadLock
55
// <join returns> contender exits
56
//
57
58
public class SuspendWithRawMonitorEnter {
59
private static final String AGENT_LIB = "SuspendWithRawMonitorEnter";
60
private static final int exit_delta = 95;
61
62
private static final int DEF_TIME_MAX = 60; // default max # secs to test
63
private static final int JOIN_MAX = 30; // max # secs to wait for join
64
65
public static final int TS_INIT = 1; // initial testState
66
public static final int TS_BLOCKER_RUNNING = 2; // blocker is running
67
public static final int TS_CONTENDER_RUNNING = 3; // contender is running
68
public static final int TS_RESUMER_RUNNING = 4; // resumer is running
69
public static final int TS_CALL_SUSPEND = 5; // call suspend on contender
70
public static final int TS_DONE_BLOCKING = 6; // done blocking threadLock
71
public static final int TS_READY_TO_RESUME = 7; // ready to resume contender
72
public static final int TS_CALL_RESUME = 8; // call resume on contender
73
public static final int TS_CONTENDER_DONE = 9; // contender has run; done
74
75
public static Object barrierLaunch = new Object(); // controls thread launch
76
public static Object barrierBlocker = new Object(); // controls blocker
77
public static Object barrierResumer = new Object(); // controls resumer
78
79
public static long count = 0;
80
public static boolean printDebug = false;
81
public volatile static int testState;
82
83
private static void log(String msg) { System.out.println(msg); }
84
85
native static int createRawMonitor();
86
native static int destroyRawMonitor();
87
native static int suspendThread(SuspendWithRawMonitorEnterWorker thr);
88
89
public static void main(String[] args) throws Exception {
90
try {
91
System.loadLibrary(AGENT_LIB);
92
log("Loaded library: " + AGENT_LIB);
93
} catch (UnsatisfiedLinkError ule) {
94
log("Failed to load library: " + AGENT_LIB);
95
log("java.library.path: " + System.getProperty("java.library.path"));
96
throw ule;
97
}
98
99
int timeMax = 0;
100
if (args.length == 0) {
101
timeMax = DEF_TIME_MAX;
102
} else {
103
int argIndex = 0;
104
int argsLeft = args.length;
105
if (args[0].equals("-p")) {
106
printDebug = true;
107
argIndex = 1;
108
argsLeft--;
109
}
110
if (argsLeft == 0) {
111
timeMax = DEF_TIME_MAX;
112
} else if (argsLeft == 1) {
113
try {
114
timeMax = Integer.parseUnsignedInt(args[argIndex]);
115
} catch (NumberFormatException nfe) {
116
System.err.println("'" + args[argIndex] +
117
"': invalid timeMax value.");
118
usage();
119
}
120
} else {
121
usage();
122
}
123
}
124
125
System.exit(run(timeMax, System.out) + exit_delta);
126
}
127
128
public static void logDebug(String mesg) {
129
if (printDebug) {
130
System.err.println(Thread.currentThread().getName() + ": " + mesg);
131
}
132
}
133
134
public static void usage() {
135
System.err.println("Usage: " + AGENT_LIB + " [-p][time_max]");
136
System.err.println("where:");
137
System.err.println(" -p ::= print debug info");
138
System.err.println(" time_max ::= max looping time in seconds");
139
System.err.println(" (default is " + DEF_TIME_MAX +
140
" seconds)");
141
System.exit(1);
142
}
143
144
public static int run(int timeMax, PrintStream out) {
145
return (new SuspendWithRawMonitorEnter()).doWork(timeMax, out);
146
}
147
148
public static void checkTestState(int exp) {
149
if (testState != exp) {
150
System.err.println("Failure at " + count + " loops.");
151
throw new InternalError("Unexpected test state value: "
152
+ "expected=" + exp + " actual=" + testState);
153
}
154
}
155
156
public int doWork(int timeMax, PrintStream out) {
157
SuspendWithRawMonitorEnterWorker blocker; // blocker thread
158
SuspendWithRawMonitorEnterWorker contender; // contender thread
159
SuspendWithRawMonitorEnterWorker resumer; // resumer thread
160
161
int retCode = createRawMonitor();
162
if (retCode != 0) {
163
throw new RuntimeException("error in JVMTI CreateRawMonitor: " +
164
"retCode=" + retCode);
165
}
166
logDebug("created threadLock");
167
168
System.out.println("About to execute for " + timeMax + " seconds.");
169
170
long start_time = System.currentTimeMillis();
171
while (System.currentTimeMillis() < start_time + (timeMax * 1000)) {
172
count++;
173
testState = TS_INIT; // starting the test loop
174
175
// launch the blocker thread
176
synchronized (barrierLaunch) {
177
blocker = new SuspendWithRawMonitorEnterWorker("blocker");
178
blocker.start();
179
180
while (testState != TS_BLOCKER_RUNNING) {
181
try {
182
barrierLaunch.wait(0); // wait until it is running
183
} catch (InterruptedException ex) {
184
}
185
}
186
}
187
188
// launch the contender thread
189
synchronized (barrierLaunch) {
190
contender = new SuspendWithRawMonitorEnterWorker("contender");
191
contender.start();
192
193
while (testState != TS_CONTENDER_RUNNING) {
194
try {
195
barrierLaunch.wait(0); // wait until it is running
196
} catch (InterruptedException ex) {
197
}
198
}
199
}
200
201
// launch the resumer thread
202
synchronized (barrierLaunch) {
203
resumer = new SuspendWithRawMonitorEnterWorker("resumer", contender);
204
resumer.start();
205
206
while (testState != TS_RESUMER_RUNNING) {
207
try {
208
barrierLaunch.wait(0); // wait until it is running
209
} catch (InterruptedException ex) {
210
}
211
}
212
}
213
214
//
215
// Known bug: We don't have a way of knowing when the
216
// contender thread contends on the threadLock. If we
217
// suspend it before it has blocked, then we don't really
218
// have contention. However, the resumer thread won't
219
// resume the contender thread until after it has grabbed
220
// the threadLock so we don't have a lock order problem
221
// and the test won't fall over.
222
//
223
// We reduce the size of this timing window by launching
224
// the resumer thread after the contender thread. So the
225
// contender thread has all the setup time for the resumer
226
// thread to call JVM/TI RawMonitorEnter() and block on
227
// the threadLock.
228
//
229
checkTestState(TS_RESUMER_RUNNING);
230
testState = TS_CALL_SUSPEND;
231
logDebug("before suspend thread");
232
retCode = suspendThread(contender);
233
if (retCode != 0) {
234
throw new RuntimeException("error in JVMTI SuspendThread: " +
235
"retCode=" + retCode);
236
}
237
logDebug("suspended thread");
238
239
//
240
// At this point, all of the child threads are running
241
// and we can get to meat of the test:
242
//
243
// - suspended threadLock contender
244
// - a threadLock exit in the blocker thread
245
// - a threadLock enter in the resumer thread
246
// - resumption of the contender thread
247
// - a threadLock enter in the freshly resumed contender thread
248
//
249
synchronized (barrierBlocker) {
250
checkTestState(TS_CALL_SUSPEND);
251
252
// tell blocker thread to exit threadLock
253
testState = TS_DONE_BLOCKING;
254
barrierBlocker.notify();
255
}
256
257
synchronized (barrierResumer) {
258
// tell resumer thread to resume contender thread
259
testState = TS_READY_TO_RESUME;
260
barrierResumer.notify();
261
262
// Can't call checkTestState() here because the
263
// resumer thread may have already resumed the
264
// contender thread.
265
}
266
267
try {
268
blocker.join();
269
resumer.join(JOIN_MAX * 1000);
270
if (resumer.isAlive()) {
271
System.err.println("Failure at " + count + " loops.");
272
throw new InternalError("resumer thread is stuck");
273
}
274
contender.join(JOIN_MAX * 1000);
275
if (contender.isAlive()) {
276
System.err.println("Failure at " + count + " loops.");
277
throw new InternalError("contender thread is stuck");
278
}
279
} catch (InterruptedException ex) {
280
}
281
282
checkTestState(TS_CONTENDER_DONE);
283
}
284
retCode = destroyRawMonitor();
285
if (retCode != 0) {
286
throw new RuntimeException("error in JVMTI DestroyRawMonitor: " +
287
"retCode=" + retCode);
288
}
289
logDebug("destroyed threadLock");
290
291
System.out.println("Executed " + count + " loops in " + timeMax +
292
" seconds.");
293
294
return 0;
295
}
296
}
297
298
class SuspendWithRawMonitorEnterWorker extends Thread {
299
private SuspendWithRawMonitorEnterWorker target; // target for resume operation
300
301
public SuspendWithRawMonitorEnterWorker(String name) {
302
super(name);
303
}
304
305
public SuspendWithRawMonitorEnterWorker(String name, SuspendWithRawMonitorEnterWorker target) {
306
super(name);
307
this.target = target;
308
}
309
310
native static int rawMonitorEnter();
311
native static int rawMonitorExit();
312
native static int resumeThread(SuspendWithRawMonitorEnterWorker thr);
313
314
public void run() {
315
SuspendWithRawMonitorEnter.logDebug("thread running");
316
317
//
318
// Launch the blocker thread:
319
// - grabs threadLock
320
// - holds threadLock until we tell it let go
321
// - releases threadLock
322
//
323
int retCode;
324
if (getName().equals("blocker")) {
325
// grab threadLock before we tell main we are running
326
SuspendWithRawMonitorEnter.logDebug("before enter threadLock");
327
retCode = rawMonitorEnter();
328
if (retCode != 0) {
329
throw new RuntimeException("error in JVMTI RawMonitorEnter: " +
330
"retCode=" + retCode);
331
}
332
SuspendWithRawMonitorEnter.logDebug("enter threadLock");
333
334
SuspendWithRawMonitorEnter.checkTestState(SuspendWithRawMonitorEnter.TS_INIT);
335
336
// recursive entry
337
SuspendWithRawMonitorEnter.logDebug("before recursive enter threadLock");
338
retCode = rawMonitorEnter();
339
if (retCode != 0) {
340
throw new RuntimeException("error in JVMTI RawMonitorEnter: " +
341
"retCode=" + retCode);
342
}
343
SuspendWithRawMonitorEnter.logDebug("recursive enter threadLock");
344
345
SuspendWithRawMonitorEnter.logDebug("before recursive exit threadLock");
346
retCode = rawMonitorExit();
347
if (retCode != 0) {
348
throw new RuntimeException("error in JVMTI RawMonitorExit: " +
349
"retCode=" + retCode);
350
}
351
SuspendWithRawMonitorEnter.logDebug("recursive exit threadLock");
352
353
synchronized(SuspendWithRawMonitorEnter.barrierBlocker) {
354
synchronized(SuspendWithRawMonitorEnter.barrierLaunch) {
355
// tell main we are running
356
SuspendWithRawMonitorEnter.testState = SuspendWithRawMonitorEnter.TS_BLOCKER_RUNNING;
357
SuspendWithRawMonitorEnter.barrierLaunch.notify();
358
}
359
SuspendWithRawMonitorEnter.logDebug("thread waiting");
360
// TS_READY_TO_RESUME is set right after TS_DONE_BLOCKING
361
// is set so either can get the blocker thread out of
362
// this wait() wrapper:
363
while (SuspendWithRawMonitorEnter.testState != SuspendWithRawMonitorEnter.TS_DONE_BLOCKING &&
364
SuspendWithRawMonitorEnter.testState != SuspendWithRawMonitorEnter.TS_READY_TO_RESUME) {
365
try {
366
// wait for main to tell us when to exit threadLock
367
SuspendWithRawMonitorEnter.barrierBlocker.wait(0);
368
} catch (InterruptedException ex) {
369
}
370
}
371
SuspendWithRawMonitorEnter.logDebug("before exit threadLock");
372
retCode = rawMonitorExit();
373
if (retCode != 0) {
374
throw new RuntimeException("error in JVMTI RawMonitorExit: "
375
+ "retCode=" + retCode);
376
}
377
SuspendWithRawMonitorEnter.logDebug("exit threadLock");
378
}
379
}
380
//
381
// Launch the contender thread:
382
// - tries to grab the threadLock
383
// - grabs threadLock
384
// - releases threadLock
385
//
386
else if (getName().equals("contender")) {
387
synchronized(SuspendWithRawMonitorEnter.barrierLaunch) {
388
// tell main we are running
389
SuspendWithRawMonitorEnter.testState = SuspendWithRawMonitorEnter.TS_CONTENDER_RUNNING;
390
SuspendWithRawMonitorEnter.barrierLaunch.notify();
391
}
392
393
SuspendWithRawMonitorEnter.logDebug("before enter threadLock");
394
retCode = rawMonitorEnter();
395
if (retCode != 0) {
396
throw new RuntimeException("error in JVMTI RawMonitorEnter: " +
397
"retCode=" + retCode);
398
}
399
SuspendWithRawMonitorEnter.logDebug("enter threadLock");
400
401
SuspendWithRawMonitorEnter.checkTestState(SuspendWithRawMonitorEnter.TS_CALL_RESUME);
402
SuspendWithRawMonitorEnter.testState = SuspendWithRawMonitorEnter.TS_CONTENDER_DONE;
403
404
SuspendWithRawMonitorEnter.logDebug("before exit threadLock");
405
retCode = rawMonitorExit();
406
if (retCode != 0) {
407
throw new RuntimeException("error in JVMTI RawMonitorExit: " +
408
"retCode=" + retCode);
409
}
410
SuspendWithRawMonitorEnter.logDebug("exit threadLock");
411
}
412
//
413
// Launch the resumer thread:
414
// - tries to grab the threadLock (should not block!)
415
// - grabs threadLock
416
// - resumes the contended thread
417
// - releases threadLock
418
//
419
else if (getName().equals("resumer")) {
420
synchronized(SuspendWithRawMonitorEnter.barrierResumer) {
421
synchronized(SuspendWithRawMonitorEnter.barrierLaunch) {
422
// tell main we are running
423
SuspendWithRawMonitorEnter.testState = SuspendWithRawMonitorEnter.TS_RESUMER_RUNNING;
424
SuspendWithRawMonitorEnter.barrierLaunch.notify();
425
}
426
SuspendWithRawMonitorEnter.logDebug("thread waiting");
427
while (SuspendWithRawMonitorEnter.testState != SuspendWithRawMonitorEnter.TS_READY_TO_RESUME) {
428
try {
429
// wait for main to tell us when to continue
430
SuspendWithRawMonitorEnter.barrierResumer.wait(0);
431
} catch (InterruptedException ex) {
432
}
433
}
434
}
435
SuspendWithRawMonitorEnter.logDebug("before enter threadLock");
436
retCode = rawMonitorEnter();
437
if (retCode != 0) {
438
throw new RuntimeException("error in JVMTI RawMonitorEnter: " +
439
"retCode=" + retCode);
440
}
441
SuspendWithRawMonitorEnter.logDebug("enter threadLock");
442
443
SuspendWithRawMonitorEnter.checkTestState(SuspendWithRawMonitorEnter.TS_READY_TO_RESUME);
444
SuspendWithRawMonitorEnter.testState = SuspendWithRawMonitorEnter.TS_CALL_RESUME;
445
446
// resume the contender thread so contender.join() can work
447
SuspendWithRawMonitorEnter.logDebug("before resume thread");
448
retCode = resumeThread(target);
449
if (retCode != 0) {
450
throw new RuntimeException("error in JVMTI ResumeThread: " +
451
"retCode=" + retCode);
452
}
453
SuspendWithRawMonitorEnter.logDebug("resumed thread");
454
455
SuspendWithRawMonitorEnter.logDebug("before exit threadLock");
456
retCode = rawMonitorExit();
457
if (retCode != 0) {
458
throw new RuntimeException("error in JVMTI RawMonitorExit: " +
459
"retCode=" + retCode);
460
}
461
SuspendWithRawMonitorEnter.logDebug("exit threadLock");
462
}
463
}
464
}
465
466