/* * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package jit.escape.LockCoarsening; import nsk.share.TestFailure; class LockCoarsening { // JVM option '-XX:+EliminateLocks' specified public static boolean eliminateLocks = false; // Number of chances Thread 2 has to acquire the lock public static int numChances = 16; // Signals to Threads_2 that Thread_1 started execuition public static volatile boolean start; // Signals to Thread_2 to stop execution public static volatile boolean done; // Thread_2 has acquired the lock public static volatile boolean acquiredLock; // Actually running the test public static volatile boolean realrun; // Thread 2 'acquire lock chance' number public static volatile int currentChance; static Thread_2 t2; public static void main(String[] args) { parseArgs(args); Thread.currentThread().getThreadGroup().setMaxPriority(Thread.MAX_PRIORITY); currentChance = 1; do { System.out.println("Chance " + currentChance + ":"); Thread_1 t1 = new Thread_1(); t1.getThreadGroup().setMaxPriority(Thread.MAX_PRIORITY); t1.setPriority(Thread.MIN_PRIORITY); t1.start(); try { t1.join(); } catch (InterruptedException e) { } System.out.println(); // if thread 2 hasn't acquired lock and we are not eliminating them, give it one more try... } while (!eliminateLocks && !acquiredLock && ++currentChance <= numChances); System.out.println("Thread 2 has acquired lock: " + acquiredLock); boolean failed = false; if (!eliminateLocks) { if (!acquiredLock) { failed = true; throw new TestFailure("acquiredLock == false, though, '-XX:-EliminateLocks' specified"); } } else { if (acquiredLock) { failed = true; throw new TestFailure("acquiredLock == true, though, '-XX:+EliminateLocks' specified"); } } if (!failed) System.out.println("TEST PASSED"); else throw new TestFailure("TEST FAILED"); } private static void parseArgs(String[] args) { eliminateLocks = false; for (int i = 0; i < args.length; ++i) { String arg = args[i]; String val; if (arg.equals("-eliminateLocks")) { eliminateLocks = true; } else if (arg.equals("-numChances")) { if (++i >= args.length) throw new TestFailure("'numChances' parameter requires an integer value"); val = args[i]; try { numChances = Integer.parseInt(val); } catch (NumberFormatException e) { throw new TestFailure("invalid value for 'numChances'"); } } else { System.out.println("Invalid argument: " + args); } } } /** * Thread that enters synchronized parts which are subject of * lock coarsening */ public static class Thread_1 extends Thread { public void run() { Dummy lock = new Dummy(); // An ugly-terrible hack to force JIT to compile Thread_1.doit(): // 1: call method from a static method of another class within a loop System.out.println("**** Compilation warm-up *****"); realrun = false; Helper.callMethod(this, lock); // 2: call method normally System.out.println("**** Starting real run ****"); realrun = true; this.doit(lock); } public final void doit(Dummy _lock) { Dummy lock = new Dummy(); start = false; done = false; acquiredLock = false; /*Thread_2*/ t2 = new Thread_2(lock); t2.getThreadGroup().setMaxPriority(Thread.MAX_PRIORITY); t2.setPriority(Thread.MAX_PRIORITY); t2.start(); //waiting for the Thread_2 to invoke lock.wait() while (t2.getState() != Thread.State.WAITING) { } start = true; // The following code is subject to lock coarsening if eliminateLocks == true { synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } synchronized (lock) { lock.foo(); } // Footer synchronized (lock) { lock.foo(); done = true; lock.notify(); } } try { t2.join(); } catch (InterruptedException e) { } } } /** * Thread that tries to acquire lock during lock coarsening. * If it unable to do it then lock coarsening occurred. */ private static class Thread_2 extends Thread { private Dummy lock; public Thread_2(Dummy lock) { this.lock = lock; } public void run() { Dummy lock = this.lock; synchronized (lock) { if (!done) { while (!start) { try { lock.wait(); } catch (InterruptedException e) { System.out.println("Interrupted!"); } } if (!done) { done = true; acquiredLock = true; if (realrun) { System.out.println("Acquired lock at " + lock.counter + " iteration of " + currentChance + " chance"); } else if (eliminateLocks) { //forcibly stop warm-up as we see that lock coarsening occurs Helper.allowExec = true; } } } } } } /** * Helper class to make method Thread_1.doit() be compiled. */ public static class Helper { public static volatile boolean allowExec = false; private static int iterations = 10000; public static void callMethod(Thread_1 t, Dummy lock) { for (int i = 0; i < iterations; ++i) { t.doit(lock); if (allowExec) break; } } } /** * Class to count number of synchronized statement. * If test fails Dummy.counter shows iteration when lock coarsening did not happen */ public static class Dummy { public volatile int counter = 0; public void foo() { if (done) return; while (t2.getState() != Thread.State.BLOCKED && t2.getState() != Thread.State.WAITING) { this.notifyAll(); Thread.yield(); } this.notifyAll(); while (t2.getState() != Thread.State.BLOCKED) { Thread.yield(); } ++counter; Thread.yield(); Thread.yield(); Thread.yield(); Thread.yield(); Thread.yield(); Thread.yield(); Thread.yield(); Thread.yield(); Thread.yield(); Thread.yield(); Thread.yield(); Thread.yield(); Thread.yield(); Thread.yield(); Thread.yield(); Thread.yield(); Thread.yield(); Thread.yield(); Thread.yield(); Thread.yield(); } } }