1 /*
  2  * Copyright (c) 2019, 2020, 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 /**
 26  * @test
 27  * @summary Test JVMTI Monitor functions for virtual threads
 28  * @compile --enable-preview -source ${jdk.version} VThreadMonitorTest.java
 29  * @run main/othervm/native --enable-preview -agentlib:VThreadMonitorTest VThreadMonitorTest
 30  */
 31 
 32 import java.io.PrintStream;
 33 
 34 class MonitorClass0 {}
 35 class MonitorClass2 {}
 36 
 37 public class VThreadMonitorTest {
 38 
 39     static {
 40         try {
 41             System.loadLibrary("VThreadMonitorTest");
 42         } catch (UnsatisfiedLinkError ule) {
 43             System.err.println("Could not load VThreadMonitorTest library");
 44             System.err.println("java.library.path: "
 45                                + System.getProperty("java.library.path"));
 46             throw ule;
 47         }
 48     }
 49     private static native boolean hasEventPosted();
 50     private static native void checkContendedMonitor(Thread thread, Object mon1, Object mon2);
 51     private static native int check();
 52 
 53     private static void log(String str) { System.out.println(str); }
 54     private static String thrName() { return Thread.currentThread().getName(); }
 55 
 56     private static final Object lock0 = new MonitorClass0();
 57     private static final Object lock1 = new Object();
 58     private static final Object lock2 = new MonitorClass2();
 59 
 60     static void sleep(long millis) {
 61         try {
 62             Thread.sleep(millis);
 63         } catch (InterruptedException ie) {
 64         }
 65     }
 66 
 67     static void m0() {
 68         synchronized (lock0) {
 69             // log(thrName() +" entered sync section with lock0\n");
 70         }
 71     }
 72     static void m1() {
 73         synchronized (lock1) {
 74             // log(thrName() +" entered sync section with lock1");
 75             m0();
 76         }
 77     }
 78     static void m2() {
 79         synchronized (lock2) {
 80             // log(thrName() +" entered sync section with lock2");
 81             m1();
 82         }
 83     }
 84 
 85     static final Runnable VT = () -> {
 86         m2();
 87     };
 88 
 89     static private int counter = 0;
 90 
 91     static final Runnable SLEEPING_VT = () -> {
 92         for (int i = 0; i < 40; i++) {
 93             for (int j = 0; j < 1000; j++) {
 94                 counter += j;
 95                 counter %= 100;
 96             }
 97             sleep(1);
 98         }
 99     };
100 
101     static final int VT_TOTAL = 10;
102     static final int VT_COUNT = 2;
103 
104     public static void main(String[] args) throws Exception {
105         Thread[] vthreads = new Thread[VT_TOTAL];
106         Thread.Builder builder = Thread.ofVirtual().name("VirtualThread-", 0);
107 
108         // Create VT threads.
109         for (int i = 0; i < VT_COUNT; i++) {
110             vthreads[i] = builder.unstarted(VT);
111         }
112         // Create SLEEPING_VT threads.
113         for (int i = VT_COUNT; i < VT_TOTAL; i++) {
114             vthreads[i] = builder.unstarted(SLEEPING_VT);
115         }
116 
117         // Make sure one of the VT threads is blocked on monitor lock0.
118         synchronized (lock0) {
119             log("Main starting VT virtual threads");
120             for (int i = 0; i < VT_TOTAL; i++) {
121                 vthreads[i].start();
122             }
123             // Wait for the MonitorContendedEnter event.
124             while (!hasEventPosted()) {
125                 log("Main thread is waiting for event\n");
126                 sleep(10);
127             }
128             // One of the VT threads is blocked at lock0, another - at lock2.
129             for (int i = 0; i < VT_COUNT; i++) {
130                 checkContendedMonitor(vthreads[i], lock0, lock2);
131             }
132             // SLEEPING_VT threads can be contended on some system  monitors,
133             // so we should not check they have no contention.
134         }
135 
136         for (int i = 0; i < VT_TOTAL; i++) {
137            vthreads[i].join();
138         }
139 
140         if (check() != 0) {
141             throw new RuntimeException("FAILED status returned from the agent");
142         }
143     }
144 }