1 /* 2 * Copyright (c) 2023, 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 * @bug 8307365 27 * @summary Exercise JvmtiThreadState creation concurrently with terminating vthreads 28 * @requires vm.continuations 29 * @modules java.base/java.lang:+open 30 * @run main/othervm/native -agentlib:ThreadStateTest ThreadStateTest 31 */ 32 33 import java.util.concurrent.*; 34 import java.util.Arrays; 35 import java.util.ArrayList; 36 import java.util.List; 37 import java.lang.reflect.Constructor; 38 import java.lang.reflect.InvocationTargetException; 39 40 public class ThreadStateTest { 41 static final int VTHREAD_COUNT = 64; 42 43 private static native void setSingleSteppingMode(boolean enable); 44 private static native void setMonitorContendedMode(boolean enable); 45 private static native void testGetThreadState(Thread thread); 46 private static native void testGetThreadListStackTraces(Thread thread); 47 48 final Runnable FOO = () -> { 49 testGetThreadState(Thread.currentThread()); 50 testGetThreadListStackTraces(Thread.currentThread()); 51 Thread.yield(); 52 }; 53 54 private void runTest() throws Exception { 55 int tryCount = 150; 56 57 // Force creation of JvmtiThreadState on vthread start. 58 setMonitorContendedMode(true); 59 60 while (tryCount-- > 0) { 61 ExecutorService scheduler = Executors.newFixedThreadPool(8); 62 ThreadFactory factory = virtualThreadBuilder(scheduler).factory(); 63 64 List<Thread> virtualThreads = new ArrayList<>(); 65 for (int i = 0; i < VTHREAD_COUNT; i++) { 66 Thread vt = factory.newThread(FOO); 67 vt.setName("VT-" + i); 68 virtualThreads.add(vt); 69 } 70 71 for (Thread t : virtualThreads) { 72 t.start(); 73 } 74 75 // Give some time for vthreads to finish. 76 Thread.sleep(10); 77 78 // Trigger race of JvmtiThreadState creation with terminating vthreads. 79 setMonitorContendedMode(false); 80 setMonitorContendedMode(true); 81 82 for (Thread t : virtualThreads) { 83 t.join(); 84 } 85 // Let all carriers go away. 86 scheduler.shutdown(); 87 Thread.sleep(20); 88 89 // Check that looping over all JvmtiThreadStates works fine. 90 setSingleSteppingMode(true); 91 92 // Reset for next iteration 93 setSingleSteppingMode(false); 94 } 95 } 96 97 public static void main(String[] args) throws Exception { 98 ThreadStateTest obj = new ThreadStateTest(); 99 obj.runTest(); 100 } 101 102 private static Thread.Builder.OfVirtual virtualThreadBuilder(Executor scheduler) { 103 Thread.Builder.OfVirtual builder = Thread.ofVirtual(); 104 try { 105 Class<?> clazz = Class.forName("java.lang.ThreadBuilders$VirtualThreadBuilder"); 106 Constructor<?> ctor = clazz.getDeclaredConstructor(Executor.class); 107 ctor.setAccessible(true); 108 return (Thread.Builder.OfVirtual) ctor.newInstance(scheduler); 109 } catch (InvocationTargetException e) { 110 Throwable cause = e.getCause(); 111 if (cause instanceof RuntimeException re) { 112 throw re; 113 } 114 throw new RuntimeException(e); 115 } catch (Exception e) { 116 throw new RuntimeException(e); 117 } 118 } 119 }