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&gt
 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 }