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.SharedSecrets;
 31 import jdk.internal.vm.ContinuationSupport;
 32 import sun.management.Util;
 33 
 34 /**
 35  * Provides the implementation of the management interface for the JDK's default virtual
 36  * thread scheduler.
 37  */
 38 public class VirtualThreadSchedulerImpls {
 39     private VirtualThreadSchedulerImpls() {
 40     }
 41 
 42     public static VirtualThreadSchedulerMXBean create() {
 43         if (ContinuationSupport.isSupported()) {
 44             return new VirtualThreadSchedulerImpl();
 45         } else {
 46             return new BoundVirtualThreadSchedulerImpl();
 47         }
 48     }
 49 
 50     /**
 51      * Base implementation of VirtualThreadSchedulerMXBean.
 52      */
 53     private abstract static class BaseVirtualThreadSchedulerImpl
 54             implements VirtualThreadSchedulerMXBean {
 55 
 56         @Override
 57         public final ObjectName getObjectName() {
 58             return Util.newObjectName("jdk.management:type=VirtualThreadScheduler");
 59         }
 60 
 61         @Override
 62         public String toString() {
 63             var sb = new StringBuilder("[parallelism=");
 64             sb.append(getParallelism());
 65             append(sb, "size", getPoolSize());
 66             append(sb, "mounted", getMountedVirtualThreadCount());
 67             append(sb, "queued", getQueuedVirtualThreadCount());
 68             sb.append(']');
 69             return sb.toString();
 70         }
 71 
 72         private void append(StringBuilder sb, String name, long value) {
 73             sb.append(", ").append(name).append('=');
 74             if (value >= 0) {
 75                 sb.append(value);
 76             } else {
 77                 sb.append("<unavailable>");
 78             }
 79         }
 80     }
 81 
 82     /**
 83      * Implementation of VirtualThreadSchedulerMXBean when virtual threads are
 84      * implemented with continuations + scheduler.
 85      */
 86     private static final class VirtualThreadSchedulerImpl extends BaseVirtualThreadSchedulerImpl {
 87         /**
 88          * Holder class for scheduler.
 89          */
 90         private static class Scheduler {
 91             private static final Thread.VirtualThreadScheduler SCHEDULER =
 92                 SharedSecrets.getJavaLangAccess().defaultVirtualThreadScheduler();
 93             static Thread.VirtualThreadScheduler instance() {
 94                 return SCHEDULER;
 95             }
 96         }
 97 
 98         @Override
 99         public int getParallelism() {
100             if (Scheduler.instance() instanceof ForkJoinPool pool) {
101                 return pool.getParallelism();
102             }
103             return -1;  // unknown
104         }
105 
106         @Override
107         public void setParallelism(int size) {
108             if (Scheduler.instance() instanceof ForkJoinPool pool) {
109                 pool.setParallelism(size);
110                 if (pool.getPoolSize() < size) {
111                     // FJ worker thread creation is on-demand
112                     Thread.startVirtualThread(() -> { });
113                 }
114                 return;
115             }
116             throw new UnsupportedOperationException();
117         }
118 
119         @Override
120         public int getPoolSize() {
121             if (Scheduler.instance() instanceof ForkJoinPool pool) {
122                 return pool.getPoolSize();
123             }
124             return -1;  // unknown
125         }
126 
127         @Override
128         public int getMountedVirtualThreadCount() {
129             if (Scheduler.instance() instanceof ForkJoinPool pool) {
130                 return pool.getActiveThreadCount();
131             }
132             return -1;  // unknown
133         }
134 
135         @Override
136         public long getQueuedVirtualThreadCount() {
137             if (Scheduler.instance() instanceof ForkJoinPool pool) {
138                 return pool.getQueuedTaskCount() + pool.getQueuedSubmissionCount();
139             }
140             return -1L;  // unknown
141         }
142     }
143 
144     /**
145      * Implementation of VirtualThreadSchedulerMXBean when virtual threads are backed
146      * by platform threads.
147      */
148     private static final class BoundVirtualThreadSchedulerImpl extends BaseVirtualThreadSchedulerImpl {
149         @Override
150         public int getParallelism() {
151             return Integer.MAX_VALUE;
152         }
153 
154         @Override
155         public void setParallelism(int size) {
156             throw new UnsupportedOperationException();
157         }
158 
159         @Override
160         public int getPoolSize() {
161             return -1;
162         }
163 
164         @Override
165         public int getMountedVirtualThreadCount() {
166             return -1;
167         }
168 
169         @Override
170         public long getQueuedVirtualThreadCount() {
171             return -1L;
172         }
173     }
174 }
175