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 && Thread.currentThread().isVirtual() 71 && currentCarrierThread() instanceof CarrierThread ct && !ct.inBlocking()) { 72 ct.beginBlocking(); 73 boolean completed = false; 74 try { 75 long comp = ForkJoinPools.beginCompensatedBlock(ct.getPool()); 76 assert currentCarrierThread() == ct; 77 completed = true; 78 return comp; 79 } finally { 80 if (!completed) { 81 ct.endBlocking(); 82 } 83 } 84 } 85 return -1; 86 } 87 88 /** 89 * Marks the beginning of a possibly blocking operation. 90 * @param blocking true if the operation may block, otherwise false 91 * @return the return value from the attempt to compensate, -1 if not attempted 92 * or blocking is false 93 */ 94 public static long begin(boolean blocking) { 95 return (blocking) ? begin() : -1; 96 } 97 98 /** 99 * Marks the end of an operation that may have blocked. 100 * @param compensateReturn the value returned by the begin method 101 */ 102 public static void end(long compensateReturn) { 103 if (compensateReturn >= 0) { 104 assert currentCarrierThread() instanceof CarrierThread ct && ct.inBlocking(); 105 CarrierThread ct = (CarrierThread) currentCarrierThread(); 106 ForkJoinPools.endCompensatedBlock(ct.getPool(), compensateReturn); 107 ct.endBlocking(); 108 } 109 } 110 111 /** 112 * Defines static methods to invoke non-public ForkJoinPool methods via the 113 * shared secret support. 114 */ 115 private static class ForkJoinPools { 116 private static final JavaUtilConcurrentFJPAccess FJP_ACCESS = 117 SharedSecrets.getJavaUtilConcurrentFJPAccess(); 118 static long beginCompensatedBlock(ForkJoinPool pool) { 119 return FJP_ACCESS.beginCompensatedBlock(pool); 120 } 121 static void endCompensatedBlock(ForkJoinPool pool, long post) { 122 FJP_ACCESS.endCompensatedBlock(pool, post); 123 } 124 } 125 126 }