1 /*
   2  * Copyright (c) 2014, 2015, 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 compiler.testlibrary.rtm;
  26 
  27 import jdk.test.lib.Asserts;
  28 import sun.hotspot.WhiteBox;
  29 
  30 import java.util.Objects;
  31 import java.util.concurrent.BrokenBarrierException;
  32 import java.util.concurrent.CyclicBarrier;
  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&gt
 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 }