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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package com.sun.management.internal; 26 27 import java.util.concurrent.Executor; 28 import java.util.concurrent.ForkJoinPool; 29 import javax.management.ObjectName; 30 import jdk.management.VirtualThreadSchedulerMXBean; 31 import jdk.internal.access.JavaLangAccess; 32 import jdk.internal.access.SharedSecrets; 33 import jdk.internal.vm.ContinuationSupport; 34 import sun.management.Util; 35 36 /** 37 * Provides the implementation of the management interface for the JDK's default virtual 38 * thread scheduler. 39 */ 40 public class VirtualThreadSchedulerImpls { 41 private VirtualThreadSchedulerImpls() { 42 } 43 44 public static VirtualThreadSchedulerMXBean create() { 45 if (ContinuationSupport.isSupported()) { 46 return new VirtualThreadSchedulerImpl(); 47 } else { 48 return new BoundVirtualThreadSchedulerImpl(); 49 } 50 } 51 52 /** 53 * Base implementation of VirtualThreadSchedulerMXBean. 54 */ 55 private abstract static class BaseVirtualThreadSchedulerImpl 56 implements VirtualThreadSchedulerMXBean { 57 58 @Override 59 public final ObjectName getObjectName() { 60 return Util.newObjectName("jdk.management:type=VirtualThreadScheduler"); 61 } 62 63 @Override 64 public String toString() { 65 var sb = new StringBuilder("[parallelism="); 66 sb.append(getParallelism()); 67 append(sb, "size", getPoolSize()); 68 append(sb, "mounted", getMountedVirtualThreadCount()); 69 append(sb, "queued", getQueuedVirtualThreadCount()); 70 sb.append(']'); 71 return sb.toString(); 72 } 73 74 private void append(StringBuilder sb, String name, long value) { 75 sb.append(", ").append(name).append('='); 76 if (value >= 0) { 77 sb.append(value); 78 } else { 79 sb.append("<unavailable>"); 80 } 81 } 82 } 83 84 /** 85 * Implementation of VirtualThreadSchedulerMXBean when virtual threads are 86 * implemented with continuations + scheduler. 87 */ 88 private static final class VirtualThreadSchedulerImpl extends BaseVirtualThreadSchedulerImpl { 89 /** 90 * Holder class for scheduler. 91 */ 92 private static class Scheduler { 93 private static final Executor scheduler = 94 SharedSecrets.getJavaLangAccess().virtualThreadDefaultScheduler(); 95 static Executor instance() { 96 return scheduler; 97 } 98 } 99 100 @Override 101 public int getParallelism() { 102 if (Scheduler.instance() instanceof ForkJoinPool pool) { 103 return pool.getParallelism(); 104 } 105 throw new InternalError(); // should not get here 106 } 107 108 @Override 109 public void setParallelism(int size) { 110 if (Scheduler.instance() instanceof ForkJoinPool pool) { 111 pool.setParallelism(size); 112 if (pool.getPoolSize() < size) { 113 // FJ worker thread creation is on-demand 114 Thread.startVirtualThread(() -> { }); 115 } 116 117 return; 118 } 119 throw new UnsupportedOperationException(); // should not get here 120 } 121 122 @Override 123 public int getPoolSize() { 124 if (Scheduler.instance() instanceof ForkJoinPool pool) { 125 return pool.getPoolSize(); 126 } 127 return -1; // should not get here 128 } 129 130 @Override 131 public int getMountedVirtualThreadCount() { 132 if (Scheduler.instance() instanceof ForkJoinPool pool) { 133 return pool.getActiveThreadCount(); 134 } 135 return -1; // should not get here 136 } 137 138 @Override 139 public long getQueuedVirtualThreadCount() { 140 if (Scheduler.instance() instanceof ForkJoinPool pool) { 141 return pool.getQueuedTaskCount() + pool.getQueuedSubmissionCount(); 142 } 143 return -1L; // should not get here 144 } 145 } 146 147 /** 148 * Implementation of VirtualThreadSchedulerMXBean when virtual threads are backed 149 * by platform threads. 150 */ 151 private static final class BoundVirtualThreadSchedulerImpl extends BaseVirtualThreadSchedulerImpl { 152 @Override 153 public int getParallelism() { 154 return Integer.MAX_VALUE; 155 } 156 157 @Override 158 public void setParallelism(int size) { 159 throw new UnsupportedOperationException(); 160 } 161 162 @Override 163 public int getPoolSize() { 164 return -1; 165 } 166 167 @Override 168 public int getMountedVirtualThreadCount() { 169 return -1; 170 } 171 172 @Override 173 public long getQueuedVirtualThreadCount() { 174 return -1L; 175 } 176 } 177 } 178