AbortProvoker.java revision 11707:ad7af1afda7a
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
25package compiler.testlibrary.rtm;
26
27import jdk.test.lib.Asserts;
28import sun.hotspot.WhiteBox;
29
30import java.util.Objects;
31import java.util.concurrent.BrokenBarrierException;
32import 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 */
38public 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}
216