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
24package compiler.testlibrary.rtm;
25
26import java.util.concurrent.BrokenBarrierException;
27import java.util.concurrent.CyclicBarrier;
28
29/**
30 * To force transactional execution abort due to memory conflict
31 * one thread should access memory region from transactional region
32 * while another thread should modify the same memory region.
33 * Since this scenario is based on the race condition between threads
34 * you should not expect some particular amount of aborts.
35 */
36class MemoryConflictProvoker extends AbortProvoker {
37    // Following field have to be static in order to avoid escape analysis.
38    @SuppressWarnings("UnsuedDeclaration")
39    private static int field = 0;
40    private static final int INNER_ITERATIONS = 10000;
41    private final CyclicBarrier barrier;
42    /**
43     * This thread will access and modify memory region
44     * from outside of the transaction.
45     */
46    private final Runnable conflictingThread;
47
48    public MemoryConflictProvoker() {
49        this(new Object());
50    }
51
52    public MemoryConflictProvoker(Object monitor) {
53        super(monitor);
54        barrier = new CyclicBarrier(2);
55        conflictingThread = () -> {
56            try {
57                barrier.await();
58            } catch (Exception e) {
59                throw new RuntimeException(e);
60            }
61            for (int i = 0; i < MemoryConflictProvoker.INNER_ITERATIONS; i++) {
62                MemoryConflictProvoker.field++;
63            }
64        };
65    }
66
67    /**
68     * Accesses and modifies memory region from within the transaction.
69     */
70    public void transactionalRegion() {
71        for (int i = 0; i < MemoryConflictProvoker.INNER_ITERATIONS; i++) {
72            synchronized(monitor) {
73                MemoryConflictProvoker.field--;
74            }
75        }
76    }
77
78    @Override
79    public void forceAbort() {
80        try {
81            Thread t = new Thread(conflictingThread);
82            t.start();
83            try {
84                barrier.await();
85            } catch (InterruptedException | BrokenBarrierException e) {
86                throw new RuntimeException(e);
87            }
88            transactionalRegion();
89            t.join();
90        } catch (Exception e) {
91            throw new RuntimeException(e);
92        }
93    }
94
95    @Override
96    public String getMethodWithLockName() {
97        return this.getClass().getName() + "::transactionalRegion";
98    }
99}
100