blob: b6f62434a04c972d6316d32c3d94cbc1efeabfae [file] [log] [blame]
/*
* Copyright (c) 2007, 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 nsk.monitoring.share.thread;
import java.lang.management.ThreadMXBean;
import java.lang.management.ThreadInfo;
import java.lang.management.MonitorInfo;
import java.lang.management.LockInfo;
import nsk.share.log.Log;
import nsk.share.log.LogAware;
import nsk.share.TestFailure;
import java.util.Map;
import java.util.HashMap;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.Lock;
/**
* Base class for all threads that are used in monitoring testing.
*/
public abstract class MonitoringThread extends ThreadMonitoringScenarioBase implements Runnable {
private final static String[] expectedMethods = {
"java.lang.Thread.run"
};
protected boolean expectedJava = true;
protected boolean expectedSuspended = false;
protected Thread runner;
public MonitoringThread(Log log) {
super(log);
}
/**
* Check that info for this thread is correct. This method is expected
* to be called between calls to waitState() and finish().
*
* @param info thread info
* @throws TestFailure when verification fails
*/
public void checkThreadInfo(ThreadInfo info) {
verify(info != null, "ThreadInfo is null");
verify(info.getThreadId() == runner.getId(), "info.getId() = " + info.getThreadId() + " != this.getId() " + runner.getId());
verify(info.getThreadName().equals(runner.getName()), "info.getName() = " + info.getThreadName() + " != this.getName() " + runner.getName());
verify(info.getThreadState().equals(runner.getState()), "info.getState() = " + info.getThreadState() + " != this.getState() " + runner.getState());
verify(checkStackTrace(info.getStackTrace()), "Verification of stack trace failed");
verify(info.isSuspended() == expectedSuspended, "ThreadInfo.isSuspended() = " + info.isSuspended() + " != " + expectedSuspended);
verify(info.isInNative() == !expectedJava, "ThreadInfo.isInNative() = " + info.isInNative() + " != " + !expectedJava);
}
public void begin() {
runner = new Thread(this);
runner.setName(this.getClass().getName() + '@' + System.identityHashCode(this) + "[id=" + runner.getId() + "]");
runner.setDaemon(true);
runner.start();
}
public abstract void waitState();
private void doCheck(ThreadInfo info, String description) {
try {
checkThreadInfo(info);
} catch (TestFailure t) {
log.info("Failed to check: " + description + " thread: " + this);
printThreadInfo(info);
throw t;
}
}
private void doCheck(ThreadInfo[] info, String description) {
verify(info.length == 1, "Failed to check: " + description + " thread: " + this + " length of returned array is wrong: " + info.length + " expected: " + 1);
doCheck(info[0], description);
}
public void check(ThreadMXBean threadMXBean) {
lockedMonitorsAvailable = false;
lockedSynchronizersAvailable = false;
doCheck(threadMXBean.getThreadInfo(runner.getId(), Integer.MAX_VALUE), "ThreadMXBean.getThreadInfo(long, int)");
doCheck(threadMXBean.getThreadInfo(runner.getId()), "ThreadMXBean.getThreadInfo(long)");
doCheck(threadMXBean.getThreadInfo(new long[] { runner.getId() }), "ThreadMXBean.getThreadInfo(long[])");
doCheck(threadMXBean.getThreadInfo(new long[] { runner.getId() }, Integer.MAX_VALUE), "ThreadMXBean.getThreadInfo(long[], int)");
lockedMonitorsAvailable = true;
lockedSynchronizersAvailable = true;
doCheck(threadMXBean.getThreadInfo(new long[] { runner.getId() }, true, true), "ThreadMXBean.getThreadInfo(long[], boolean, boolean)");
}
public abstract void finish();
public void end() {
try {
if (runner != null)
runner.join();
} catch (InterruptedException e) {
log.warn(e);
}
}
/**
* Run this thread.
*/
public abstract void run();
protected void waitThreadState(Thread.State state) {
ThreadUtils.waitThreadState(runner, state);
}
protected boolean isStackTraceElementExpected(StackTraceElement element) {
return super.isStackTraceElementExpected(element) || checkStackTraceElement(element, expectedMethods);
}
public final void setExpectedJava(boolean expectedJava) {
this.expectedJava = expectedJava;
}
public final long getId() {
return runner.getId();
}
public static void yield() {
Thread.yield();
}
}