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