1 /* 2 * Copyright (c) 2019, 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.misc; 27 28 import java.util.concurrent.ForkJoinPool; 29 import jdk.internal.access.JavaLangAccess; 30 import jdk.internal.access.JavaUtilConcurrentFJPAccess; 31 import jdk.internal.access.SharedSecrets; 32 33 /** 34 * Defines static methods to mark the beginning and end of a possibly blocking 35 * operation. The methods are intended to be used with try-finally as follows: 36 * {@snippet lang=java : 37 * long comp = Blocker.begin(); 38 * try { 39 * // blocking operation 40 * } finally { 41 * Blocker.end(comp); 42 * } 43 * } 44 * If invoked from a virtual thread and the underlying carrier thread is a 45 * CarrierThread then the code in the block runs as if it were in run in 46 * ForkJoinPool.ManagedBlocker. This means the pool can be expanded to support 47 * additional parallelism during the blocking operation. 48 */ 49 public class Blocker { 50 private static final JavaLangAccess JLA; 51 static { 52 JLA = SharedSecrets.getJavaLangAccess(); 53 if (JLA == null) { 54 throw new InternalError("JavaLangAccess not setup"); 55 } 56 } 57 58 private Blocker() { } 59 60 private static Thread currentCarrierThread() { 61 return JLA.currentCarrierThread(); 62 } 63 64 /** 65 * Marks the beginning of a possibly blocking operation. 66 * @return the return value from the attempt to compensate or -1 if not attempted 67 */ 68 public static long begin() { 69 if (VM.isBooted() 70 && currentCarrierThread() instanceof CarrierThread ct && !ct.inBlocking()) { 71 ct.beginBlocking(); 72 boolean completed = false; 73 try { 74 long comp = ForkJoinPools.beginCompensatedBlock(ct.getPool()); 75 assert currentCarrierThread() == ct; 76 completed = true; 77 return comp; 78 } finally { 79 if (!completed) { 80 ct.endBlocking(); 81 } 82 } 83 } 84 return -1; 85 } 86 87 /** 88 * Marks the beginning of a possibly blocking operation. 89 * @param blocking true if the operation may block, otherwise false 90 * @return the return value from the attempt to compensate, -1 if not attempted 91 * or blocking is false 92 */ 93 public static long begin(boolean blocking) { 94 return (blocking) ? begin() : -1; 95 } 96 97 /** 98 * Marks the end of an operation that may have blocked. 99 * @param compensateReturn the value returned by the begin method 100 */ 101 public static void end(long compensateReturn) { 102 if (compensateReturn >= 0) { 103 assert currentCarrierThread() instanceof CarrierThread ct && ct.inBlocking(); 104 CarrierThread ct = (CarrierThread) currentCarrierThread(); 105 ForkJoinPools.endCompensatedBlock(ct.getPool(), compensateReturn); 106 ct.endBlocking(); 107 } 108 } 109 110 /** 111 * Defines static methods to invoke non-public ForkJoinPool methods via the 112 * shared secret support. 113 */ 114 private static class ForkJoinPools { 115 private static final JavaUtilConcurrentFJPAccess FJP_ACCESS = 116 SharedSecrets.getJavaUtilConcurrentFJPAccess(); 117 static long beginCompensatedBlock(ForkJoinPool pool) { 118 return FJP_ACCESS.beginCompensatedBlock(pool); 119 } 120 static void endCompensatedBlock(ForkJoinPool pool, long post) { 121 FJP_ACCESS.endCompensatedBlock(pool, post); 122 } 123 } 124 125 }