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 package java.lang;
 26 
 27 import java.lang.Thread.Builder.OfPlatform;
 28 import java.lang.Thread.Builder.OfVirtual;
 29 import java.lang.Thread.UncaughtExceptionHandler;
 30 import java.lang.invoke.MethodHandles;
 31 import java.lang.invoke.VarHandle;
 32 import java.util.Locale;
 33 import java.util.Objects;
 34 import java.util.concurrent.ThreadFactory;
 35 import jdk.internal.misc.Unsafe;
 36 import jdk.internal.invoke.MhUtil;
 37 import jdk.internal.vm.ContinuationSupport;
 38 
 39 /**
 40  * Defines static methods to create platform and virtual thread builders.
 41  */
 42 class ThreadBuilders {
 43     private ThreadBuilders() { }
 44 
 45     /**
 46      * Base class for Thread.Builder implementations.
 47      */
 48     private static class BaseThreadBuilder {
 49         private String name;
 50         private long counter;
 51         private int characteristics;
 52         private UncaughtExceptionHandler uhe;
 53 
 54         String name() {
 55             return name;
 56         }
 57 
 58         long counter() {
 59             return counter;
 60         }
 61 
 62         int characteristics() {
 63             return characteristics;
 64         }
 65 
 66         UncaughtExceptionHandler uncaughtExceptionHandler() {
 67             return uhe;
 68         }
 69 
 70         String nextThreadName() {
 71             if (name != null && counter >= 0) {
 72                 return name + (counter++);
 73             } else {
 74                 return name;
 75             }
 76         }
 77 
 78         void setName(String name) {
 79             this.name = Objects.requireNonNull(name);
 80             this.counter = -1;
 81         }
 82 
 83         void setName(String prefix, long start) {
 84             Objects.requireNonNull(prefix);
 85             if (start < 0)
 86                 throw new IllegalArgumentException("'start' is negative");
 87             this.name = prefix;
 88             this.counter = start;
 89         }
 90 
 91         void setInheritInheritableThreadLocals(boolean inherit) {
 92             if (inherit) {
 93                 characteristics &= ~Thread.NO_INHERIT_THREAD_LOCALS;
 94             } else {
 95                 characteristics |= Thread.NO_INHERIT_THREAD_LOCALS;
 96             }
 97         }
 98 
 99         void setUncaughtExceptionHandler(UncaughtExceptionHandler ueh) {
100             this.uhe = Objects.requireNonNull(ueh);
101         }
102     }
103 
104     /**
105      * ThreadBuilder.OfPlatform implementation.
106      */
107     static final class PlatformThreadBuilder
108             extends BaseThreadBuilder implements OfPlatform {
109         private ThreadGroup group;
110         private boolean daemon;
111         private boolean daemonChanged;
112         private int priority;
113         private long stackSize;
114 
115         PlatformThreadBuilder() {
116         }
117 
118         @Override
119         String nextThreadName() {
120             String name = super.nextThreadName();
121             return (name != null) ? name : Thread.genThreadName();
122         }
123 
124         @Override
125         public OfPlatform name(String name) {
126             setName(name);
127             return this;
128         }
129 
130         @Override
131         public OfPlatform name(String prefix, long start) {
132             setName(prefix, start);
133             return this;
134         }
135 
136         @Override
137         public OfPlatform inheritInheritableThreadLocals(boolean inherit) {
138             setInheritInheritableThreadLocals(inherit);
139             return this;
140         }
141 
142         @Override
143         public OfPlatform uncaughtExceptionHandler(UncaughtExceptionHandler ueh) {
144             setUncaughtExceptionHandler(ueh);
145             return this;
146         }
147 
148         @Override
149         public OfPlatform group(ThreadGroup group) {
150             this.group = Objects.requireNonNull(group);
151             return this;
152         }
153 
154         @Override
155         public OfPlatform daemon(boolean on) {
156             daemon = on;
157             daemonChanged = true;
158             return this;
159         }
160 
161         @Override
162         public OfPlatform priority(int priority) {
163             if (priority < Thread.MIN_PRIORITY || priority > Thread.MAX_PRIORITY)
164                 throw new IllegalArgumentException();
165             this.priority = priority;
166             return this;
167         }
168 
169         @Override
170         public OfPlatform stackSize(long stackSize) {
171             if (stackSize < 0L)
172                 throw new IllegalArgumentException();
173             this.stackSize = stackSize;
174             return this;
175         }
176 
177         @Override
178         public Thread unstarted(Runnable task) {
179             Objects.requireNonNull(task);
180             String name = nextThreadName();
181             var thread = new Thread(group, name, characteristics(), task, stackSize);
182             if (daemonChanged)
183                 thread.daemon(daemon);
184             if (priority != 0)
185                 thread.priority(priority);
186             UncaughtExceptionHandler uhe = uncaughtExceptionHandler();
187             if (uhe != null)
188                 thread.uncaughtExceptionHandler(uhe);
189             return thread;
190         }
191 
192         @Override
193         public Thread start(Runnable task) {
194             Thread thread = unstarted(task);
195             thread.start();
196             return thread;
197         }
198 
199         @Override
200         public ThreadFactory factory() {
201             return new PlatformThreadFactory(group, name(), counter(), characteristics(),
202                     daemonChanged, daemon, priority, stackSize, uncaughtExceptionHandler());
203         }
204     }
205 
206     /**
207      * ThreadBuilder.OfVirtual implementation.
208      */
209     static final class VirtualThreadBuilder
210             extends BaseThreadBuilder implements OfVirtual {
211         private Thread.VirtualThreadScheduler scheduler;
212 
213         VirtualThreadBuilder() {
214         }
215 
216         @Override
217         public OfVirtual name(String name) {
218             setName(name);
219             return this;
220         }
221 
222         @Override
223         public OfVirtual name(String prefix, long start) {
224             setName(prefix, start);
225             return this;
226         }
227 
228         @Override
229         public OfVirtual inheritInheritableThreadLocals(boolean inherit) {
230             setInheritInheritableThreadLocals(inherit);
231             return this;
232         }
233 
234         @Override
235         public OfVirtual uncaughtExceptionHandler(UncaughtExceptionHandler ueh) {
236             setUncaughtExceptionHandler(ueh);
237             return this;
238         }
239 
240         Thread unstarted(Runnable task, Thread preferredCarrier) {
241             Objects.requireNonNull(task);
242             var thread = newVirtualThread(scheduler,
243                                           preferredCarrier,
244                                           nextThreadName(),
245                                           characteristics(),
246                                           task);
247             UncaughtExceptionHandler uhe = uncaughtExceptionHandler();
248             if (uhe != null)
249                 thread.uncaughtExceptionHandler(uhe);
250             return thread;
251         }
252 
253         @Override
254         public Thread unstarted(Runnable task) {
255             return unstarted(task, null);
256         }
257 
258         @Override
259         public Thread start(Runnable task) {
260             Thread thread = unstarted(task);
261             thread.start();
262             return thread;
263         }
264 
265         @Override
266         public ThreadFactory factory() {
267             return new VirtualThreadFactory(scheduler, name(), counter(), characteristics(),
268                     uncaughtExceptionHandler());
269         }
270     }
271 
272     /**
273      * Base ThreadFactory implementation.
274      */
275     private abstract static class BaseThreadFactory implements ThreadFactory {
276         private static final VarHandle COUNT = MhUtil.findVarHandle(
277                 MethodHandles.lookup(), "count", long.class);
278 
279         private final String name;
280         private final int characteristics;
281         private final UncaughtExceptionHandler uhe;
282 
283         private final boolean hasCounter;
284         private volatile long count;
285 
286         BaseThreadFactory(String name,
287                           long start,
288                           int characteristics,
289                           UncaughtExceptionHandler uhe)  {
290             this.name = name;
291             if (name != null && start >= 0) {
292                 this.hasCounter = true;
293                 this.count = start;
294             } else {
295                 this.hasCounter = false;
296             }
297             this.characteristics = characteristics;
298             this.uhe = uhe;
299         }
300 
301         int characteristics() {
302             return characteristics;
303         }
304 
305         UncaughtExceptionHandler uncaughtExceptionHandler() {
306             return uhe;
307         }
308 
309         String nextThreadName() {
310             if (hasCounter) {
311                 return name + (long) COUNT.getAndAdd(this, 1L);
312             } else {
313                 return name;
314             }
315         }
316     }
317 
318     /**
319      * ThreadFactory for platform threads.
320      */
321     private static class PlatformThreadFactory extends BaseThreadFactory {
322         private final ThreadGroup group;
323         private final boolean daemonChanged;
324         private final boolean daemon;
325         private final int priority;
326         private final long stackSize;
327 
328         PlatformThreadFactory(ThreadGroup group,
329                               String name,
330                               long start,
331                               int characteristics,
332                               boolean daemonChanged,
333                               boolean daemon,
334                               int priority,
335                               long stackSize,
336                               UncaughtExceptionHandler uhe) {
337             super(name, start, characteristics, uhe);
338             this.group = group;
339             this.daemonChanged = daemonChanged;
340             this.daemon = daemon;
341             this.priority = priority;
342             this.stackSize = stackSize;
343         }
344 
345         @Override
346         String nextThreadName() {
347             String name = super.nextThreadName();
348             return (name != null) ? name : Thread.genThreadName();
349         }
350 
351         @Override
352         public Thread newThread(Runnable task) {
353             Objects.requireNonNull(task);
354             String name = nextThreadName();
355             Thread thread = new Thread(group, name, characteristics(), task, stackSize);
356             if (daemonChanged)
357                 thread.daemon(daemon);
358             if (priority != 0)
359                 thread.priority(priority);
360             UncaughtExceptionHandler uhe = uncaughtExceptionHandler();
361             if (uhe != null)
362                 thread.uncaughtExceptionHandler(uhe);
363             return thread;
364         }
365     }
366 
367     /**
368      * ThreadFactory for virtual threads.
369      */
370     private static class VirtualThreadFactory extends BaseThreadFactory {
371         private final Thread.VirtualThreadScheduler scheduler;
372 
373         VirtualThreadFactory(Thread.VirtualThreadScheduler scheduler,
374                              String name,
375                              long start,
376                              int characteristics,
377                              UncaughtExceptionHandler uhe) {
378             super(name, start, characteristics, uhe);
379             this.scheduler = scheduler;
380         }
381 
382         @Override
383         public Thread newThread(Runnable task) {
384             Objects.requireNonNull(task);
385             String name = nextThreadName();
386             Thread thread = newVirtualThread(scheduler, null, name, characteristics(), task);
387             UncaughtExceptionHandler uhe = uncaughtExceptionHandler();
388             if (uhe != null)
389                 thread.uncaughtExceptionHandler(uhe);
390             return thread;
391         }
392     }
393 
394     /**
395      * Creates a new virtual thread to run the given task.
396      */
397     private static Thread newVirtualThread(Thread.VirtualThreadScheduler scheduler,
398                                            Thread preferredCarrier,
399                                            String name,
400                                            int characteristics,
401                                            Runnable task) {
402         if (ContinuationSupport.isSupported()) {
403             return new VirtualThread(scheduler, preferredCarrier, name, characteristics, task);
404         } else {
405             if (scheduler != null)
406                 throw new UnsupportedOperationException();
407             return new BoundVirtualThread(name, characteristics, task);
408         }
409     }
410 
411     static Thread newVirtualThread(String name, int characteristics, Runnable task) {
412        return newVirtualThread(null, null, name, characteristics, task);
413     }
414 
415     /**
416      * A "virtual thread" that is backed by a platform thread. This implementation
417      * is intended for platforms that don't have the underlying VM support for
418      * continuations. It can also be used for testing.
419      */
420     static final class BoundVirtualThread extends BaseVirtualThread {
421         private static final Unsafe U = Unsafe.getUnsafe();
422         private final Runnable task;
423         private boolean runInvoked;
424 
425         BoundVirtualThread(String name, int characteristics, Runnable task) {
426             super(name, characteristics, true);
427             this.task = task;
428         }
429 
430         @Override
431         public void run() {
432             // run is specified to do nothing when Thread is a virtual thread
433             if (Thread.currentThread() == this && !runInvoked) {
434                 runInvoked = true;
435                 Object bindings = Thread.scopedValueBindings();
436                 runWith(bindings, task);
437             }
438         }
439 
440         @Override
441         void park() {
442             U.park(false, 0L);
443         }
444 
445         @Override
446         void parkNanos(long nanos) {
447             U.park(false, nanos);
448         }
449 
450         @Override
451         void unpark() {
452             U.unpark(this);
453         }
454 
455         @Override
456         public String toString() {
457             StringBuilder sb = new StringBuilder("VirtualThread[#");
458             sb.append(threadId());
459             String name = getName();
460             if (!name.isEmpty()) {
461                 sb.append(",");
462                 sb.append(name);
463             }
464             sb.append("]/");
465             String stateAsString = threadState().toString();
466             sb.append(stateAsString.toLowerCase(Locale.ROOT));
467             return sb.toString();
468         }
469     }
470 }