1 /* 2 * Copyright (c) 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 virtual threads entering a lot of monitors with contention 27 * @requires os.arch=="amd64" | os.arch=="x86_64" | os.arch=="aarch64" 28 * @library /test/lib 29 * @run main/othervm LotsOfContendedMonitorEnter 30 */ 31 32 /* 33 * @test id=LM_LEGACY 34 * @requires os.arch=="amd64" | os.arch=="x86_64" | os.arch=="aarch64" 35 * @library /test/lib 36 * @run main/othervm -XX:LockingMode=1 LotsOfContendedMonitorEnter 37 */ 38 39 /* 40 * @test id=LM_LIGHTWEIGHT 41 * @requires os.arch=="amd64" | os.arch=="x86_64" | os.arch=="aarch64" 42 * @library /test/lib 43 * @run main/othervm -XX:LockingMode=2 LotsOfContendedMonitorEnter 44 */ 45 46 import java.util.concurrent.CountDownLatch; 47 import jdk.test.lib.thread.VThreadRunner; 48 49 public class LotsOfContendedMonitorEnter { 50 51 public static void main(String[] args) throws Exception { 52 int depth; 53 if (args.length > 0) { 54 depth = Integer.parseInt(args[0]); 55 } else { 56 depth = 1024; 57 } 58 VThreadRunner.run(() -> testContendedEnter(depth)); 59 } 60 61 /** 62 * Enter the monitor for a new object, racing with another virtual thread that 63 * attempts to enter around the same time, then repeat to the given depth. 64 */ 65 private static void testContendedEnter(int depthRemaining) throws Exception { 66 if (depthRemaining > 0) { 67 var lock = new Object(); 68 69 // start thread to enter monitor for brief period, then enters again when signalled 70 var started = new CountDownLatch(1); 71 var signal = new CountDownLatch(1); 72 var thread = Thread.ofVirtual().start(() -> { 73 started.countDown(); 74 75 // enter, may be contended 76 synchronized (lock) { 77 Thread.onSpinWait(); 78 } 79 80 // wait to be signalled 81 try { 82 signal.await(); 83 } catch (InterruptedException e) { } 84 85 // enter again, this will block until the main thread releases 86 synchronized (lock) { 87 // do nothing 88 } 89 }); 90 try { 91 // wait for thread to start 92 started.await(); 93 94 // enter, may be contended 95 synchronized (lock) { 96 // signal thread to enter monitor again, it should block 97 signal.countDown(); 98 await(thread, Thread.State.BLOCKED); 99 testContendedEnter(depthRemaining - 1); 100 } 101 } finally { 102 thread.join(); 103 } 104 } 105 } 106 107 /** 108 * Waits for the given thread to reach a given state. 109 */ 110 private static void await(Thread thread, Thread.State expectedState) { 111 Thread.State state = thread.getState(); 112 while (state != expectedState) { 113 assert state != Thread.State.TERMINATED : "Thread has terminated"; 114 Thread.yield(); 115 state = thread.getState(); 116 } 117 } 118 }