-
Notifications
You must be signed in to change notification settings - Fork 232
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
8231595: [TEST] develop a test case for SuspendThreadList including c…
…urrent thread Extend test coverage for SuspendThreadList Backport-of: 4091899
- Loading branch information
Showing
2 changed files
with
431 additions
and
0 deletions.
There are no files selected for viewing
222 changes: 222 additions & 0 deletions
222
...hotspot/jtreg/serviceability/jvmti/SuspendWithCurrentThread/SuspendWithCurrentThread.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,222 @@ | ||
/* | ||
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. | ||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
* | ||
* This code is free software; you can redistribute it and/or modify it | ||
* under the terms of the GNU General Public License version 2 only, as | ||
* published by the Free Software Foundation. | ||
* | ||
* This code is distributed in the hope that it will be useful, but WITHOUT | ||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
* version 2 for more details (a copy is included in the LICENSE file that | ||
* accompanied this code). | ||
* | ||
* You should have received a copy of the GNU General Public License version | ||
* 2 along with this work; if not, write to the Free Software Foundation, | ||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | ||
* | ||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | ||
* or visit www.oracle.com if you need additional information or have any | ||
* questions. | ||
*/ | ||
|
||
/* | ||
* @test | ||
* @bug 8231595 | ||
* @summary [TEST] develop a test case for SuspendThreadList including current thread | ||
* @library /test/lib | ||
* @compile SuspendWithCurrentThread.java | ||
* @run main/othervm/native -agentlib:SuspendWithCurrentThread SuspendWithCurrentThread SuspenderIndex=first | ||
* @run main/othervm/native -agentlib:SuspendWithCurrentThread SuspendWithCurrentThread SuspenderIndex=last | ||
*/ | ||
|
||
import java.io.PrintStream; | ||
|
||
public class SuspendWithCurrentThread { | ||
private static final String AGENT_LIB = "SuspendWithCurrentThread"; | ||
private static final String SUSPENDER_OPT = "SuspenderIndex="; | ||
private static final int THREADS_COUNT = 10; | ||
|
||
private static void log(String msg) { System.out.println(msg); } | ||
|
||
private static native void registerTestedThreads(Thread[] threads); | ||
private static native boolean checkTestedThreadsSuspended(); | ||
private static native void resumeTestedThreads(); | ||
private static native void releaseTestedThreadsInfo(); | ||
|
||
// The suspender thread index defines the thread which has to suspend | ||
// the tested threads including itself with the JVMTI SuspendThreadList | ||
private static int suspenderIndex; | ||
|
||
public static void main(String args[]) throws Exception { | ||
try { | ||
System.loadLibrary(AGENT_LIB); | ||
log("Loaded library: " + AGENT_LIB); | ||
} catch (UnsatisfiedLinkError ule) { | ||
log("Failed to load library: " + AGENT_LIB); | ||
log("java.library.path: " + System.getProperty("java.library.path")); | ||
throw ule; | ||
} | ||
if (args.length != 1) { | ||
throw new RuntimeException("Main: wrong arguments count: " + args.length + ", expected: 1"); | ||
} | ||
String arg = args[0]; | ||
if (arg.equals(SUSPENDER_OPT + "first")) { | ||
suspenderIndex = 0; | ||
} else if (arg.equals(SUSPENDER_OPT + "last")) { | ||
suspenderIndex = THREADS_COUNT - 1; | ||
} else { | ||
throw new RuntimeException("Main: wrong argument: " + arg + ", expected: SuspenderIndex={first|last}"); | ||
} | ||
log("Main: suspenderIndex: " + suspenderIndex); | ||
|
||
SuspendWithCurrentThread test = new SuspendWithCurrentThread(); | ||
test.run(); | ||
} | ||
|
||
private ThreadToSuspend[] startTestedThreads(int threadsCount) throws RuntimeException { | ||
ThreadToSuspend[]threads = new ThreadToSuspend[threadsCount]; | ||
|
||
// create tested threads | ||
for (int i = 0; i < threads.length; i++) { | ||
threads[i] = new ThreadToSuspend("ThreadToSuspend#" + i, | ||
i == suspenderIndex // isSuspender | ||
); | ||
} | ||
log("Main: starting tested threads"); | ||
for (int i = 0; i < threads.length; i++) { | ||
threads[i].start(); | ||
if (!threads[i].checkReady()) { | ||
throw new RuntimeException("Main: unable to prepare tested thread: " + threads[i]); | ||
} | ||
} | ||
log("Main: tested threads started"); | ||
|
||
registerTestedThreads(threads); | ||
return threads; | ||
} | ||
|
||
private boolean checkSuspendedStatus() throws RuntimeException { | ||
log("Main: checking all tested threads have been suspended"); | ||
return checkTestedThreadsSuspended(); | ||
} | ||
|
||
/* The test does the following steps: | ||
* - main thread starts several (THREADS_COUNT) ThreadToSuspend tested threads | ||
* - main thread waits for threads to be ready with the thread.checkReady() | ||
* - main thread registers tested threads within the native agent library | ||
* with the native method registerTestedThreads() | ||
* - main thread triggers the suspender tested thread with the | ||
* ThreadToSuspend.setAllThreadsReady() to suspend tested threads | ||
* - suspender thread suspends tested threads including itself with the native | ||
* method suspendTestedThreads() (uses the JVMTI SuspendThreadList function) | ||
* - main thread checks tested threads suspended status with the native method | ||
* checkSuspendedStatus(); the tested threads are expected to have suspended status | ||
* - main thread resumes tested threads with the native method resumeTestedThreads() | ||
* - main thread releases tested threads with the native method releaseTestedThreads() | ||
* - main thread triggers the tested threads to finish with the thread.letFinish() | ||
*/ | ||
private void run() throws Exception { | ||
ThreadToSuspend[] threads = null; // tested threads | ||
|
||
log("Main: started"); | ||
try { | ||
threads = startTestedThreads(THREADS_COUNT); | ||
|
||
log("Main: trigger " + threads[suspenderIndex].getName() + | ||
" to suspend all tested threads including itself"); | ||
ThreadToSuspend.setAllThreadsReady(); | ||
|
||
if (!checkSuspendedStatus()) { | ||
throw new RuntimeException("Main: FAILED status returned from checkTestedThreadsSuspended"); | ||
} | ||
|
||
log("Main: resuming all tested threads"); | ||
resumeTestedThreads(); | ||
} finally { | ||
// let threads to finish | ||
for (int i = 0; i < threads.length; i++) { | ||
threads[i].letFinish(); | ||
} | ||
log("Main: tested threads finished"); | ||
} | ||
|
||
// wait for threads to finish | ||
log("Main: joining tested threads"); | ||
try { | ||
for (int i = 0; i < threads.length; i++) { | ||
threads[i].join(); | ||
} | ||
log("Main: tested thread joined"); | ||
} catch (InterruptedException e) { | ||
throw new RuntimeException(e); | ||
} | ||
log("Main: releasing tested threads native info"); | ||
releaseTestedThreadsInfo(); | ||
|
||
log("Main: finished"); | ||
} | ||
} | ||
|
||
/* =================================================================== */ | ||
|
||
// tested threads | ||
class ThreadToSuspend extends Thread { | ||
private static void log(String msg) { System.out.println(msg); } | ||
|
||
private static native void init(); | ||
private static native void suspendTestedThreads(); | ||
private static volatile boolean allThreadsReady = false; | ||
|
||
public static void setAllThreadsReady() { | ||
allThreadsReady = true; | ||
} | ||
|
||
private volatile boolean threadReady = false; | ||
private volatile boolean shouldFinish = false; | ||
private boolean isSuspender = false; | ||
|
||
// make thread with specific name | ||
public ThreadToSuspend(String name, boolean isSuspender) { | ||
super(name); | ||
this.isSuspender = isSuspender; | ||
} | ||
|
||
// run thread continuously | ||
public void run() { | ||
boolean needSuspend = true; | ||
|
||
if (isSuspender) { | ||
init(); | ||
} | ||
threadReady = true; | ||
|
||
// run in a loop | ||
while (!shouldFinish) { | ||
if (isSuspender && needSuspend && allThreadsReady) { | ||
log(getName() + ": before suspending all tested threads including myself"); | ||
needSuspend = false; | ||
suspendTestedThreads(); | ||
log(getName() + ": after suspending all tested threads including myself"); | ||
} | ||
} | ||
} | ||
|
||
// check if thread is ready | ||
public boolean checkReady() { | ||
try { | ||
while (!threadReady) { | ||
sleep(1); | ||
} | ||
} catch (InterruptedException e) { | ||
throw new RuntimeException("checkReady: sleep was interrupted\n\t" + e); | ||
} | ||
return threadReady; | ||
} | ||
|
||
// let thread to finish | ||
public void letFinish() { | ||
shouldFinish = true; | ||
} | ||
} |
Oops, something went wrong.
4c27fa0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review
Issues