1 /*
   2  * Copyright (c) 2018, 2019, 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.StackWalker.StackFrame;
  28 import java.lang.invoke.MethodHandles;
  29 import java.lang.invoke.VarHandle;
  30 import java.security.AccessControlContext;
  31 import java.security.AccessController;
  32 import java.security.PrivilegedAction;
  33 import java.security.ProtectionDomain;
  34 import java.time.Duration;
  35 import java.util.Arrays;
  36 import java.util.Objects;
  37 import java.util.Optional;
  38 import java.util.Set;
  39 import java.util.concurrent.Callable;
  40 import java.util.concurrent.CompletableFuture;
  41 import java.util.concurrent.CompletionException;
  42 import java.util.concurrent.Exchanger;
  43 import java.util.concurrent.Executor;
  44 import java.util.concurrent.Executors;
  45 import java.util.concurrent.ForkJoinPool;
  46 import java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory;
  47 import java.util.concurrent.ForkJoinWorkerThread;
  48 import java.util.concurrent.Future;
  49 import java.util.concurrent.RejectedExecutionException;
  50 import java.util.concurrent.ScheduledExecutorService;
  51 import java.util.concurrent.ScheduledThreadPoolExecutor;
  52 import java.util.concurrent.TimeUnit;
  53 import java.util.concurrent.locks.Condition;
  54 import java.util.concurrent.locks.ReentrantLock;
  55 
  56 import jdk.internal.misc.InnocuousThread;
  57 import jdk.internal.misc.Strands;
  58 import jdk.internal.misc.Unsafe;
  59 import sun.security.action.GetPropertyAction;
  60 
  61 import static java.lang.StackWalker.Option.RETAIN_CLASS_REFERENCE;
  62 import static java.lang.StackWalker.Option.SHOW_REFLECT_FRAMES;
  63 import static java.util.concurrent.TimeUnit.NANOSECONDS;
  64 
  65 /**
  66  * A <i>user mode</i> thread to execute a task that is scheduled by the Java
  67  * virtual machine rather than the operating system.
  68  *
  69  * <p> A fiber is created and scheduled in a {@link FiberScope FiberScope}
  70  * to execute a task by invoking one of the {@link FiberScope#schedule(Runnable)
  71  * schedule} methods of that class. A fiber terminates when the task completes
  72  * execution, either normally or with a exception or error. The {@linkplain #join()
  73  * join} method may be used to wait for a fiber to terminate, returning the result
  74  * of the task or throwing {@linkplain CompletionException} when the task terminates
  75  * with an exception or error. The {@linkplain #awaitTermination(Duration)
  76  * awaitTermination} method may be used to wait for a fiber to terminate for up a
  77  * given waiting duration. The {@linkplain #toFuture() toFuture} method can be
  78  * used to obtain a {@linkplain CompletableFuture} to interoperate with code that
  79  * uses {@linkplain Future} or {@code CompletableFuture}.
  80  *
  81  * <p> Tasks executed by fibers are discouraged from using the APIs defined by
  82  * {@linkplain Thread java.lang.Thread} for footprint/memory reasons. If a task
  83  * invokes {@linkplain Thread#currentThread() Thread.currentThread()} then it
  84  * returns a {@code Thread} object that is unique to the fiber and all thread
  85  * locals (including the {@link Thread#getName() thread name}, {@link ThreadLocal
  86  * thread-local variables}, and the {@link Thread#getContextClassLoader()
  87  * thread context class loader}) are <em>fiber local</em> when used in the context
  88  * of a fiber.
  89  *
  90  * <p> Fibers support <em>cooperative cancellation</em>. Each fiber has a
  91  * <em>cancel status</em> that is set by invoking its {@linkplain #cancel() cancel}
  92  * method. Once set, the cancel status can never be reset. Computation or blocking
  93  * tasks poll for cancellation using the static {@linkplain #cancelled()} method.
  94  * The method returns {@code true} when the cancel status is set and the fiber is
  95  * executing in a <em>cancellable</em> fiber scope. Fibers also support an
  96  * <em>interrupt status</em> for use with the thread interrupt mechanism defined
  97  * by {@code java.lang.Thread}.
  98  *
  99  * <p> Unless otherwise noted, passing a {@code null} argument will cause a
 100  * {@linkplain NullPointerException} to be thrown.
 101  *
 102  * @param <V> the task result type
 103  */
 104 
 105 public class Fiber<V> {
 106     private static final ContinuationScope FIBER_SCOPE = new ContinuationScope("Fibers");
 107     private static final Executor DEFAULT_SCHEDULER = defaultScheduler();
 108     private static final ScheduledExecutorService UNPARKER = delayedTaskScheduler();
 109     private static final int TRACE_PINNING_MODE = tracePinningMode();
 110 
 111     private static final VarHandle STATE;
 112     private static final VarHandle PARK_PERMIT;
 113     private static final VarHandle RESULT;
 114     private static final VarHandle FUTURE;
 115     private static final VarHandle CANCELLED;
 116     static {
 117         try {
 118             MethodHandles.Lookup l = MethodHandles.lookup();
 119             STATE = l.findVarHandle(Fiber.class, "state", short.class);
 120             PARK_PERMIT = l.findVarHandle(Fiber.class, "parkPermit", boolean.class);
 121             RESULT = l.findVarHandle(Fiber.class, "result", Object.class);
 122             FUTURE = l.findVarHandle(Fiber.class, "future", CompletableFuture.class);
 123             CANCELLED = l.findVarHandle(Fiber.class, "cancelled", boolean.class);
 124        } catch (Exception e) {
 125             throw new InternalError(e);
 126         }
 127     }
 128 
 129     // scheduler and continuation
 130     private final Executor scheduler;
 131     private final Continuation cont;
 132     private final Runnable runContinuation;
 133 
 134     // carrier thread when mounted
 135     private volatile Thread carrierThread;
 136 
 137     // current scope
 138     private volatile FiberScope scope;
 139 
 140     // fiber state
 141     private static final short ST_NEW      = 0;
 142     private static final short ST_STARTED  = 1;
 143     private static final short ST_RUNNABLE = 2;
 144     private static final short ST_PARKING  = 3;
 145     private static final short ST_PARKED   = 4;
 146     private static final short ST_PINNED   = 5;
 147     private static final short ST_YIELDED  = 6;
 148     private static final short ST_WALKINGSTACK = 51;  // Thread.getStackTrace
 149     private static final short ST_TERMINATED   = 99;
 150     private volatile short state;
 151 
 152     // park/unpark and await support
 153     private final ReentrantLock lock = new ReentrantLock();
 154     private Condition parking;            // created lazily
 155     private Condition termination;        // created lazily
 156     private volatile boolean parkPermit;
 157     private volatile Object parkBlocker;  // used by LockSupport
 158 
 159     // task result
 160     private volatile Object result;
 161 
 162     // CompletableFuture integration
 163     private volatile CompletableFuture<V> future;
 164 
 165     // cancel status
 166     private volatile boolean cancelled;
 167 
 168     // interrupt support
 169     private final Object interruptLock = new Object();
 170     private volatile boolean interrupted;
 171 
 172     // task to execute after continue (for capturing stack trace and self-suspend)
 173     private volatile Runnable afterContinueTask;
 174 
 175     // java.lang.Thread integration
 176     private volatile ShadowThread shadowThread;  // created lazily
 177     private volatile InheritableThreadContext inheritableThreadContext;
 178 
 179     /**
 180      * Creates a new {@code Fiber} to run the given task with the given scheduler.
 181      *
 182      * @param task the task to execute
 183      * @param scheduler the scheduler
 184      */
 185     @SuppressWarnings("unchecked")
 186     private Fiber(Object task, Executor scheduler) {
 187         Objects.requireNonNull(task);
 188         Objects.requireNonNull(scheduler);
 189 
 190         Runnable target = () -> {
 191             V result = null;
 192             Throwable exc = null;
 193             try {
 194                 if (task instanceof Callable) {
 195                     result = ((Callable<? extends V>) task).call();
 196                     complete(result);
 197                 } else {
 198                     ((Runnable) task).run();
 199                     complete(null);
 200                 }
 201             } catch (Throwable e) {
 202                 exc = e;
 203                 completeExceptionally(e);
 204             } finally {
 205                 try {
 206                     scope.afterTask(result, exc);
 207                 } finally {
 208                     if (exc != null) {
 209                         Thread shadowThread = this.shadowThread;
 210                         if (shadowThread != null) {
 211                             shadowThread.dispatchUncaughtException(exc);
 212                         }
 213                     }
 214                 }
 215             }
 216         };
 217 
 218         this.scheduler = scheduler;
 219         this.cont = new Continuation(FIBER_SCOPE, target) {
 220             @Override
 221             protected void onPinned(Continuation.Pinned reason) {
 222                 if (TRACE_PINNING_MODE > 0) {
 223                     boolean printAll = (TRACE_PINNING_MODE == 1);
 224                     PinnedThreadPrinter.printStackTrace(printAll);
 225                 }
 226                 yieldFailed();
 227             }
 228         };
 229         this.runContinuation = this::runContinuation;
 230 
 231         // Inheritable context from creating thread or fiber
 232         InheritableThreadContext ctxt = null;
 233         Thread parentThread = Thread.currentCarrierThread();
 234         Fiber<?> parentFiber = parentThread.getFiber();
 235         if (parentFiber != null) {
 236             parentThread = parentFiber.shadowThreadOrNull();
 237             if (parentThread == null) {
 238                 ctxt = parentFiber.inheritableThreadContext;
 239                 if (ctxt == null) {
 240                     // context has been cleared by creating the shadow thread
 241                     parentThread = parentFiber.shadowThreadOrNull();
 242                     assert parentThread != null;
 243                 }
 244             }
 245         }
 246         if (parentThread != null) {
 247             this.inheritableThreadContext = new InheritableThreadContext(parentThread);
 248         } else {
 249             assert ctxt != null;
 250             this.inheritableThreadContext = ctxt;
 251         }
 252     }
 253 
 254     /**
 255      * Creates a new {@code Fiber} to run the given task.
 256      *
 257      * @param task the task to execute
 258      */
 259     Fiber(Runnable task) {
 260         this(task, DEFAULT_SCHEDULER);
 261     }
 262 
 263     /**
 264      * Creates a new {@code Fiber} to run the given task.
 265      *
 266      * @param task the task to execute
 267      */
 268     Fiber(Callable<? extends V> task) {
 269         this(task, DEFAULT_SCHEDULER);
 270     }
 271 
 272     /**
 273      * Creates a new {@code Fiber} to run the given task.
 274      *
 275      * @param scheduler the scheduler
 276      * @param task the task to execute
 277      */
 278     Fiber(Executor scheduler, Runnable task) {
 279         this(task, scheduler);
 280     }
 281 
 282     /**
 283      * Creates a new {@code Fiber} to run the given task.
 284      *
 285      * @param scheduler the scheduler
 286      * @param task the task to execute
 287      */
 288     Fiber(Executor scheduler, Callable<? extends V> task) {
 289         this(task, scheduler);
 290     }
 291 
 292     /**
 293      * Returns the current {@code Fiber}.
 294      *
 295      * @return Returns the current fiber or an empty {@code Optional} if not
 296      *         called from a fiber
 297      */
 298     public static Optional<Fiber<?>> current() {
 299         return Optional.ofNullable(currentFiber());
 300     }
 301 
 302     static Fiber<?> currentFiber() {
 303         return Thread.currentCarrierThread().getFiber();
 304     }
 305 
 306     FiberScope scope() {
 307         assert currentFiber() == this;
 308         return scope;
 309     }
 310 
 311     void setScope(FiberScope scope) {
 312         assert currentFiber() == this;
 313         this.scope = scope;
 314     }
 315 
 316     /**
 317      * Schedules this {@code Fiber} to execute in the given scope.
 318      *
 319      * @return this fiber
 320      * @throws IllegalStateException if the fiber has already been scheduled
 321      * @throws IllegalCallerException if the caller thread or fiber is not
 322      *         executing in the scope
 323      * @throws RejectedExecutionException if the scheduler cannot accept a task
 324      */
 325     Fiber<V> schedule(FiberScope scope) {
 326         Objects.requireNonNull(scope);
 327 
 328         if (!stateCompareAndSet(ST_NEW, ST_STARTED))
 329             throw new IllegalStateException("Fiber already scheduled");
 330 
 331         this.scope = scope;
 332 
 333         boolean scheduled = false;
 334         try {
 335             scheduler.execute(runContinuation);
 336             scheduled = true;
 337         } finally {
 338             if (!scheduled) {
 339                 completeExceptionally(new IllegalStateException("stillborn"));
 340                 afterTerminate(false);
 341             }
 342         }
 343 
 344         return this;
 345     }
 346 
 347     /**
 348      * Runs or continues execution of the continuation on the current thread.
 349      */
 350     private void runContinuation() {
 351         assert Thread.currentCarrierThread().getFiber() == null;
 352 
 353         // set state to ST_RUNNING
 354         boolean firstRun = stateCompareAndSet(ST_STARTED, ST_RUNNABLE);
 355         if (!firstRun) {
 356             // continue on this carrier thread if fiber was parked or it yielded
 357             if (stateCompareAndSet(ST_PARKED, ST_RUNNABLE)) {
 358                 parkPermitGetAndSet(false);  // consume parking permit
 359             } else if (!stateCompareAndSet(ST_YIELDED, ST_RUNNABLE)) {
 360                 return;
 361             }
 362         }
 363 
 364         mount(firstRun);
 365         try {
 366             cont.run();
 367         } finally {
 368             unmount();
 369             if (cont.isDone()) {
 370                 afterTerminate(true);
 371             } else {
 372                 afterYield();
 373             }
 374         }
 375     }
 376 
 377     /**
 378      * Mounts this fiber. This method must be invoked before the continuation
 379      * is run or continued. It binds the fiber to the current carrier thread.
 380      */
 381     private void mount(boolean firstRun) {
 382         Thread thread = Thread.currentCarrierThread();
 383 
 384         // sets the carrier thread and forward interrupt status if needed
 385         carrierThread = thread;
 386         if (interrupted) {
 387             thread.interrupt();
 388         }
 389 
 390         // set the fiber so that Thread.currentThread() returns the Fiber object
 391         assert thread.getFiber() == null;
 392         thread.setFiber(this);
 393 
 394         if (firstRun && notifyJvmtiEvents) {
 395             notifyFiberStarted(thread, this);
 396             notifyFiberMount(thread, this);
 397         }
 398     }
 399 
 400     /**
 401      * Unmounts this fiber. This method must be invoked after the continuation
 402      * yields or terminates. It unbinds this fiber from the carrier thread.
 403      */
 404     private void unmount() {
 405         Thread thread = Thread.currentCarrierThread();
 406 
 407         if (notifyJvmtiEvents) {
 408             notifyFiberUnmount(thread, this);
 409         }
 410 
 411         // drop connection between this fiber and the carrier thread
 412         thread.setFiber(null);
 413         synchronized (interruptLock) {   // synchronize with interrupt
 414             carrierThread = null;
 415         }
 416     }
 417 
 418     /**
 419      * Invoke after yielding. If parking, sets the state to ST_PARKED and notifies
 420      * anyone waiting for the fiber to park.
 421      */
 422     private void afterYield() {
 423         int s = stateGet();
 424         if (s == ST_PARKING) {
 425             // signal anyone waiting for this fiber to park
 426             stateGetAndSet(ST_PARKED);
 427             signalParking();
 428         } else if (s == ST_RUNNABLE) {
 429             // Thread.yield, submit task to continue
 430             assert Thread.currentCarrierThread().getFiber() == null;
 431             stateGetAndSet(ST_YIELDED);
 432             scheduler.execute(runContinuation);
 433         } else {
 434             throw new InternalError();
 435         }
 436     }
 437 
 438     /**
 439      * Invokes when the fiber terminates to set the state to ST_TERMINATED
 440      * and notify anyone waiting for the fiber to terminate.
 441      *
 442      * @param notifyAgents true to notify JVMTI agents
 443      */
 444     private void afterTerminate(boolean notifyAgents) {
 445         int oldState = stateGetAndSet(ST_TERMINATED);
 446         assert oldState == ST_STARTED || oldState == ST_RUNNABLE;
 447 
 448         // notify the scope
 449         scope.afterTerminate();
 450 
 451         if (notifyAgents && notifyJvmtiEvents) {
 452             Thread thread = Thread.currentCarrierThread();
 453             notifyFiberTerminated(thread, this);
 454         }
 455 
 456         // notify anyone waiting for this fiber to terminate
 457         signalTermination();
 458     }
 459 
 460     /**
 461      * Invoked by onPinned when the continuation cannot yield due to a
 462      * synchronized or native frame on the continuation stack. If the fiber is
 463      * parking then its state is changed to ST_PINNED and carrier thread parks.
 464      */
 465     private void yieldFailed() {
 466         if (stateGet() == ST_RUNNABLE) {
 467             // nothing to do
 468             return;
 469         }
 470 
 471         // switch to carrier thread
 472         Thread thread = Thread.currentCarrierThread();
 473         thread.setFiber(null);
 474 
 475         boolean parkInterrupted = false;
 476         lock.lock();
 477         try {
 478             if (!stateCompareAndSet(ST_PARKING, ST_PINNED))
 479                 throw new InternalError();
 480 
 481             Condition parking = parkingCondition();
 482 
 483             // signal anyone waiting for this fiber to park
 484             parking.signalAll();
 485 
 486             // and wait to be unparked (may be interrupted)
 487             parkingCondition().await();
 488 
 489         } catch (InterruptedException e) {
 490             parkInterrupted = true;
 491         } finally {
 492             lock.unlock();
 493 
 494             // continue running on the carrier thread
 495             if (!stateCompareAndSet(ST_PINNED, ST_RUNNABLE))
 496                 throw new InternalError();
 497 
 498             // consume parking permit
 499             parkPermitGetAndSet(false);
 500 
 501             // switch back to fiber
 502             thread.setFiber(this);
 503         }
 504 
 505         // restore interrupt status
 506         if (parkInterrupted)
 507             Thread.currentThread().interrupt();
 508     }
 509 
 510     /**
 511      * Disables the current fiber for scheduling purposes.
 512      *
 513      * <p> If this fiber has already been {@link #unpark() unparked} then the
 514      * parking permit is consumed and this method completes immediately;
 515      * otherwise the current fiber is disabled for scheduling purposes and lies
 516      * dormant until it is {@linkplain #unpark() unparked} or the thread is
 517      * {@link Thread#interrupt() interrupted}.
 518      *
 519      * @throws IllegalCallerException if not called from a fiber
 520      */
 521     static void park() {
 522         Fiber<?> fiber = Thread.currentCarrierThread().getFiber();
 523         if (fiber == null)
 524             throw new IllegalCallerException("not a fiber");
 525         fiber.maybePark();
 526     }
 527 
 528     /**
 529      * Disables the current fiber for scheduling purposes for up to the
 530      * given waiting time.
 531      *
 532      * <p> If this fiber has already been {@link #unpark() unparked} then the
 533      * parking permit is consumed and this method completes immediately;
 534      * otherwise if the time to wait is greater than zero then the current fiber
 535      * is disabled for scheduling purposes and lies dormant until it is {@link
 536      * #unpark unparked}, the waiting time elapses or the thread is
 537      * {@linkplain Thread#interrupt() interrupted}.
 538      *
 539      * @param nanos the maximum number of nanoseconds to wait.
 540      *
 541      * @throws IllegalCallerException if not called from a fiber
 542      */
 543     static void parkNanos(long nanos) {
 544         Thread thread = Thread.currentCarrierThread();
 545         Fiber<?> fiber = thread.getFiber();
 546         if (fiber == null)
 547             throw new IllegalCallerException("not a fiber");
 548         if (nanos > 0) {
 549             // switch to carrier thread when submitting to avoid parking here
 550             thread.setFiber(null);
 551             Future<?> unparker;
 552             try {
 553                 unparker = UNPARKER.schedule(fiber::unpark, nanos, NANOSECONDS);
 554             } finally {
 555                 thread.setFiber(fiber);
 556             }
 557             // now park
 558             try {
 559                 fiber.maybePark();
 560             } finally {
 561                 unparker.cancel(false);
 562             }
 563         } else {
 564             // consume permit when not parking
 565             fiber.yield();
 566             fiber.parkPermitGetAndSet(false);
 567         }
 568     }
 569 
 570     /**
 571      * Park or complete immediately.
 572      *
 573      * <p> If this fiber has already been unparked or its interrupt status is
 574      * set then this method completes immediately; otherwise it yields.
 575      */
 576     private void maybePark() {
 577         assert Thread.currentCarrierThread().getFiber() == this;
 578 
 579         // prepare to park; important to do this before consuming the parking permit
 580         if (!stateCompareAndSet(ST_RUNNABLE, ST_PARKING))
 581             throw new InternalError();
 582 
 583         // consume permit if available, and continue rather than park
 584         if (parkPermitGetAndSet(false) || interrupted) {
 585             if (!stateCompareAndSet(ST_PARKING, ST_RUNNABLE))
 586                 throw new InternalError();
 587 
 588             // signal anyone waiting for this fiber to park
 589             signalParking();
 590             return;
 591         }
 592 
 593         // yield until continued on a carrier thread
 594         boolean yielded = false;
 595         boolean retry;
 596         do {
 597             if (Continuation.yield(FIBER_SCOPE)) {
 598                 yielded = true;
 599             }
 600             if (retry = (carrierThread == null)) {
 601                 Runnable hook = this.afterContinueTask;
 602                 if (hook != null) hook.run();
 603             }
 604         } while (retry);
 605 
 606         // continued
 607         assert stateGet() == ST_RUNNABLE;
 608 
 609         // notify JVMTI mount event here so that stack is available to agents
 610         if (yielded && notifyJvmtiEvents) {
 611             notifyFiberMount(Thread.currentCarrierThread(), this);
 612         }
 613     }
 614 
 615     /**
 616      * Re-enables this fiber for scheduling. If the fiber was {@link #park()
 617      * parked} then it will be unblocked, otherwise its next call to {@code park}
 618      * or {@linkplain #parkNanos(long) parkNanos} is guaranteed not to block.
 619      *
 620      * @throws RejectedExecutionException if the scheduler cannot accept a task
 621      * @return this fiber
 622      */
 623     Fiber<V> unpark() {
 624         Thread thread = Thread.currentCarrierThread();
 625         Fiber<?> fiber = thread.getFiber();
 626         if (!parkPermitGetAndSet(true) && fiber != this) {
 627             int s = waitIfParking();
 628             if (s == ST_PARKED) {
 629                 scheduler.execute(runContinuation);
 630             }
 631         }
 632         return this;
 633     }
 634 
 635     /**
 636      * If this fiber is parking then wait for it to exit the ST_PARKING state.
 637      * If the fiber is pinned then signal it to continue on the original carrier
 638      * thread.
 639      *
 640      * @return the fiber state
 641      */
 642     private int waitIfParking() {
 643         int s;
 644         int spins = 0;
 645         while (((s = stateGet()) == ST_PARKING) && (spins < 32)) {
 646             Thread.onSpinWait();
 647             spins++;
 648         }
 649         if (s == ST_PARKING || s == ST_PINNED) {
 650             boolean parkInterrupted = false;
 651             Thread thread = Thread.currentCarrierThread();
 652             Fiber<?> f = thread.getFiber();
 653             if (f != null) thread.setFiber(null);
 654             lock.lock();
 655             try {
 656                 while ((s = stateGet()) == ST_PARKING) {
 657                     try {
 658                         parkingCondition().await();
 659                     } catch (InterruptedException e) {
 660                         parkInterrupted = true;
 661                     }
 662                 }
 663                 if (s == ST_PINNED) {
 664                     // signal so that execution continues on original thread
 665                     parkingCondition().signalAll();
 666                 }
 667             } finally {
 668                 lock.unlock();
 669                 if (f != null) thread.setFiber(f);
 670             }
 671             if (parkInterrupted)
 672                 Thread.currentThread().interrupt();
 673         }
 674         return s;
 675     }
 676 
 677     /**
 678      * For use by Thread.yield to yield on the current carrier thread. A no-op
 679      * if the continuation is pinned.
 680      */
 681     void yield() {
 682         assert Thread.currentCarrierThread().getFiber() == this
 683                 && stateGet() == ST_RUNNABLE;
 684         Continuation.yield(FIBER_SCOPE);
 685         assert stateGet() == ST_RUNNABLE;
 686     }
 687 
 688     /**
 689      * Waits for this fiber to terminate for up to the given waiting duration.
 690      * This method does not wait if the duration to wait is less than or equal
 691      * to zero.
 692      *
 693      * @param duration the maximum duration to wait
 694      * @return {@code true} if the fiber has terminated
 695      * @throws InterruptedException if interrupted while waiting or called with
 696      *         the interrupt status set. The interrupt status is cleared when
 697      *         this exception is thrown.
 698      *
 699      * @see #join()
 700      */
 701     public final boolean awaitTermination(Duration duration) throws InterruptedException {
 702         long nanos = TimeUnit.NANOSECONDS.convert(duration);
 703         if (nanos > 0) {
 704             return awaitInterruptibly(nanos);
 705         } else {
 706             if (Strands.clearInterrupt())
 707                 throw new InterruptedException();
 708             short s = stateGet();
 709             if (s == ST_NEW)
 710                 throw new IllegalStateException("Fiber not scheduled");
 711             return s == ST_TERMINATED;
 712         }
 713     }
 714 
 715     /**
 716      * Waits up to {@code nanos} nanoseconds for this fiber to terminate.
 717      * A timeout of {@code 0} means to wait forever.
 718      *
 719      * @throws IllegalArgumentException if nanos is negative
 720      * @throws InterruptedException if interrupted while waiting
 721      * @throws IllegalStateException if the fiber has not been scheduled
 722      * @return true if the fiber has terminated
 723      */
 724     boolean awaitInterruptibly(long nanos) throws InterruptedException {
 725         if (nanos < 0)
 726             throw new IllegalArgumentException("Timeout is negative");
 727         if (Strands.clearInterrupt())
 728             throw new InterruptedException();
 729         if (stateGet() == ST_TERMINATED)
 730             return true;
 731 
 732         lock.lock();
 733         try {
 734             short s = stateGet();
 735             if (s == ST_NEW)
 736                 throw new IllegalStateException("Fiber not scheduled");
 737             if (s == ST_TERMINATED)
 738                 return true;
 739 
 740             // wait
 741             if (nanos == 0) {
 742                 terminationCondition().await();
 743             } else {
 744                 terminationCondition().await(nanos, NANOSECONDS);
 745             }
 746         } finally {
 747             lock.unlock();
 748         }
 749         return (stateGet() == ST_TERMINATED);
 750     }
 751 
 752     /**
 753      * Tests if this fiber is alive. A fiber is alive if it has been scheduled
 754      * but has not yet terminated.
 755      *
 756      * @return {@code true} if this fiber is alive; {@code false} otherwise.
 757      */
 758     public final boolean isAlive() {
 759         short s = stateGet();
 760         return (s != ST_NEW) && (s != ST_TERMINATED);
 761     }
 762 
 763     /**
 764      * Sets this fiber's cancel status if not already set. If the fiber hasn't
 765      * terminated then its <em>interrupt status</em> is also set and the fiber
 766      * is {@link java.util.concurrent.locks.LockSupport#unpark(Object) unparked}.
 767      *
 768      * <p> If a {@linkplain CompletableFuture} object has been obtained using the
 769      * {@linkplain #toFuture()} method then its {@linkplain
 770      * CompletableFuture#cancel(boolean) cancel(boolean)} method is invoked to
 771      * complete it with {@link java.util.concurrent.CancellationException} if
 772      * not already completed or cancelled.
 773      *
 774      * @return true if the fiber's cancel status is changed by this method
 775      *
 776      * @throws RejectedExecutionException if the scheduler cannot accept a task
 777      */
 778     public final boolean cancel() {
 779         boolean changed = !cancelled && CANCELLED.compareAndSet(this, false, true);
 780         if (stateGet() != ST_TERMINATED) {
 781             CompletableFuture<V> future;
 782             FiberScope scope;
 783 
 784             // complete future
 785             if (changed && ((future = this.future) != null)) {
 786                 ((FutureImpl<V>) future).tryCancel(false);
 787             }
 788 
 789             // interrupt thread, even if already cancelled
 790             interrupt();
 791 
 792             // notify scope on first cancel
 793             if (changed && ((scope = this.scope) != null)) {
 794                 scope.afterCancel(this);
 795             }
 796         }
 797         return changed;
 798     }
 799 
 800     /**
 801      * Returns the fiber's cancel status, irrespective of the scope that it is in.
 802      *
 803      * @return {@code true} if the fiber's cancel status is set
 804      */
 805     public final boolean isCancelled() {
 806         return cancelled;
 807     }
 808 
 809     /**
 810      * Return {@code true} if the current fiber's cancel status is set and it
 811      * is in executing in a <em>cancellable</em> scope.
 812      *
 813      * This method always returns {@code false} when invoked from a thread.
 814      *
 815      * @apiNote This method is intended to be used by blocking or compute bound
 816      * operations that check cooperatively for cancellation.
 817      *
 818      * @return {@code true} if the current fiber has been cancelled
 819      */
 820     public static boolean cancelled() {
 821         Fiber<?> fiber = currentFiber();
 822         if (fiber != null && fiber.cancelled) {
 823             FiberScope scope = fiber.scope;
 824             assert scope != null;
 825             return scope.isCancellable();
 826         } else {
 827             return false;
 828         }
 829     }
 830 
 831     /**
 832      * Tests whether this fiber has been interrupted, optionally clearing the
 833      * interrupt status.
 834      */
 835     boolean isInterrupted(boolean clear) {
 836         boolean oldValue = interrupted;
 837         if (oldValue && clear) {
 838             assert Thread.currentCarrierThread().getFiber() == this;
 839             synchronized (interruptLock) {
 840                 interrupted = false;
 841 
 842                 Thread t = carrierThread;
 843                 if (t != null) t.clearInterrupt();
 844             }
 845         }
 846         return oldValue;
 847     }
 848 
 849     /**
 850      * Interrupts this fiber.
 851      *
 852      * <p> Interrupting a fiber that has terminated has no effect.
 853      *
 854      * @throws RejectedExecutionException if the scheduler cannot accept a task
 855      */
 856     void interrupt() {
 857         if (stateGet() != ST_TERMINATED) {
 858             synchronized (interruptLock) {
 859                 Thread shadowThread = this.shadowThread;
 860 
 861                 // fiber may be blocked in an I/O operation with an interrupter set
 862                 if (shadowThread != null
 863                     && Thread.currentCarrierThread().getFiber() != this) {
 864                     synchronized (shadowThread.blockerLock()) {
 865                         interrupted = true;
 866                         shadowThread.runInterrupter();
 867                     }
 868                 } else {
 869                     interrupted = true;
 870                 }
 871 
 872                 // interrupt carrier thread
 873                 Thread t = carrierThread;
 874                 if (t != null) t.interrupt();
 875             }
 876 
 877             unpark();
 878         }
 879     }
 880 
 881     /**
 882      * Tests whether this fiber has been interrupted. The <i>interrupt status</i>
 883      * of the thread is unaffected by this method.
 884      *
 885      * @return {@code true} if this fiber's interrupt status is set
 886      */
 887     boolean isInterrupted() {
 888         return isInterrupted(false);
 889     }
 890 
 891     /**
 892      * Clears the current fiber's <i>interrupt status</i>..
 893      *
 894      * @return {@code true} if the current fiber's interrupt status was set
 895      */
 896     static boolean clearInterrupt() {
 897         Fiber<?> fiber = currentFiber();
 898         if (fiber != null) {
 899             return fiber.isInterrupted(true);
 900         } else {
 901             return false;
 902         }
 903     }
 904 
 905     /**
 906      * Waits for this fiber to terminate and returns the result of its task. If
 907      * the task completed with an exception (or error) then {@linkplain CompletionException}
 908      * is thrown with the exception (or error) as its cause.
 909      *
 910      * @return the result or {@code null} if the fiber was created with a Runnable
 911      * @throws CompletionException if the task completed with an exception
 912      * @throws InterruptedException if interrupted while waiting or called with
 913      *         the interrupt status set. The interrupt status is cleared when
 914      *         this exception is thrown.
 915      *
 916      * @see #awaitTermination(Duration)
 917      */
 918     public final V join() throws InterruptedException {
 919         awaitInterruptibly(0);
 920         @SuppressWarnings("unchecked")
 921         V r = (V) resultOrThrow();
 922         return r;
 923     }
 924 
 925     /**
 926      * Returns the task result or throws CompletionException with the exception
 927      * when the task terminates with an exception.
 928      */
 929     private Object resultOrThrow() {
 930         Object r = result;
 931         assert r != null;
 932         if (r instanceof ExceptionHolder) {
 933             Throwable ex = ((ExceptionHolder) r).exception();
 934             throw new CompletionException(ex);
 935         } else {
 936             return (r != NULL_RESULT) ? r : null;
 937         }
 938     }
 939 
 940     /**
 941      * Returns a {@code CompletableFuture} to represent the result of the task.
 942      * The {@code CompletableFuture} can be used with code that uses a {@linkplain
 943      * java.util.concurrent.Future Future} to wait on a task and retrieve its
 944      * result. It can also be used with code that needs a {@linkplain
 945      * java.util.concurrent.CompletionStage} or other operations defined by
 946      * {@code CompletableFuture}.
 947      *
 948      * <p> Invoking the {@code CompletableFuture}'s {@linkplain CompletableFuture#complete
 949      * complete} or {@linkplain CompletableFuture#completeExceptionally
 950      * completeExceptionally} methods to explicitly complete the result has no
 951      * effect on the result returned by the {@linkplain #join()} method defined
 952      * here. The {@code CompletableFuture}'s {@linkplain CompletableFuture#cancel(boolean)
 953      * cancel} method cancels the fiber as if by calling the {@linkplain #cancel()
 954      * cancel} method. Once cancelled, the {@code CompletableFuture}'s {@linkplain
 955      * CompletableFuture#isDone() isDone} method will return {@code true}. The
 956      * fiber's {@link #isAlive() isAlive} method will continue to return {@code
 957      * true} until the fiber terminates.
 958      *
 959      * <p> The first invocation of this method creates the {@code CompletableFuture},
 960      * subsequent calls to this method return the same object.
 961      *
 962      * @return a CompletableFuture to represent the result of the task
 963      */
 964     @SuppressWarnings("unchecked")
 965     public final CompletableFuture<V> toFuture() {
 966         CompletableFuture<V> future = this.future;
 967         if (future == null) {
 968             future = new FutureImpl<>(this);
 969             Object previous = FUTURE.compareAndExchange(this, null, future);
 970             if (previous != null) {
 971                 future = (CompletableFuture<V>) previous;
 972             } else {
 973                 Object r = this.result;
 974                 if (r != null) {
 975                     if (r instanceof ExceptionHolder) {
 976                         Throwable ex = ((ExceptionHolder) r).exception();
 977                         future.completeExceptionally(ex);
 978                     } else {
 979                         future.complete((r != NULL_RESULT) ? (V) r : null);
 980                     }
 981                 } else if (cancelled) {
 982                     future.cancel(false);
 983                 }
 984             }
 985         }
 986         return future;
 987     }
 988 
 989     private static class FutureImpl<V> extends CompletableFuture<V> {
 990         private final Fiber<V> fiber;
 991         FutureImpl(Fiber<V> fiber) {
 992             this.fiber = fiber;
 993         }
 994         boolean tryCancel(boolean mayInterruptIfRunning) {
 995             return super.cancel(mayInterruptIfRunning);
 996         }
 997         @Override
 998         public boolean cancel(boolean mayInterruptIfRunning) {
 999             return fiber.cancel() && this.isCancelled();
1000         }
1001     }
1002 
1003     /**
1004      * Return the ShadowThread for this fiber or null if it does not exist.
1005      */
1006     Thread shadowThreadOrNull() {
1007         return shadowThread;
1008     }
1009 
1010     /**
1011      * Return the ShadowThread for this fiber, creating if it does not already
1012      * exist.
1013      */
1014     Thread shadowThread() {
1015         assert Thread.currentCarrierThread() == carrierThread;
1016         ShadowThread thread = shadowThread;
1017         if (thread== null) {
1018             shadowThread = thread = new ShadowThread(this, inheritableThreadContext);
1019 
1020             // allow context to be GC'ed.
1021             inheritableThreadContext = null;
1022         }
1023         return thread;
1024     }
1025 
1026     /**
1027      * By use by Thread.sleep to park the current fiber for the specified number
1028      * of nanoseconds.
1029      */
1030     static void sleepNanos(long nanos) throws InterruptedException {
1031         Fiber<?> fiber = Thread.currentCarrierThread().getFiber();
1032         if (fiber == null)
1033             throw new IllegalCallerException("not a fiber");
1034         if (fiber.isInterrupted(true))
1035             throw new InterruptedException();
1036         long remainingNanos = nanos;
1037         long startNanos = System.nanoTime();
1038         while (remainingNanos > 0) {
1039             parkNanos(remainingNanos);
1040             if (fiber.isInterrupted(true)) {
1041                 throw new InterruptedException();
1042             }
1043             remainingNanos = nanos - (System.nanoTime() - startNanos);
1044         }
1045     }
1046 
1047     /**
1048      * Returns the state of the fiber state as a thread state.
1049      */
1050     Thread.State getState() {
1051         switch (stateGet()) {
1052             case ST_NEW:
1053                 return Thread.State.NEW;
1054             case ST_STARTED:
1055             case ST_RUNNABLE:
1056             case ST_YIELDED:
1057                 Thread t = carrierThread;
1058                 if (t != null) {
1059                     // if mounted then return state of carrier thread (although
1060                     // it may not be correct if the fiber is rescheduled to the
1061                     // same carrier thread)
1062                     Thread.State s = t.getState();
1063                     if (carrierThread == t) {
1064                         return s;
1065                     }
1066                 }
1067                 return Thread.State.RUNNABLE;
1068             case ST_PARKING:
1069                 return Thread.State.RUNNABLE;  // not yet waiting
1070             case ST_PARKED:
1071             case ST_PINNED:
1072             case ST_WALKINGSTACK:
1073                 return Thread.State.WAITING;
1074             case ST_TERMINATED:
1075                 return Thread.State.TERMINATED;
1076             default:
1077                 throw new InternalError();
1078         }
1079     }
1080 
1081     @Override
1082     public String toString() {
1083         String prefix = "Fiber@" + Integer.toHexString(hashCode()) + "[";
1084         StringBuilder sb = new StringBuilder(prefix);
1085         Thread t = carrierThread;
1086         if (t != null) {
1087             sb.append(t.getName());
1088             ThreadGroup g = t.getThreadGroup();
1089             if (g != null) {
1090                 sb.append(",");
1091                 sb.append(g.getName());
1092             }
1093         } else {
1094             if (stateGet() == ST_TERMINATED) {
1095                 sb.append("<terminated>");
1096             } else {
1097                 sb.append("<no carrier thread>");
1098             }
1099         }
1100         sb.append("]");
1101         return sb.toString();
1102     }
1103 
1104     /**
1105      * Signal the Condition object for parking
1106      */
1107     private void signalParking() {
1108         Thread t = Thread.currentCarrierThread();
1109         boolean inFiber = t.getFiber() != null;
1110         if (inFiber) t.setFiber(null);
1111         lock.lock();
1112         try {
1113             Condition parking = this.parking;
1114             if (parking != null) {
1115                 parking.signalAll();
1116             }
1117         } finally {
1118             lock.unlock();
1119             if (inFiber) t.setFiber(this);
1120         }
1121     }
1122 
1123     /**
1124      * Signal the Condition object for termination
1125      */
1126     private void signalTermination() {
1127         lock.lock();
1128         try {
1129             Condition termination = this.termination;
1130             if (termination != null) {
1131                 termination.signalAll();
1132             }
1133         } finally {
1134             lock.unlock();
1135         }
1136     }
1137 
1138     /**
1139      * Returns the Condition object for parking, creating it if needed.
1140      */
1141     private Condition parkingCondition() {
1142         assert lock.isHeldByCurrentThread();
1143         Condition parking = this.parking;
1144         if (parking == null) {
1145             this.parking = parking = lock.newCondition();
1146         }
1147         return parking;
1148     }
1149 
1150     /**
1151      * Returns the Condition object for termination, creating it if needed.
1152      */
1153     private Condition terminationCondition() {
1154         assert lock.isHeldByCurrentThread();
1155         Condition termination = this.termination;
1156         if (termination == null) {
1157             this.termination = termination = lock.newCondition();
1158         }
1159         return termination;
1160     }
1161 
1162     // -- task result --
1163 
1164     private static final Object NULL_RESULT = new Object();
1165 
1166     private static class ExceptionHolder {
1167         final Throwable exc;
1168         ExceptionHolder(Throwable exc) { this.exc = exc; }
1169         Throwable exception() { return exc; }
1170     }
1171 
1172     @SuppressWarnings("unchecked")
1173     private void complete(V value) {
1174         Object r = (value == null) ? NULL_RESULT : value;
1175         if (RESULT.compareAndSet(this, null, r)) {
1176             CompletableFuture<V> future = this.future;
1177             if (future != null) {
1178                 future.complete((V) r);
1179             }
1180         }
1181     }
1182 
1183     private void completeExceptionally(Throwable exc) {
1184         if (RESULT.compareAndSet(this, null, new ExceptionHolder(exc))) {
1185             CompletableFuture<V> future = this.future;
1186             if (future != null) {
1187                 future.completeExceptionally(exc);
1188             }
1189         }
1190     }
1191 
1192     // -- stack trace support --
1193 
1194     private static final StackWalker STACK_WALKER = StackWalker.getInstance(FIBER_SCOPE);
1195     private static final StackTraceElement[] EMPTY_STACK = new StackTraceElement[0];
1196 
1197     /**
1198      * Returns an array of stack trace elements representing the stack trace
1199      * of this fiber.
1200      */
1201     StackTraceElement[] getStackTrace() {
1202         if (Thread.currentCarrierThread().getFiber() == this) {
1203             return STACK_WALKER
1204                     .walk(s -> s.map(StackFrame::toStackTraceElement)
1205                     .toArray(StackTraceElement[]::new));
1206         } else {
1207             // target fiber may be mounted or unmounted
1208             StackTraceElement[] stackTrace;
1209             do {
1210                 Thread carrier = carrierThread;
1211                 if (carrier != null) {
1212                     // mounted
1213                     stackTrace = tryGetStackTrace(carrier);
1214                 } else {
1215                     // not mounted
1216                     stackTrace = tryGetStackTrace();
1217                 }
1218                 if (stackTrace == null) {
1219                     Thread.onSpinWait();
1220                 }
1221             } while (stackTrace == null);
1222             return stackTrace;
1223         }
1224     }
1225 
1226     /**
1227      * Returns the stack trace for this fiber if it mounted on the given carrier
1228      * thread. If the fiber parks or is re-scheduled to another thread then
1229      * null is returned.
1230      */
1231     private StackTraceElement[] tryGetStackTrace(Thread carrier) {
1232         assert carrier != Thread.currentCarrierThread();
1233 
1234         StackTraceElement[] stackTrace;
1235         carrier.suspendThread();
1236         try {
1237             // get stack trace if fiber is still mounted on the suspended
1238             // carrier thread. Skip if the fiber is parking as the
1239             // continuation frames may or may not be on the thread stack.
1240             if (carrierThread == carrier && stateGet() != ST_PARKING) {
1241                 PrivilegedAction<StackTraceElement[]> pa = carrier::getStackTrace;
1242                 stackTrace = AccessController.doPrivileged(pa);
1243             } else {
1244                 stackTrace = null;
1245             }
1246         } finally {
1247             carrier.resumeThread();
1248         }
1249 
1250         if (stackTrace != null) {
1251             // return stack trace elements up to Fiber.runContinuation frame
1252             int index = 0;
1253             int runMethod = -1;
1254             while (index < stackTrace.length && runMethod < 0) {
1255                 StackTraceElement e = stackTrace[index];
1256                 if ("java.base".equals(e.getModuleName())
1257                         && "java.lang.Fiber".equals(e.getClassName())
1258                         && "runContinuation".equals(e.getMethodName())) {
1259                     runMethod = index;
1260                 } else {
1261                     index++;
1262                 }
1263             }
1264             if (runMethod >= 0) {
1265                 stackTrace = Arrays.copyOf(stackTrace, runMethod + 1);
1266             }
1267         }
1268 
1269         return stackTrace;
1270     }
1271 
1272     /**
1273      * Returns the stack trace for this fiber if it parked (not mounted) or
1274      * null if not in the parked state.
1275      */
1276     private StackTraceElement[] tryGetStackTrace() {
1277         if (stateCompareAndSet(ST_PARKED, ST_WALKINGSTACK)) {
1278             try {
1279                 return cont.stackWalker()
1280                         .walk(s -> s.map(StackFrame::toStackTraceElement)
1281                                     .toArray(StackTraceElement[]::new));
1282             } finally {
1283                 int oldState = stateGetAndSet(ST_PARKED);
1284                 assert oldState == ST_WALKINGSTACK;
1285 
1286                 // fiber may have been unparked while obtaining the stack so we
1287                 // unpark to avoid a lost unpark. This will appear as a spurious
1288                 // (but harmless) wakeup
1289                 unpark();
1290             }
1291         } else {
1292             short state = stateGet();
1293             if (state == ST_NEW || state == ST_TERMINATED) {
1294                 return EMPTY_STACK;
1295             } else {
1296                 return null;
1297             }
1298         }
1299     }
1300 
1301     /**
1302      * Continues a parked fiber on the current thread to execute the given task.
1303      * The task is executed without mounting the fiber. Returns true if the task
1304      * was executed, false if the task could not be executed because the fiber
1305      * is not parked.
1306      *
1307      * @throws IllegalCallerException if called from a fiber
1308      */
1309     private boolean tryRun(Runnable task) {
1310         if (Thread.currentCarrierThread().getFiber() != null) {
1311             throw new IllegalCallerException();
1312         }
1313         if (stateCompareAndSet(ST_PARKED, ST_RUNNABLE)) {
1314             assert carrierThread == null && afterContinueTask == null;
1315             afterContinueTask = task;
1316             try {
1317                 cont.run();
1318             } finally {
1319                 afterContinueTask = null;
1320                 int oldState = stateGetAndSet(ST_PARKED);
1321                 assert carrierThread == null;
1322                 assert oldState == ST_RUNNABLE;
1323                 assert !cont.isDone();
1324             }
1325 
1326             // fiber may have been unparked while running on this thread so we
1327             // unpark to avoid a lost unpark. This will appear as a spurious
1328             // (but harmless) wakeup
1329             unpark();
1330 
1331             return true;
1332         } else {
1333             return false;
1334         }
1335     }
1336 
1337     // -- wrappers for VarHandle methods --
1338 
1339     private short stateGet() {
1340         return (short) STATE.get(this);
1341     }
1342 
1343     private short stateGetAndSet(short newValue) {
1344         return (short) STATE.getAndSet(this, newValue);
1345     }
1346 
1347     private boolean stateCompareAndSet(short expectedValue, short newValue) {
1348         return STATE.compareAndSet(this, expectedValue, newValue);
1349     }
1350 
1351     private boolean parkPermitGetAndSet(boolean newValue) {
1352         return (boolean) PARK_PERMIT.getAndSet(this, newValue);
1353     }
1354 
1355     // -- JVM TI support --
1356 
1357     /**
1358      * Returns a thread with the fiber's stack mounted. The thread is suspended
1359      * or close to suspending itself. Returns {@code null} if the fiber is not
1360      * parked or cannot be mounted.
1361      *
1362      * @apiNote This method is for use by JVM TI and debugging operations only
1363      */
1364     Thread tryMountAndSuspend() {
1365         var exchanger = new Exchanger<Boolean>();
1366         var thread = InnocuousThread.newThread(() -> {
1367             boolean continued = tryRun(() -> {
1368                 exchangeUninterruptibly(exchanger, true);
1369                 Thread.currentCarrierThread().suspendThread();
1370             });
1371             if (!continued) {
1372                 exchangeUninterruptibly(exchanger, false);
1373             }
1374         });
1375         thread.setDaemon(true);
1376         thread.start();
1377         boolean continued = exchangeUninterruptibly(exchanger, true);
1378         if (continued) {
1379             return thread;
1380         } else {
1381             joinUninterruptibly(thread);
1382             return null;
1383         }
1384     }
1385 
1386     /**
1387      * Returns true if the fiber is mounted on a carrier thread with the
1388      * continuation stack.
1389      *
1390      * @apiNote This method is for use by JVM TI and debugging operations only
1391      */
1392     boolean isMountedWithStack() {
1393         return (carrierThread != null) && (stateGet() != ST_PARKING);
1394     }
1395 
1396     private static <V> V exchangeUninterruptibly(Exchanger<V> exchanger, V x) {
1397         V y = null;
1398         boolean interrupted = false;
1399         while (y == null) {
1400             try {
1401                 y = exchanger.exchange(x);
1402             } catch (InterruptedException e) {
1403                 interrupted = true;
1404             }
1405         }
1406         if (interrupted) {
1407             Thread.currentThread().interrupt();
1408         }
1409         return y;
1410     }
1411 
1412     private static void joinUninterruptibly(Thread thread) {
1413         boolean interrupted = false;
1414         for (;;) {
1415             try {
1416                 thread.join();
1417                 break;
1418             } catch (InterruptedException e) {
1419                 interrupted = true;
1420             }
1421         }
1422         if (interrupted) {
1423             Thread.currentThread().interrupt();
1424         }
1425     }
1426 
1427     private static volatile boolean notifyJvmtiEvents;  // set by VM
1428     private static native void notifyFiberStarted(Thread thread, Fiber<?> fiber);
1429     private static native void notifyFiberTerminated(Thread thread, Fiber<?> fiber);
1430     private static native void notifyFiberMount(Thread thread, Fiber<?> fiber);
1431     private static native void notifyFiberUnmount(Thread thread, Fiber<?> fiber);
1432     private static native void registerNatives();
1433     static {
1434         registerNatives();
1435     }
1436 
1437     /**
1438      * Creates the default scheduler as ForkJoinPool.
1439      */
1440     private static Executor defaultScheduler() {
1441         ForkJoinWorkerThreadFactory factory = pool -> {
1442             PrivilegedAction<ForkJoinWorkerThread> pa = () -> new CarrierThread(pool);
1443             return AccessController.doPrivileged(pa);
1444         };
1445         PrivilegedAction<Executor> pa = () -> {
1446             int parallelism;
1447             String s = System.getProperty("jdk.defaultScheduler.parallelism");
1448             if (s != null) {
1449                 parallelism = Integer.parseInt(s);
1450             } else {
1451                 parallelism = Runtime.getRuntime().availableProcessors();
1452             }
1453             Thread.UncaughtExceptionHandler ueh = (t, e) -> { };
1454             // use FIFO as default
1455             s = System.getProperty("jdk.defaultScheduler.lifo");
1456             boolean asyncMode = (s == null) || s.equalsIgnoreCase("false");
1457             return new ForkJoinPool(parallelism, factory, ueh, asyncMode);
1458         };
1459         return AccessController.doPrivileged(pa);
1460     }
1461 
1462     /**
1463      * A thread in the ForkJoinPool created by the default scheduler.
1464      */
1465     private static class CarrierThread extends ForkJoinWorkerThread {
1466         private static final ThreadGroup CARRIER_THREADGROUP = carrierThreadGroup();
1467         private static final AccessControlContext INNOCUOUS_ACC = innocuousACC();
1468 
1469         private static final Unsafe UNSAFE;
1470         private static final long CONTEXTCLASSLOADER;
1471         private static final long INHERITABLETHREADLOCALS;
1472         private static final long INHERITEDACCESSCONTROLCONTEXT;
1473 
1474         CarrierThread(ForkJoinPool pool) {
1475             super(CARRIER_THREADGROUP, pool);
1476             UNSAFE.putReference(this, CONTEXTCLASSLOADER, ClassLoader.getSystemClassLoader());
1477             UNSAFE.putReference(this, INHERITABLETHREADLOCALS, null);
1478             UNSAFE.putReferenceRelease(this, INHERITEDACCESSCONTROLCONTEXT, INNOCUOUS_ACC);
1479         }
1480 
1481         @Override
1482         public void setUncaughtExceptionHandler(UncaughtExceptionHandler ueh) { }
1483 
1484         @Override
1485         public void setContextClassLoader(ClassLoader cl) {
1486             throw new SecurityException("setContextClassLoader");
1487         }
1488 
1489         /**
1490          * The thread group for the carrier threads.
1491          */
1492         private static final ThreadGroup carrierThreadGroup() {
1493             return AccessController.doPrivileged(new PrivilegedAction<ThreadGroup>() {
1494                 public ThreadGroup run() {
1495                     ThreadGroup group = Thread.currentCarrierThread().getThreadGroup();
1496                     for (ThreadGroup p; (p = group.getParent()) != null; )
1497                         group = p;
1498                     return new ThreadGroup(group, "CarrierThreads");
1499                 }
1500             });
1501         }
1502 
1503         /**
1504          * Return an AccessControlContext that doesn't support any permissions.
1505          */
1506         private static AccessControlContext innocuousACC() {
1507             return new AccessControlContext(new ProtectionDomain[] {
1508                     new ProtectionDomain(null, null)
1509             });
1510         }
1511 
1512         static {
1513             UNSAFE = Unsafe.getUnsafe();
1514             CONTEXTCLASSLOADER = UNSAFE.objectFieldOffset(Thread.class,
1515                     "contextClassLoader");
1516             INHERITABLETHREADLOCALS = UNSAFE.objectFieldOffset(Thread.class,
1517                     "inheritableThreadLocals");
1518             INHERITEDACCESSCONTROLCONTEXT = UNSAFE.objectFieldOffset(Thread.class,
1519                     "inheritedAccessControlContext");
1520         }
1521     }
1522 
1523     /**
1524      * Creates the ScheduledThreadPoolExecutor used to schedule unparking.
1525      */
1526     private static ScheduledExecutorService delayedTaskScheduler() {
1527         ScheduledThreadPoolExecutor stpe = (ScheduledThreadPoolExecutor)
1528             Executors.newScheduledThreadPool(1, r ->
1529                 AccessController.doPrivileged(new PrivilegedAction<>() {
1530                     public Thread run() {
1531                         Thread t = new Thread(r);
1532                         t.setName("FiberUnparker");
1533                         t.setDaemon(true);
1534                         return t;
1535                     }}));
1536         stpe.setRemoveOnCancelPolicy(true);
1537         return stpe;
1538     }
1539 
1540     /**
1541      * Helper class to print the fiber stack trace when a carrier thread is
1542      * pinned.
1543      */
1544     private static class PinnedThreadPrinter {
1545         static final StackWalker INSTANCE;
1546         static {
1547             var options = Set.of(SHOW_REFLECT_FRAMES, RETAIN_CLASS_REFERENCE);
1548             PrivilegedAction<StackWalker> pa = () -> LiveStackFrame.getStackWalker(options, FIBER_SCOPE);
1549             INSTANCE = AccessController.doPrivileged(pa);
1550         }
1551         /**
1552          * Prints a stack trace of the current fiber to the standard output stream.
1553          * This method is synchronized to reduce interference in the output.
1554          * @param printAll true to print all stack frames, false to only print the
1555          *        frames that are native or holding a monitor
1556          */
1557         static synchronized void printStackTrace(boolean printAll) {
1558             System.out.println(Fiber.currentFiber());
1559             INSTANCE.forEach(f -> {
1560                 if (f.getDeclaringClass() != PinnedThreadPrinter.class) {
1561                     var ste = f.toStackTraceElement();
1562                     int monitorCount = ((LiveStackFrame) f).getMonitors().length;
1563                     if (monitorCount > 0 || f.isNativeMethod()) {
1564                         System.out.format("    %s <== monitors:%d%n", ste, monitorCount);
1565                     } else if (printAll) {
1566                         System.out.format("    %s%n", ste);
1567                     }
1568                 }
1569             });
1570         }
1571     }
1572 
1573     /**
1574      * Reads the value of the jdk.tracePinning property to determine if stack
1575      * traces should be printed when a carrier thread is pinned when a fiber
1576      * attempts to park.
1577      */
1578     private static int tracePinningMode() {
1579         String value = GetPropertyAction.privilegedGetProperty("jdk.tracePinnedThreads");
1580         if (value != null) {
1581             if (value.length() == 0 || "full".equalsIgnoreCase(value))
1582                 return 1;
1583             if ("short".equalsIgnoreCase(value))
1584                 return 2;
1585         }
1586         return 0;
1587     }
1588 }