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 com.oracle.java.testlibrary.Utils; 33 import sun.misc.Unsafe; 34 35 /** 36 * Base class for different transactional execution abortion 37 * provokers aimed to force abort due to specified reason. 38 */ 39 public abstract class AbortProvoker implements CompilableTest { 40 public static final long DEFAULT_ITERATIONS = 10000L; 41 /** 42 * Inflates monitor associated with object {@code monitor}. 43 * Inflation is forced by entering the same monitor from 44 * two different threads. 45 * 46 * @param monitor monitor to be inflated. 47 * @return inflated monitor. 48 * @throws Exception if something went wrong. 49 */ 50 public static Object inflateMonitor(Object monitor) throws Exception { 51 Unsafe unsafe = Utils.getUnsafe(); 52 CyclicBarrier barrier = new CyclicBarrier(2); 53 54 Runnable inflatingRunnable = () -> { 55 unsafe.monitorEnter(monitor); 56 try { 57 barrier.await(); 58 barrier.await(); 59 } catch (InterruptedException | BrokenBarrierException e) { 60 throw new RuntimeException( 61 "Synchronization issue occurred.", e); 62 } finally { 63 unsafe.monitorExit(monitor); 64 } 65 }; 66 67 Thread t = new Thread(inflatingRunnable); 68 t.start(); 69 // Wait until thread t enters the monitor. 70 barrier.await(); 71 // At this point monitor will be owned by thread t, 72 // so our attempt to enter the same monitor will force 73 // monitor inflation. 74 Asserts.assertFalse(unsafe.tryMonitorEnter(monitor), 75 "Not supposed to enter the monitor first"); 76 barrier.await(); 77 t.join(); 78 return monitor; 79 } 80 81 82 /** 83 * Get instance of specified AbortProvoker, inflate associated monitor 84 * if needed and then invoke forceAbort method in a loop. 85 * 86 * Usage: 87 * AbortProvoker <AbortType name> [<inflate monitor> 88 * [<iterations> [ <delay>]]] 89 * 90 * Default parameters are: 91 * <ul> 92 * <li>inflate monitor = <b>true</b></li> 93 * <li>iterations = {@code AbortProvoker.DEFAULT_ITERATIONS}</li> 94 * <li>delay = <b>0</b></li> 95 * </ul> 96 */ 97 public static void main(String args[]) throws Throwable { 98 Asserts.assertGT(args.length, 0, "At least one argument is required."); 99 100 AbortType abortType = AbortType.lookup(Integer.valueOf(args[0])); 101 boolean monitorShouldBeInflated = true; 102 long iterations = AbortProvoker.DEFAULT_ITERATIONS; 103 104 if (args.length > 1) { 105 monitorShouldBeInflated = Boolean.valueOf(args[1]); 106 107 if (args.length > 2) { 108 iterations = Long.valueOf(args[2]); 109 110 if (args.length > 3) { 111 Thread.sleep(Integer.valueOf(args[3])); 112 } 113 } 114 } 115 116 AbortProvoker provoker = abortType.provoker(); 117 118 if (monitorShouldBeInflated) { 119 provoker.inflateMonitor(); 120 } 121 122 for (long i = 0; i < iterations; i++) { 123 provoker.forceAbort(); 124 } 125 } 126 127 protected final Object monitor; 128 129 protected AbortProvoker() { 130 this(new Object()); 131 } 132 133 protected AbortProvoker(Object monitor) { 134 this.monitor = Objects.requireNonNull(monitor); 135 } 136 137 /** 138 * Inflates monitor used by this AbortProvoker instance. 139 * @throws Exception 140 */ 141 public void inflateMonitor() throws Exception { 142 AbortProvoker.inflateMonitor(monitor); 143 } 144 145 /** 146 * Forces transactional execution abortion. 147 */ 148 public abstract void forceAbort(); 149 150 /** 151 * Returns names of all methods that have to be compiled 152 * in order to successfully force transactional execution 153 * abortion. 154 * 155 * @return array with methods' names that have to be compiled. 156 */ 157 @Override 158 public String[] getMethodsToCompileNames() { 159 return new String[] { getMethodWithLockName() }; 160 } 161 162 /** 163 * Returns name of the method that will contain monitor whose locking 164 * will be elided using transactional execution. 165 * 166 * @return name of the method that will contain elided lock. 167 */ 168 @Override 169 public String getMethodWithLockName() { 170 return this.getClass().getName() + "::forceAbort"; 171 } 172 }