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