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.ForkJoinPool;
 28 import javax.management.ObjectName;
 29 import jdk.management.VirtualThreadSchedulerMXBean;
 30 import jdk.internal.access.JavaLangAccess;
 31 import jdk.internal.access.SharedSecrets;
 32 import jdk.internal.vm.ContinuationSupport;
 33 import sun.management.Util;
 34 
 35 /**
 36  * Provides the implementation of the management interface for the JDK's virtual thread scheduler.
 37  */
 38 public class VirtualThreadSchedulerImpls {
 39     private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
 40 
 41     private VirtualThreadSchedulerImpls() {
 42     }
 43 
 44     /**
 45      * Creates the VirtualThreadSchedulerMXBean.
 46      */
 47     public static VirtualThreadSchedulerMXBean create() {
 48         // -XX:-VMContinuations
 49         if (!ContinuationSupport.isSupported()) {
 50             return new BoundVirtualThreadSchedulerImpl();
 51         }
 52 
 53         // built-in ForkJoinPool scheduler
 54         if (System.getProperty("jdk.virtualThreadScheduler.implClass") == null) {
 55             return new BuiltinVirtualThreadSchedulerImpl();
 56         }
 57 
 58         // custom scheduler implements VirtualThreadSchedulerMXBean
 59         if (JLA.defaultVirtualThreadScheduler() instanceof VirtualThreadSchedulerMXBean bean) {
 60             return bean;
 61         }
 62 
 63         // custom scheduler does not implement VirtualThreadSchedulerMXBean
 64         return new CustomVirtualThreadSchedulerImpl();
 65     }
 66 
 67     /**
 68      * Base implementation of VirtualThreadSchedulerMXBean.
 69      */
 70     private abstract static class BaseVirtualThreadSchedulerImpl
 71             implements VirtualThreadSchedulerMXBean {
 72 
 73         @Override
 74         public final ObjectName getObjectName() {
 75             return Util.newObjectName("jdk.management:type=VirtualThreadScheduler");
 76         }
 77 
 78         @Override
 79         public String toString() {
 80             var sb = new StringBuilder("[parallelism=");
 81             sb.append(getParallelism());
 82             append(sb, "size", getPoolSize());
 83             append(sb, "mounted", getMountedVirtualThreadCount());
 84             append(sb, "queued", getQueuedVirtualThreadCount());
 85             sb.append(']');
 86             return sb.toString();
 87         }
 88 
 89         private void append(StringBuilder sb, String name, long value) {
 90             sb.append(", ").append(name).append('=');
 91             if (value >= 0) {
 92                 sb.append(value);
 93             } else {
 94                 sb.append("<unavailable>");
 95             }
 96         }
 97     }
 98 
 99     /**
100      * Implementation of VirtualThreadSchedulerMXBean when virtual threads are
101      * implemented with continuations and the built-in ForkJoinPool scheduler.
102      */
103     private static final class BuiltinVirtualThreadSchedulerImpl
104             extends BaseVirtualThreadSchedulerImpl {
105 
106         private ForkJoinPool forkJoinPool() {
107             return (ForkJoinPool) JLA.builtinVirtualThreadScheduler();
108         }
109 
110         @Override
111         public int getParallelism() {
112             return forkJoinPool().getParallelism();
113         }
114 
115         @Override
116         public void setParallelism(int size) {
117             forkJoinPool().setParallelism(size);
118         }
119 
120         @Override
121         public int getPoolSize() {
122             return forkJoinPool().getPoolSize();
123         }
124 
125         @Override
126         public int getMountedVirtualThreadCount() {
127             return forkJoinPool().getActiveThreadCount();
128         }
129 
130         @Override
131         public long getQueuedVirtualThreadCount() {
132             ForkJoinPool p = forkJoinPool();
133             return p.getQueuedTaskCount() + p.getQueuedSubmissionCount();
134         }
135     }
136 
137     /**
138      * Implementation of VirtualThreadSchedulerMXBean when virtual threads are backed
139      * by platform threads.
140      */
141     private static final class BoundVirtualThreadSchedulerImpl
142             extends BaseVirtualThreadSchedulerImpl {
143         @Override
144         public int getParallelism() {
145             return Integer.MAX_VALUE;
146         }
147 
148         @Override
149         public void setParallelism(int size) {
150             throw new UnsupportedOperationException();
151         }
152 
153         @Override
154         public int getPoolSize() {
155             return -1;
156         }
157 
158         @Override
159         public int getMountedVirtualThreadCount() {
160             return -1;
161         }
162 
163         @Override
164         public long getQueuedVirtualThreadCount() {
165             return -1L;
166         }
167     }
168 
169     /**
170      * Implementation of VirtualThreadSchedulerMXBean when using a custom virtual
171      * thread scheduler that does not implement VirtualThreadSchedulerMXBean.
172      */
173     private static final class CustomVirtualThreadSchedulerImpl
174             extends BaseVirtualThreadSchedulerImpl {
175 
176         @Override
177         public int getParallelism() {
178             return 1;
179         }
180 
181         @Override
182         public void setParallelism(int size) {
183             throw new UnsupportedOperationException();
184         }
185 
186         @Override
187         public int getPoolSize() {
188             return -1;
189         }
190 
191         @Override
192         public int getMountedVirtualThreadCount() {
193             return -1;
194         }
195 
196         @Override
197         public long getQueuedVirtualThreadCount() {
198             return -1L;
199         }
200     }
201 }
202