test/hotspot/jtreg/serviceability/jvmti/SuspendWithCurrentThread/SuspendWithCurrentThread.java
changeset 58530 865c889ce351
equal deleted inserted replaced
58529:36cdb1cab7b0 58530:865c889ce351
       
     1 /*
       
     2  * Copyright (c) 2019, 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 8231595
       
    27  * @summary [TEST] develop a test case for SuspendThreadList including current thread
       
    28  * @library /test/lib
       
    29  * @compile SuspendWithCurrentThread.java
       
    30  * @run main/othervm/native -agentlib:SuspendWithCurrentThread SuspendWithCurrentThread SuspenderIndex=first
       
    31  * @run main/othervm/native -agentlib:SuspendWithCurrentThread SuspendWithCurrentThread SuspenderIndex=last
       
    32  */
       
    33 
       
    34 import java.io.PrintStream;
       
    35 
       
    36 public class SuspendWithCurrentThread {
       
    37     private static final String AGENT_LIB = "SuspendWithCurrentThread";
       
    38     private static final String SUSPENDER_OPT = "SuspenderIndex=";
       
    39     private static final int THREADS_COUNT = 10;
       
    40 
       
    41     private static void log(String msg) { System.out.println(msg); }
       
    42 
       
    43     private static native void    registerTestedThreads(Thread[] threads);
       
    44     private static native boolean checkTestedThreadsSuspended();
       
    45     private static native void    resumeTestedThreads();
       
    46     private static native void    releaseTestedThreadsInfo();
       
    47 
       
    48     // The suspender thread index defines the thread which has to suspend
       
    49     // the tested threads including itself with the JVMTI SuspendThreadList
       
    50     private static int suspenderIndex;
       
    51 
       
    52     public static void main(String args[]) throws Exception {
       
    53         try {
       
    54             System.loadLibrary(AGENT_LIB);
       
    55             log("Loaded library: " + AGENT_LIB);
       
    56         } catch (UnsatisfiedLinkError ule) {
       
    57             log("Failed to load library: " + AGENT_LIB);
       
    58             log("java.library.path: " + System.getProperty("java.library.path"));
       
    59             throw ule;
       
    60         }
       
    61         if (args.length != 1) {
       
    62             throw new RuntimeException("Main: wrong arguments count: " + args.length + ", expected: 1");
       
    63         }
       
    64         String arg = args[0];
       
    65         if (arg.equals(SUSPENDER_OPT + "first")) {
       
    66             suspenderIndex = 0;
       
    67         } else if (arg.equals(SUSPENDER_OPT + "last")) {
       
    68             suspenderIndex = THREADS_COUNT - 1;
       
    69         } else {
       
    70             throw new RuntimeException("Main: wrong argument: " + arg + ", expected: SuspenderIndex={first|last}");
       
    71         }
       
    72         log("Main: suspenderIndex: " + suspenderIndex);
       
    73 
       
    74         SuspendWithCurrentThread test = new SuspendWithCurrentThread();
       
    75         test.run();
       
    76     }
       
    77 
       
    78     private ThreadToSuspend[] startTestedThreads(int threadsCount) throws RuntimeException  {
       
    79         ThreadToSuspend[]threads = new ThreadToSuspend[threadsCount];
       
    80 
       
    81         // create tested threads
       
    82         for (int i = 0; i < threads.length; i++) {
       
    83             threads[i] = new ThreadToSuspend("ThreadToSuspend#" + i,
       
    84                                              i == suspenderIndex // isSuspender
       
    85                                             );
       
    86         }
       
    87         log("Main: starting tested threads");
       
    88         for (int i = 0; i < threads.length; i++) {
       
    89             threads[i].start();
       
    90             if (!threads[i].checkReady()) {
       
    91                 throw new RuntimeException("Main: unable to prepare tested thread: " + threads[i]);
       
    92             }
       
    93         }
       
    94         log("Main: tested threads started");
       
    95 
       
    96         registerTestedThreads(threads);
       
    97         return threads;
       
    98     }
       
    99 
       
   100     private boolean checkSuspendedStatus() throws RuntimeException  {
       
   101         log("Main: checking all tested threads have been suspended");
       
   102         return checkTestedThreadsSuspended();
       
   103     }
       
   104 
       
   105     /* The test does the following steps:
       
   106      *  - main thread starts several (THREADS_COUNT) ThreadToSuspend tested threads
       
   107      *  - main thread waits for threads to be ready with the thread.checkReady()
       
   108      *  - main thread registers tested threads within the native agent library
       
   109      *    with the native method registerTestedThreads()
       
   110      *  - main thread triggers the suspender tested thread with the
       
   111      *    ThreadToSuspend.setAllThreadsReady() to suspend tested threads
       
   112      *  - suspender thread suspends tested threads including itself with the native
       
   113      *    method suspendTestedThreads() (uses the JVMTI SuspendThreadList function)
       
   114      *  - main thread checks tested threads suspended status with the native method
       
   115      *    checkSuspendedStatus(); the tested threads are expected to have suspended status
       
   116      *  - main thread resumes tested threads with the native method resumeTestedThreads()
       
   117      *  - main thread releases tested threads with the native method releaseTestedThreads()
       
   118      *  - main thread triggers the tested threads to finish with the thread.letFinish()
       
   119      */
       
   120     private void run() throws Exception {
       
   121         ThreadToSuspend[] threads = null; // tested threads
       
   122 
       
   123         log("Main: started");
       
   124         try {
       
   125             threads = startTestedThreads(THREADS_COUNT);
       
   126 
       
   127             log("Main: trigger " + threads[suspenderIndex].getName() +
       
   128                 " to suspend all tested threads including itself");
       
   129             ThreadToSuspend.setAllThreadsReady();
       
   130 
       
   131             if (!checkSuspendedStatus()) {
       
   132                 throw new RuntimeException("Main: FAILED status returned from checkTestedThreadsSuspended");
       
   133             }
       
   134 
       
   135             log("Main: resuming all tested threads");
       
   136             resumeTestedThreads();
       
   137         } finally {
       
   138             // let threads to finish
       
   139             for (int i = 0; i < threads.length; i++) {
       
   140                 threads[i].letFinish();
       
   141             }
       
   142             log("Main: tested threads finished");
       
   143         }
       
   144 
       
   145         // wait for threads to finish
       
   146         log("Main: joining tested threads");
       
   147         try {
       
   148             for (int i = 0; i < threads.length; i++) {
       
   149                 threads[i].join();
       
   150             }
       
   151             log("Main: tested thread joined");
       
   152         } catch (InterruptedException e) {
       
   153             throw new RuntimeException(e);
       
   154         }
       
   155         log("Main: releasing tested threads native info");
       
   156         releaseTestedThreadsInfo();
       
   157 
       
   158         log("Main: finished");
       
   159     }
       
   160 }
       
   161 
       
   162 /* =================================================================== */
       
   163 
       
   164 // tested threads
       
   165 class ThreadToSuspend extends Thread {
       
   166     private static void log(String msg) { System.out.println(msg); }
       
   167 
       
   168     private static native void init();
       
   169     private static native void suspendTestedThreads();
       
   170     private static volatile boolean allThreadsReady = false;
       
   171 
       
   172     public static void setAllThreadsReady() {
       
   173         allThreadsReady = true;
       
   174     }
       
   175 
       
   176     private volatile boolean threadReady = false;
       
   177     private volatile boolean shouldFinish = false;
       
   178     private boolean isSuspender = false;
       
   179 
       
   180     // make thread with specific name
       
   181     public ThreadToSuspend(String name, boolean isSuspender) {
       
   182         super(name);
       
   183         this.isSuspender = isSuspender;
       
   184     }
       
   185 
       
   186     // run thread continuously
       
   187     public void run() {
       
   188         boolean needSuspend = true;
       
   189 
       
   190         if (isSuspender) {
       
   191             init();
       
   192         }
       
   193         threadReady = true;
       
   194 
       
   195         // run in a loop
       
   196         while (!shouldFinish) {
       
   197             if (isSuspender && needSuspend && allThreadsReady) {
       
   198                 log(getName() + ": before suspending all tested threads including myself");
       
   199                 needSuspend = false;
       
   200                 suspendTestedThreads();
       
   201                 log(getName() + ": after suspending all tested threads including myself");
       
   202             }
       
   203         }
       
   204     }
       
   205 
       
   206     // check if thread is ready
       
   207     public boolean checkReady() {
       
   208         try {
       
   209             while (!threadReady) {
       
   210                 sleep(1);
       
   211             }
       
   212         } catch (InterruptedException e) {
       
   213             throw new RuntimeException("checkReady: sleep was interrupted\n\t" + e);
       
   214         }
       
   215         return threadReady;
       
   216     }
       
   217 
       
   218     // let thread to finish
       
   219     public void letFinish() {
       
   220         shouldFinish = true;
       
   221     }
       
   222 }