< prev index next >

src/java.base/share/classes/jdk/internal/vm/Continuation.java

Print this page

  1 /*
  2  * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 
 26 package jdk.internal.vm;
 27 
 28 import jdk.internal.misc.PreviewFeatures;
 29 import jdk.internal.misc.Unsafe;
 30 import jdk.internal.vm.annotation.DontInline;
 31 import jdk.internal.vm.annotation.IntrinsicCandidate;
 32 import sun.security.action.GetPropertyAction;
 33 
 34 import java.lang.invoke.MethodHandles;
 35 import java.lang.invoke.VarHandle;
 36 import java.util.EnumSet;
 37 import java.util.Map;
 38 import java.util.Set;
 39 import java.util.concurrent.ConcurrentHashMap;
 40 import java.util.function.Supplier;
 41 import jdk.internal.access.JavaLangAccess;
 42 import jdk.internal.access.SharedSecrets;

 43 
 44 /**
 45  * A one-shot delimited continuation.
 46  */
 47 public class Continuation {
 48     private static final Unsafe U = Unsafe.getUnsafe();
 49     private static final boolean PRESERVE_SCOPED_VALUE_CACHE;
 50     private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
 51     static {
 52         ContinuationSupport.ensureSupported();
 53         PreviewFeatures.ensureEnabled();
 54 
 55         StackChunk.init(); // ensure StackChunk class is initialized
 56 
 57         String value = GetPropertyAction.privilegedGetProperty("jdk.preserveScopedValueCache");
 58         PRESERVE_SCOPED_VALUE_CACHE = (value == null) || Boolean.parseBoolean(value);
 59     }
 60 
 61     private static final VarHandle MOUNTED;
 62 
 63     /** Reason for pinning */
 64     public enum Pinned {
 65         /** Native frame on stack */ NATIVE,
 66         /** Monitor held */          MONITOR,
 67         /** In critical section */   CRITICAL_SECTION }
 68 
 69     /** Preemption attempt result */
 70     public enum PreemptStatus {
 71         /** Success */                                                      SUCCESS(null),
 72         /** Permanent failure */                                            PERM_FAIL_UNSUPPORTED(null),
 73         /** Permanent failure: continuation already yielding */             PERM_FAIL_YIELDING(null),

294     }
295 
296     private void postYieldCleanup() {
297         if (done) {
298             this.tail = null;
299         }
300     }
301 
302     private void finish() {
303         done = true;
304         assert isEmpty();
305     }
306 
307     @IntrinsicCandidate
308     private native static int doYield();
309 
310     @IntrinsicCandidate
311     private native static void enterSpecial(Continuation c, boolean isContinue, boolean isVirtualThread);
312 
313 

314     @DontInline
315     @IntrinsicCandidate
316     private static void enter(Continuation c, boolean isContinue) {
317         // This method runs in the "entry frame".
318         // A yield jumps to this method's caller as if returning from this method.
319         try {
320             c.enter0();
321         } finally {
322             c.finish();
323         }
324     }
325 

326     private void enter0() {
327       target.run();
328     }
329 
330     private boolean isStarted() {
331         return tail != null;
332     }
333 
334     private boolean isEmpty() {
335         for (StackChunk c = tail; c != null; c = c.parent()) {
336             if (!c.isEmpty())
337                 return false;
338         }
339         return true;
340     }
341 
342     /**
343      * Suspends the current continuations up to the given scope
344      *
345      * @param scope The {@link ContinuationScope} to suspend
346      * @return {@code true} for success; {@code false} for failure
347      * @throws IllegalStateException if not currently in the given {@code scope},
348      */

349     public static boolean yield(ContinuationScope scope) {
350         Continuation cont = JLA.getContinuation(currentCarrierThread());
351         Continuation c;
352         for (c = cont; c != null && c.scope != scope; c = c.parent)
353             ;
354         if (c == null)
355             throw new IllegalStateException("Not in scope " + scope);
356 
357         return cont.yield0(scope, null);
358     }
359 

360     private boolean yield0(ContinuationScope scope, Continuation child) {
361         preempted = false;
362 
363         if (scope != this.scope)
364             this.yieldInfo = scope;
365         int res = doYield();
366         U.storeFence(); // needed to prevent certain transformations by the compiler
367 
368         assert scope != this.scope || yieldInfo == null : "scope: " + scope + " this.scope: " + this.scope + " yieldInfo: " + yieldInfo + " res: " + res;
369         assert yieldInfo == null || scope == this.scope || yieldInfo instanceof Integer : "scope: " + scope + " this.scope: " + this.scope + " yieldInfo: " + yieldInfo + " res: " + res;
370 
371         if (child != null) { // TODO: ugly
372             if (res != 0) {
373                 child.yieldInfo = res;
374             } else if (yieldInfo != null) {
375                 assert yieldInfo instanceof Integer;
376                 child.yieldInfo = yieldInfo;
377             } else {
378                 child.yieldInfo = res;
379             }

  1 /*
  2  * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 
 26 package jdk.internal.vm;
 27 

 28 import jdk.internal.misc.Unsafe;
 29 import jdk.internal.vm.annotation.DontInline;
 30 import jdk.internal.vm.annotation.IntrinsicCandidate;
 31 import sun.security.action.GetPropertyAction;
 32 
 33 import java.lang.invoke.MethodHandles;
 34 import java.lang.invoke.VarHandle;
 35 import java.util.EnumSet;

 36 import java.util.Set;

 37 import java.util.function.Supplier;
 38 import jdk.internal.access.JavaLangAccess;
 39 import jdk.internal.access.SharedSecrets;
 40 import jdk.internal.vm.annotation.Hidden;
 41 
 42 /**
 43  * A one-shot delimited continuation.
 44  */
 45 public class Continuation {
 46     private static final Unsafe U = Unsafe.getUnsafe();
 47     private static final boolean PRESERVE_SCOPED_VALUE_CACHE;
 48     private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
 49     static {
 50         ContinuationSupport.ensureSupported();

 51 
 52         StackChunk.init(); // ensure StackChunk class is initialized
 53 
 54         String value = GetPropertyAction.privilegedGetProperty("jdk.preserveScopedValueCache");
 55         PRESERVE_SCOPED_VALUE_CACHE = (value == null) || Boolean.parseBoolean(value);
 56     }
 57 
 58     private static final VarHandle MOUNTED;
 59 
 60     /** Reason for pinning */
 61     public enum Pinned {
 62         /** Native frame on stack */ NATIVE,
 63         /** Monitor held */          MONITOR,
 64         /** In critical section */   CRITICAL_SECTION }
 65 
 66     /** Preemption attempt result */
 67     public enum PreemptStatus {
 68         /** Success */                                                      SUCCESS(null),
 69         /** Permanent failure */                                            PERM_FAIL_UNSUPPORTED(null),
 70         /** Permanent failure: continuation already yielding */             PERM_FAIL_YIELDING(null),

291     }
292 
293     private void postYieldCleanup() {
294         if (done) {
295             this.tail = null;
296         }
297     }
298 
299     private void finish() {
300         done = true;
301         assert isEmpty();
302     }
303 
304     @IntrinsicCandidate
305     private native static int doYield();
306 
307     @IntrinsicCandidate
308     private native static void enterSpecial(Continuation c, boolean isContinue, boolean isVirtualThread);
309 
310 
311     @Hidden
312     @DontInline
313     @IntrinsicCandidate
314     private static void enter(Continuation c, boolean isContinue) {
315         // This method runs in the "entry frame".
316         // A yield jumps to this method's caller as if returning from this method.
317         try {
318             c.enter0();
319         } finally {
320             c.finish();
321         }
322     }
323 
324     @Hidden
325     private void enter0() {
326         target.run();
327     }
328 
329     private boolean isStarted() {
330         return tail != null;
331     }
332 
333     private boolean isEmpty() {
334         for (StackChunk c = tail; c != null; c = c.parent()) {
335             if (!c.isEmpty())
336                 return false;
337         }
338         return true;
339     }
340 
341     /**
342      * Suspends the current continuations up to the given scope
343      *
344      * @param scope The {@link ContinuationScope} to suspend
345      * @return {@code true} for success; {@code false} for failure
346      * @throws IllegalStateException if not currently in the given {@code scope},
347      */
348     @Hidden
349     public static boolean yield(ContinuationScope scope) {
350         Continuation cont = JLA.getContinuation(currentCarrierThread());
351         Continuation c;
352         for (c = cont; c != null && c.scope != scope; c = c.parent)
353             ;
354         if (c == null)
355             throw new IllegalStateException("Not in scope " + scope);
356 
357         return cont.yield0(scope, null);
358     }
359 
360     @Hidden
361     private boolean yield0(ContinuationScope scope, Continuation child) {
362         preempted = false;
363 
364         if (scope != this.scope)
365             this.yieldInfo = scope;
366         int res = doYield();
367         U.storeFence(); // needed to prevent certain transformations by the compiler
368 
369         assert scope != this.scope || yieldInfo == null : "scope: " + scope + " this.scope: " + this.scope + " yieldInfo: " + yieldInfo + " res: " + res;
370         assert yieldInfo == null || scope == this.scope || yieldInfo instanceof Integer : "scope: " + scope + " this.scope: " + this.scope + " yieldInfo: " + yieldInfo + " res: " + res;
371 
372         if (child != null) { // TODO: ugly
373             if (res != 0) {
374                 child.yieldInfo = res;
375             } else if (yieldInfo != null) {
376                 assert yieldInfo instanceof Integer;
377                 child.yieldInfo = yieldInfo;
378             } else {
379                 child.yieldInfo = res;
380             }
< prev index next >