1 /* 2 * Copyright (c) 2021, 2025, 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 26 package jdk.internal.vm; 27 28 import java.util.Objects; 29 import java.util.stream.Stream; 30 31 /** 32 * A container of threads. 33 */ 34 public abstract class ThreadContainer extends StackableScope { 35 36 /** 37 * Creates a ThreadContainer. 38 * @param shared true for a shared container, false for a container 39 * owned by the current thread 40 */ 41 protected ThreadContainer(boolean shared) { 42 super(shared); 43 } 44 45 /** 46 * Return the name of this container, may be null. 47 */ 48 public String name() { 49 return null; 50 } 51 52 /** 53 * Returns the parent of this container or null if this is the root container. 54 */ 55 public ThreadContainer parent() { 56 return ThreadContainers.parent(this); 57 } 58 59 /** 60 * Return the stream of children of this container. 61 */ 62 public final Stream<ThreadContainer> children() { 63 return ThreadContainers.children(this); 64 } 65 66 /** 67 * Return a count of the number of threads in this container. 68 */ 69 public long threadCount() { 70 return threads().mapToLong(e -> 1L).sum(); 71 } 72 73 /** 74 * Returns a stream of the live threads in this container. 75 */ 76 public abstract Stream<Thread> threads(); 77 78 /** 79 * Invoked by {@code add} to add a thread to this container before it starts. 80 */ 81 protected void onStart(Thread thread) { 82 } 83 84 /** 85 * Invoked by {@code remove} to remove a thread from this container when it 86 * terminates (or failed to start). 87 */ 88 protected void onExit(Thread thread) { 89 } 90 91 /** 92 * Adds a thread to this container. This method should be invoked before the 93 * thread executes. 94 */ 95 public final void add(Thread thread) { 96 // Prevent a virtual thread from being preempted as this could potentially 97 // deadlock with a carrier is removing a virtual thread from the container 98 boolean pinned = ContinuationSupport.pinIfSupported(); 99 try { 100 onStart(thread); 101 } finally { 102 if (pinned) Continuation.unpin(); 103 } 104 } 105 106 /** 107 * Remove a thread from this container. This method can be invoked by the thread 108 * itself as it terminates, or it can be invoked by another thread after the given 109 * thread has terminated (or failed to start). 110 */ 111 public final void remove(Thread thread) { 112 // Prevent a virtual thread from being preempted as this could potentially 113 // deadlock with a carrier is removing a virtual thread from the container 114 boolean pinned = ContinuationSupport.pinIfSupported(); 115 try { 116 onExit(thread); 117 } finally { 118 if (pinned) Continuation.unpin(); 119 } 120 } 121 122 /** 123 * The scoped values captured when the thread container was created. 124 */ 125 public ScopedValueContainer.BindingsSnapshot scopedValueBindings() { 126 return null; 127 } 128 129 @Override 130 public String toString() { 131 String name = name(); 132 if (name != null && name.indexOf('@') >= 0) { 133 return name; 134 } else { 135 String id = Objects.toIdentityString(this); 136 return (name != null) ? name + "/" + id : id; 137 } 138 } 139 }