Path: blob/master/test/jdk/javax/management/monitor/GaugeMonitorDeadlockTest.java
41152 views
/*1* Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test25* @bug 630318726* @summary Test that no locks are held when a monitor attribute is sampled27* or notif delivered.28* @author Eamonn McManus29*30* @library /test/lib31*32* @run clean GaugeMonitorDeadlockTest33* @run build GaugeMonitorDeadlockTest34* @run main GaugeMonitorDeadlockTest 135* @run main GaugeMonitorDeadlockTest 236* @run main GaugeMonitorDeadlockTest 337* @run main GaugeMonitorDeadlockTest 438*/3940import java.lang.management.ManagementFactory;41import java.lang.management.ThreadInfo;42import java.lang.management.ThreadMXBean;43import java.util.concurrent.atomic.AtomicInteger;44import javax.management.JMX;45import javax.management.MBeanServer;46import javax.management.Notification;47import javax.management.NotificationListener;48import javax.management.ObjectName;49import javax.management.monitor.GaugeMonitor;50import javax.management.monitor.GaugeMonitorMBean;5152import jdk.test.lib.Utils;5354public class GaugeMonitorDeadlockTest {55private static enum When {IN_GET_ATTRIBUTE, IN_NOTIFY};56private static long checkingTime;5758public static void main(String[] args) throws Exception {59if (args.length != 1)60throw new Exception("Arg should be test number");61checkingTime = Utils.adjustTimeout(1000); // default 1s timeout62System.out.println("=== checkingTime = " + checkingTime + "ms");6364int testNo = Integer.parseInt(args[0]) - 1;65TestCase test = testCases[testNo];66System.out.println("Test: " + test.getDescription());67test.run();68System.out.println("Test passed");69}7071private static abstract class TestCase {72TestCase(String description, When when) {73this.description = description;74this.when = when;75}7677void run() throws Exception {78final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();79final ObjectName observedName = new ObjectName("a:b=c");80final ObjectName monitorName = new ObjectName("a:type=Monitor");81mbs.registerMBean(new GaugeMonitor(), monitorName);82final GaugeMonitorMBean monitorProxy =83JMX.newMBeanProxy(mbs, monitorName, GaugeMonitorMBean.class);84final TestMBean observedProxy =85JMX.newMBeanProxy(mbs, observedName, TestMBean.class);8687final Runnable sensitiveThing = new Runnable() {88public void run() {89doSensitiveThing(monitorProxy, observedName);90}91};9293final Runnable nothing = new Runnable() {94public void run() {}95};9697final Runnable withinGetAttribute =98(when == When.IN_GET_ATTRIBUTE) ? sensitiveThing : nothing;99100mbs.registerMBean(new Test(withinGetAttribute), observedName);101monitorProxy.addObservedObject(observedName);102monitorProxy.setObservedAttribute("Thing");103monitorProxy.setThresholds(105, 100);104monitorProxy.setGranularityPeriod(10L); // 10 ms105monitorProxy.setNotifyHigh(true);106monitorProxy.setNotifyLow(true);107108System.out.println("=== Waiting observedProxy.getGetCount() to be "109+ "changed, presumable deadlock if timeout?");110final int initGetCount = observedProxy.getGetCount();111monitorProxy.start();112113long checkedTime = System.currentTimeMillis();114long nowTime;115ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();116while (observedProxy.getGetCount() == initGetCount) {117Thread.sleep(100);118119nowTime = System.currentTimeMillis();120if (nowTime - checkedTime >= checkingTime) {121System.out.println("=== Checking deadlocked ...");122if (threadMXBean.findDeadlockedThreads() != null) {123for (ThreadInfo info : threadMXBean.dumpAllThreads(true, true)) {124System.out.println(info);125}126throw new Error("Found deadlocked threads: "127+ threadMXBean.findDeadlockedThreads().length);128}129checkedTime = System.currentTimeMillis();130}131}132133// This won't show up as a deadlock in CTRL-\ or in134// ThreadMXBean.findDeadlockedThreads(), because they don't135// see that thread A is waiting for thread B (B.join()), and136// thread B is waiting for a lock held by thread A137138// Now we know the monitor has observed the initial value,139// so if we want to test notify behaviour we can trigger by140// exceeding the threshold.141if (when == When.IN_NOTIFY) {142final Thread testedThread = new Thread(sensitiveThing);143final AtomicInteger notifCount = new AtomicInteger();144final NotificationListener listener = new NotificationListener() {145public void handleNotification(Notification n, Object h) {146testedThread.start();147try {148testedThread.join();149} catch (InterruptedException e) {150throw new RuntimeException(e);151}152notifCount.incrementAndGet();153}154};155mbs.addNotificationListener(monitorName, listener, null, null);156observedProxy.setThing(1000);157System.out.println("=== Waiting notifications, presumable "158+ "deadlock if timeout?");159long startTime = System.currentTimeMillis();160checkedTime = startTime;161while (notifCount.get() == 0) {162Thread.sleep(100);163164nowTime = System.currentTimeMillis();165if (nowTime - checkedTime >= checkingTime) {166System.out.println("=== Checking the thread state ...");167if (testedThread.isAlive()) {168System.out.println("=== Waiting testedThread to die "169+ "after " + (nowTime - startTime) + "ms");170171ThreadInfo tinfo = threadMXBean.getThreadInfo(testedThread.getId());172if (Thread.State.BLOCKED.equals(tinfo.getThreadState())) {173for (ThreadInfo info : threadMXBean.dumpAllThreads(true, true)) {174System.out.println(info);175}176} else {177System.out.println(tinfo);178}179} else {180System.out.println("=== The testedThread is dead as wished, "181+ "the test must be passed soon.");182}183checkedTime = System.currentTimeMillis();184}185}186}187}188189abstract void doSensitiveThing(GaugeMonitorMBean monitorProxy,190ObjectName observedName);191192String getDescription() {193return description;194}195196private final String description;197private final When when;198}199200private static final TestCase[] testCases = {201new TestCase("Remove monitored MBean within monitored getAttribute",202When.IN_GET_ATTRIBUTE) {203@Override204void doSensitiveThing(GaugeMonitorMBean monitorProxy,205ObjectName observedName) {206monitorProxy.removeObservedObject(observedName);207}208},209new TestCase("Stop monitor within monitored getAttribute",210When.IN_GET_ATTRIBUTE) {211@Override212void doSensitiveThing(GaugeMonitorMBean monitorProxy,213ObjectName observedName) {214monitorProxy.stop();215}216},217new TestCase("Remove monitored MBean within threshold listener",218When.IN_NOTIFY) {219@Override220void doSensitiveThing(GaugeMonitorMBean monitorProxy,221ObjectName observedName) {222monitorProxy.removeObservedObject(observedName);223}224},225new TestCase("Stop monitor within threshold listener",226When.IN_NOTIFY) {227@Override228void doSensitiveThing(GaugeMonitorMBean monitorProxy,229ObjectName observedName) {230monitorProxy.stop();231}232},233};234235public static interface TestMBean {236public int getThing();237public void setThing(int thing);238public int getGetCount();239}240241public static class Test implements TestMBean {242public Test(Runnable runWithinGetAttribute) {243this.runWithinGetAttribute = runWithinGetAttribute;244}245246public int getThing() {247Thread t = new Thread(runWithinGetAttribute);248t.start();249try {250t.join();251} catch (InterruptedException e) {252throw new RuntimeException(e);253}254getCount++;255return thing;256}257258public void setThing(int thing) {259this.thing = thing;260}261262public int getGetCount() {263return getCount;264}265266private final Runnable runWithinGetAttribute;267private volatile int getCount;268private volatile int thing;269}270}271272273