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 Thread lazyStart(Runnable task) {
267             Thread thread = unstarted(task);
268             if (thread instanceof VirtualThread vthread) {
269                 vthread.lazyStart();
270             } else {
271                 thread.start();
272             }
273             return thread;
274         }
275 
276         @Override
277         public ThreadFactory factory() {
278             return new VirtualThreadFactory(scheduler, name(), counter(), characteristics(),
279                     uncaughtExceptionHandler());
280         }
281     }
282 
283     /**
284      * Base ThreadFactory implementation.
285      */
286     private abstract static class BaseThreadFactory implements ThreadFactory {
287         private static final VarHandle COUNT = MhUtil.findVarHandle(
288                 MethodHandles.lookup(), "count", long.class);
289 
290         private final String name;
291         private final int characteristics;
292         private final UncaughtExceptionHandler uhe;
293 
294         private final boolean hasCounter;
295         private volatile long count;
296 
297         BaseThreadFactory(String name,
298                           long start,
299                           int characteristics,
300                           UncaughtExceptionHandler uhe)  {
301             this.name = name;
302             if (name != null && start >= 0) {
303                 this.hasCounter = true;
304                 this.count = start;
305             } else {
306                 this.hasCounter = false;
307             }
308             this.characteristics = characteristics;
309             this.uhe = uhe;
310         }
311 
312         int characteristics() {
313             return characteristics;
314         }
315 
316         UncaughtExceptionHandler uncaughtExceptionHandler() {
317             return uhe;
318         }
319 
320         String nextThreadName() {
321             if (hasCounter) {
322                 return name + (long) COUNT.getAndAdd(this, 1L);
323             } else {
324                 return name;
325             }
326         }
327     }
328 
329     /**
330      * ThreadFactory for platform threads.
331      */
332     private static class PlatformThreadFactory extends BaseThreadFactory {
333         private final ThreadGroup group;
334         private final boolean daemonChanged;
335         private final boolean daemon;
336         private final int priority;
337         private final long stackSize;
338 
339         PlatformThreadFactory(ThreadGroup group,
340                               String name,
341                               long start,
342                               int characteristics,
343                               boolean daemonChanged,
344                               boolean daemon,
345                               int priority,
346                               long stackSize,
347                               UncaughtExceptionHandler uhe) {
348             super(name, start, characteristics, uhe);
349             this.group = group;
350             this.daemonChanged = daemonChanged;
351             this.daemon = daemon;
352             this.priority = priority;
353             this.stackSize = stackSize;
354         }
355 
356         @Override
357         String nextThreadName() {
358             String name = super.nextThreadName();
359             return (name != null) ? name : Thread.genThreadName();
360         }
361 
362         @Override
363         public Thread newThread(Runnable task) {
364             Objects.requireNonNull(task);
365             String name = nextThreadName();
366             Thread thread = new Thread(group, name, characteristics(), task, stackSize);
367             if (daemonChanged)
368                 thread.daemon(daemon);
369             if (priority != 0)
370                 thread.priority(priority);
371             UncaughtExceptionHandler uhe = uncaughtExceptionHandler();
372             if (uhe != null)
373                 thread.uncaughtExceptionHandler(uhe);
374             return thread;
375         }
376     }
377 
378     /**
379      * ThreadFactory for virtual threads.
380      */
381     private static class VirtualThreadFactory extends BaseThreadFactory {
382         private final Thread.VirtualThreadScheduler scheduler;
383 
384         VirtualThreadFactory(Thread.VirtualThreadScheduler scheduler,
385                              String name,
386                              long start,
387                              int characteristics,
388                              UncaughtExceptionHandler uhe) {
389             super(name, start, characteristics, uhe);
390             this.scheduler = scheduler;
391         }
392 
393         @Override
394         public Thread newThread(Runnable task) {
395             Objects.requireNonNull(task);
396             String name = nextThreadName();
397             Thread thread = newVirtualThread(scheduler, null, name, characteristics(), task);
398             UncaughtExceptionHandler uhe = uncaughtExceptionHandler();
399             if (uhe != null)
400                 thread.uncaughtExceptionHandler(uhe);
401             return thread;
402         }
403     }
404 
405     /**
406      * Creates a new virtual thread to run the given task.
407      */
408     private static Thread newVirtualThread(Thread.VirtualThreadScheduler scheduler,
409                                            Thread preferredCarrier,
410                                            String name,
411                                            int characteristics,
412                                            Runnable task) {
413         if (ContinuationSupport.isSupported()) {
414             return new VirtualThread(scheduler, preferredCarrier, name, characteristics, task);
415         } else {
416             if (scheduler != null)
417                 throw new UnsupportedOperationException();
418             return new BoundVirtualThread(name, characteristics, task);
419         }
420     }
421 
422     static Thread newVirtualThread(String name, int characteristics, Runnable task) {
423        return newVirtualThread(null, null, name, characteristics, task);
424     }
425 
426     /**
427      * A "virtual thread" that is backed by a platform thread. This implementation
428      * is intended for platforms that don't have the underlying VM support for
429      * continuations. It can also be used for testing.
430      */
431     static final class BoundVirtualThread extends BaseVirtualThread {
432         private static final Unsafe U = Unsafe.getUnsafe();
433         private final Runnable task;
434         private boolean runInvoked;
435 
436         BoundVirtualThread(String name, int characteristics, Runnable task) {
437             super(name, characteristics, true);
438             this.task = task;
439         }
440 
441         @Override
442         public void run() {
443             // run is specified to do nothing when Thread is a virtual thread
444             if (Thread.currentThread() == this && !runInvoked) {
445                 runInvoked = true;
446                 Object bindings = Thread.scopedValueBindings();
447                 runWith(bindings, task);
448             }
449         }
450 
451         @Override
452         void park() {
453             U.park(false, 0L);
454         }
455 
456         @Override
457         void parkNanos(long nanos) {
458             U.park(false, nanos);
459         }
460 
461         @Override
462         void unpark() {
463             U.unpark(this);
464         }
465 
466         @Override
467         public String toString() {
468             StringBuilder sb = new StringBuilder("VirtualThread[#");
469             sb.append(threadId());
470             String name = getName();
471             if (!name.isEmpty()) {
472                 sb.append(",");
473                 sb.append(name);
474             }
475             sb.append("]/");
476             String stateAsString = threadState().toString();
477             sb.append(stateAsString.toLowerCase(Locale.ROOT));
478             return sb.toString();
479         }
480     }
481 }