1 /*
  2  * Copyright (c) 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  * @summary Test SuspendAllVirtualThreads/ResumeAllVirtualThreads
 27  * @library /test/lib
 28  * @compile --enable-preview -source ${jdk.version} SuspendResume2.java
 29  * @run driver jdk.test.lib.FileInstaller . .
 30  * @run main/othervm/native
 31  *      --enable-preview
 32  *      -Djava.util.concurrent.ForkJoinPool.common.parallelism=1
 33  *      -agentlib:SuspendResume2
 34  *      SuspendResume2
 35  */
 36 
 37 import java.io.PrintStream;
 38 import java.util.concurrent.*;
 39 import jdk.test.lib.jvmti.DebugeeClass;
 40 
 41 public class SuspendResume2 extends DebugeeClass {
 42 
 43     // load native library if required
 44     static {
 45         System.loadLibrary("SuspendResume2");
 46     }
 47 
 48     native static void TestSuspendResume();
 49     native static int GetStatus();
 50 
 51     static public void sleep(long millis) {
 52         try {
 53             Thread.sleep(millis);
 54         } catch (InterruptedException e) {
 55             throw new RuntimeException("Interruption in TestedThread.sleep: \n\t" + e);
 56         }
 57     }
 58 
 59     // run test from command line
 60     public static void main(String argv[]) {
 61         int status = run(argv, System.out);
 62         if (status != DebugeeClass.TEST_PASSED) {
 63             throw new RuntimeException("FAILED: unexpected status: " + status);
 64         }
 65     }
 66 
 67     public static int run(String argv[], PrintStream out) {
 68         return new SuspendResume2().runIt(argv, out);
 69     }
 70 
 71     private static final int VTHREADS_CNT = 20;
 72     int status = DebugeeClass.TEST_PASSED;
 73 
 74     // run debuggee
 75     public int runIt(String argv[], PrintStream out) {
 76         System.out.println("\n## Java: runIt: Starting threads");
 77         status = test_vthreads();
 78         if (status != DebugeeClass.TEST_PASSED) {
 79             System.out.println("\n## Java: runIt FAILED: status from native Agent: " + status);
 80         }
 81         return status;
 82     }
 83 
 84     private int test_vthreads() {
 85         TestedThread[] threads = new TestedThread[VTHREADS_CNT];
 86         Thread vts[] = new Thread[VTHREADS_CNT];
 87 
 88         for (int i = 0; i < VTHREADS_CNT; i++) {
 89             String name = "TestedThread" + i;
 90             TestedThread thread = new TestedThread(name);
 91             threads[i] = thread;
 92             vts[i] = start_thread(name, thread);
 93         }
 94 
 95         System.out.println("\n## Java: runIt: testing Suspend/Resume");
 96         TestSuspendResume();
 97 
 98         System.out.println("\n## Java: runIt: Finishing vthreads");
 99         try {
100             for (int i = 0; i < VTHREADS_CNT; i++) {
101                 // let thread to finish
102                 TestedThread thread = threads[i];
103                 thread.letFinish();
104                 vts[i].join();
105             }
106         } catch (InterruptedException e) {
107             throw new RuntimeException(e);
108         }
109         return GetStatus();
110     }
111 
112     Thread start_thread(String name, TestedThread thread) {
113         Thread vthread =  Thread.ofVirtual().name(name).start(thread);
114         thread.ensureReady(); // testing sync
115         System.out.println("## Java: started thread: " + name);
116         return vthread;
117     }
118 }
119 
120 // class for tested threads
121 class TestedThread extends Thread {
122     private volatile boolean threadReady = false;
123     private volatile boolean shouldFinish = false;
124 
125     // make thread with specific name
126     public TestedThread(String name) {
127         super(name);
128     }
129 
130     // run thread continuously
131     public void run() {
132         // run in a loop
133         threadReady = true;
134         int i = 0;
135         int n = 1000;
136         while (!shouldFinish) {
137             if (n <= 0) {
138                 n = 1000;
139                 SuspendResume2.sleep(1);
140             }
141             if (i > n) {
142                 i = 0;
143                 n = n - 1;
144             }
145             i = i + 1;
146         }
147     }
148 
149     // ensure thread is ready
150     public void ensureReady() {
151         try {
152             while (!threadReady) {
153                 sleep(1);
154             }
155         } catch (InterruptedException e) {
156             throw new RuntimeException("Interruption while preparing tested thread: \n\t" + e);
157         }
158     }
159 
160     // let thread to finish
161     public void letFinish() {
162         shouldFinish = true;
163     }
164 }