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