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