1 /* 2 * Copyright (c) 2014, 2020, 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 package compiler.testlibrary.rtm; 25 26 import jdk.test.lib.Asserts; 27 import sun.hotspot.WhiteBox; 28 29 import java.util.Objects; 30 import java.util.concurrent.BrokenBarrierException; 31 import java.util.concurrent.CyclicBarrier; 32 33 /** 34 * Base class for different transactional execution abortion 35 * provokers aimed to force abort due to specified reason. 36 */ 37 public abstract class AbortProvoker implements CompilableTest { 38 public static final long DEFAULT_ITERATIONS = 10000L; 39 private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); 40 @SuppressWarnings("unused") 41 private static int sharedState = 0; 42 /** 43 * Inflates monitor associated with object {@code monitor}. 44 * Inflation is forced by entering the same monitor from 45 * two different threads. 46 * 47 * @param monitor monitor to be inflated. 48 * @return inflated monitor. 49 * @throws Exception if something went wrong. 50 */ 51 public static Object inflateMonitor(Object monitor) throws Exception { 52 CyclicBarrier barrier = new CyclicBarrier(2); 53 54 Runnable inflatingRunnable = () -> { 55 synchronized (monitor) { 56 try { 57 barrier.await(); 58 } catch (BrokenBarrierException | InterruptedException e) { 59 throw new RuntimeException( 60 "Synchronization issue occurred.", e); 61 } 62 try { 63 monitor.wait(); 64 } catch (InterruptedException e) { 65 throw new AssertionError("The thread waiting on an" 66 + " inflated monitor was interrupted, thus test" 67 + " results may be incorrect.", e); 68 } 69 } 70 }; 71 72 Thread t = new Thread(inflatingRunnable); 73 t.setDaemon(true); 74 t.start(); 75 // Wait until thread t enters the monitor. 76 barrier.await(); 77 synchronized (monitor) { 78 // At this point thread t is already waiting on the monitor. 79 // Modifying static field just to avoid lock's elimination. 80 sharedState++; 81 } 82 verifyMonitorState(monitor, true /* inflated */); 83 return monitor; 84 } 85 86 /** 87 * Verifies that {@code monitor} is a stack-lock or inflated lock depending 88 * on {@code shouldBeInflated} value. If {@code monitor} is inflated while 89 * it is expected that it should be a stack-lock, then this method attempts 90 * to deflate it by forcing a safepoint and then verifies the state once 91 * again. 92 * 93 * @param monitor monitor to be verified. 94 * @param shouldBeInflated flag indicating whether or not monitor is 95 * expected to be inflated. 96 * @throws RuntimeException if the {@code monitor} in a wrong state. 97 */ 98 public static void verifyMonitorState(Object monitor, 99 boolean shouldBeInflated) { 100 if (!shouldBeInflated && WHITE_BOX.isMonitorInflated(monitor)) { 101 boolean did_deflation = WHITE_BOX.deflateIdleMonitors(); 102 Asserts.assertEQ(did_deflation, true, 103 "deflateIdleMonitors() should have worked."); 104 } 105 Asserts.assertEQ(WHITE_BOX.isMonitorInflated(monitor), shouldBeInflated, 106 "Monitor in a wrong state."); 107 } 108 /** 109 * Verifies that monitor used by the {@code provoker} is a stack-lock or 110 * inflated lock depending on {@code shouldBeInflated} value. If such 111 * monitor is inflated while it is expected that it should be a stack-lock, 112 * then this method attempts to deflate it by forcing a safepoint and then 113 * verifies the state once again. 114 * 115 * @param provoker AbortProvoker whose monitor's state should be verified. 116 * @param shouldBeInflated flag indicating whether or not monitor is 117 * expected to be inflated. 118 * @throws RuntimeException if the {@code monitor} in a wrong state. 119 */ 120 public static void verifyMonitorState(AbortProvoker provoker, 121 boolean shouldBeInflated) { 122 verifyMonitorState(provoker.monitor, shouldBeInflated); 123 } 124 125 /** 126 * Get instance of specified AbortProvoker, inflate associated monitor 127 * if needed and then invoke forceAbort method in a loop. 128 * 129 * Usage: 130 * AbortProvoker <AbortType name> [<inflate monitor> 131 * [<iterations> [ <delay>]]] 132 * 133 * Default parameters are: 134 * <ul> 135 * <li>inflate monitor = <b>true</b></li> 136 * <li>iterations = {@code AbortProvoker.DEFAULT_ITERATIONS}</li> 137 * <li>delay = <b>0</b></li> 138 * </ul> 139 */ 140 public static void main(String args[]) throws Throwable { 141 Asserts.assertGT(args.length, 0, "At least one argument is required."); 142 143 AbortType abortType = AbortType.lookup(Integer.valueOf(args[0])); 144 boolean monitorShouldBeInflated = true; 145 long iterations = AbortProvoker.DEFAULT_ITERATIONS; 146 147 if (args.length > 1) { 148 monitorShouldBeInflated = Boolean.valueOf(args[1]); 149 150 if (args.length > 2) { 151 iterations = Long.valueOf(args[2]); 152 153 if (args.length > 3) { 154 Thread.sleep(Integer.valueOf(args[3])); 155 } 156 } 157 } 158 159 AbortProvoker provoker = abortType.provoker(); 160 161 if (monitorShouldBeInflated) { 162 provoker.inflateMonitor(); 163 } 164 165 for (long i = 0; i < iterations; i++) { 166 AbortProvoker.verifyMonitorState(provoker, monitorShouldBeInflated); 167 provoker.forceAbort(); 168 } 169 } 170 171 protected final Object monitor; 172 173 protected AbortProvoker() { 174 this(new Object()); 175 } 176 177 protected AbortProvoker(Object monitor) { 178 this.monitor = Objects.requireNonNull(monitor); 179 } 180 181 /** 182 * Inflates monitor used by this AbortProvoker instance. 183 * @throws Exception 184 */ 185 public void inflateMonitor() throws Exception { 186 AbortProvoker.inflateMonitor(monitor); 187 } 188 189 /** 190 * Forces transactional execution abortion. 191 */ 192 public abstract void forceAbort(); 193 194 /** 195 * Returns names of all methods that have to be compiled 196 * in order to successfully force transactional execution 197 * abortion. 198 * 199 * @return array with methods' names that have to be compiled. 200 */ 201 @Override 202 public String[] getMethodsToCompileNames() { 203 return new String[] { getMethodWithLockName() }; 204 } 205 206 /** 207 * Returns name of the method that will contain monitor whose locking 208 * will be elided using transactional execution. 209 * 210 * @return name of the method that will contain elided lock. 211 */ 212 @Override 213 public String getMethodWithLockName() { 214 return this.getClass().getName() + "::forceAbort"; 215 } 216 }