blob: 1c183b248af0fb23e499aa342accff0c51f3f299 [file] [log] [blame]
/*
* Copyright (c) 2006, 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.share.jdi;
import java.io.*;
import java.util.*;
import com.sun.jdi.*;
import nsk.share.Consts;
/*
* Class is used as base debugger in tests for ThreadReference.ownedMonitorsAndFrames().
*
* In all this test similar scenario is used:
* - debugger VM force debugge VM to create test thread which acquires different monitors
* - when test thread acquire all monitors debuggee save information about all acquired monitors in special array 'monitorsInfo'
* - debugger read data from 'monitorsInfo' and compare it with data returned by ThreadReference.ownedMonitorsAndFrames()
*/
public class OwnedMonitorsDebugger extends TestDebuggerType2 {
/*
* debug data about monitor acquired by debuggee test thread,
* intended to compare with data returned by ThreadReference.ownedMonitorsAndFrames
*/
public static class DebugMonitorInfo {
// create DebugMonitorInfo using mirror of instance of nsk.share.locks.LockingThread.DebugMonitorInfo
DebugMonitorInfo(ObjectReference debuggeeMirror) {
monitor = (ObjectReference) debuggeeMirror.getValue(debuggeeMirror.referenceType().fieldByName("monitor"));
stackDepth = ((IntegerValue) debuggeeMirror.getValue(debuggeeMirror.referenceType().fieldByName("stackDepth"))).intValue();
thread = (ThreadReference) debuggeeMirror.getValue(debuggeeMirror.referenceType().fieldByName("thread"));
}
public DebugMonitorInfo(ObjectReference monitor, int stackDepth, ThreadReference thread) {
this.monitor = monitor;
this.stackDepth = stackDepth;
this.thread = thread;
}
public ObjectReference monitor;
public int stackDepth;
public ThreadReference thread;
}
public static void main(String argv[]) {
System.exit(run(argv, System.out) + Consts.JCK_STATUS_BASE);
}
public static int run(String argv[], PrintStream out) {
return new OwnedMonitorsDebugger().runIt(argv, out);
}
protected boolean canRunTest() {
if (!vm.canGetMonitorFrameInfo()) {
log.display("TEST CANCELED due to: vm.canGetMonitorFrameInfo() = false");
return false;
} else
return super.canRunTest();
}
protected String debuggeeClassName() {
return OwnedMonitorsDebuggee.class.getName();
}
// read debuggee's array 'monitorsInfo' containing information about acquired monitors
protected List<DebugMonitorInfo> getDebugMonitorsInfo() {
List<DebugMonitorInfo> result = new ArrayList<DebugMonitorInfo>();
ReferenceType referenceType = debuggee.classByName(debuggeeClassNameWithoutArgs());
ArrayReference monitorsInfo = (ArrayReference) referenceType.getValue(referenceType.fieldByName("monitorsInfo"));
for (int i = 0; i < monitorsInfo.length(); i++)
result.add(new DebugMonitorInfo((ObjectReference) monitorsInfo.getValue(i)));
return result;
}
private boolean compare(MonitorInfo actual, DebugMonitorInfo expected) {
boolean success = true;
if (actual.stackDepth() != expected.stackDepth) {
setSuccess(false);
success = false;
log.complain("Expected and actual monitor(" + actual.monitor() + ") stack depth differs, expected: " + expected.stackDepth + " actual: "
+ actual.stackDepth());
}
if (!actual.thread().equals(expected.thread)) {
setSuccess(false);
success = false;
log.complain("Expected and actual monitor(" + actual.monitor() + " thread differs, expected: " + expected.thread + " actual: "
+ actual.thread());
}
return success;
}
protected void compare(List<MonitorInfo> actualData, List<DebugMonitorInfo> expectedData) {
boolean success = true;
// compare total amount of monitors
if (actualData.size() != expectedData.size()) {
setSuccess(false);
success = false;
log.complain("Number of expected monitors and actual ones differs");
log.complain("Expected: " + expectedData.size() + ", actual: " + actualData.size());
}
// check that all expected monitors are contained in 'actualData'
for (DebugMonitorInfo expectedMonitorInfo : expectedData) {
boolean isMonitorFound = false;
for (MonitorInfo actualMonitorInfo : actualData) {
if (expectedMonitorInfo.monitor.equals(actualMonitorInfo.monitor())) {
isMonitorFound = true;
if (!compare(actualMonitorInfo, expectedMonitorInfo))
success = false;
break;
}
}
if (!isMonitorFound) {
setSuccess(false);
success = false;
log.complain("Expected monitor not found in result of ownedMonitorsAndFrames(): " + expectedMonitorInfo.monitor);
}
}
// check that all monitors from 'actualData' are contained in
// 'expectedData'
for (MonitorInfo actualMonitorInfo : actualData) {
boolean isMonitorFound = false;
for (DebugMonitorInfo expectedMonitorInfo : expectedData) {
if (actualMonitorInfo.monitor().equals(expectedMonitorInfo.monitor)) {
isMonitorFound = true;
break;
}
}
if (!isMonitorFound) {
setSuccess(false);
success = false;
log.complain("Unexpected monitor in result of ownedMonitorsAndFrames(): " + actualMonitorInfo.monitor() + " Depth: "
+ actualMonitorInfo.stackDepth() + " Thread: " + actualMonitorInfo.thread());
}
}
if (!success)
logDebugInfo(actualData, expectedData);
}
private void logDebugInfo(List<MonitorInfo> actualData, List<DebugMonitorInfo> expectedData) {
log.display("ACTUAL MONITORS (total " + actualData.size() + "):");
ThreadReference thread = null;
for (MonitorInfo monitorInfo : actualData) {
log.display("Monitor: " + monitorInfo.monitor());
log.display("Depth: " + monitorInfo.stackDepth());
log.display("Thread: " + monitorInfo.thread());
if (thread == null)
thread = monitorInfo.thread();
}
log.display("EXPECTED MONITORS (total " + expectedData.size() + "):");
for (DebugMonitorInfo monitorInfo : expectedData) {
log.display("Monitor: " + monitorInfo.monitor);
log.display("Depth: " + monitorInfo.stackDepth);
log.display("Thread: " + monitorInfo.thread);
if (thread == null)
thread = monitorInfo.thread;
}
if (thread != null) {
try {
log.display("Thread frames:");
for (StackFrame frame : thread.frames()) {
Location location = frame.location();
log.display(location.declaringType().name() + "." + location.method().name() + ", line: " + location.lineNumber());
}
} catch (Exception e) {
unexpectedException(e);
}
}
}
/*
* Check that ThreadReference.ownedMonitorsAndFrames() returns correct
* data before calling this method debuggee should save information about
* acquired monitors in special array 'monitorsInfo',
* debugger forces debuggee to do it using command 'COMMAND_UPDATE_MONITOR_INFO'
*/
protected void checkMonitorInfo(ThreadReference threadReference) {
List<MonitorInfo> actualData = null;
try {
actualData = threadReference.ownedMonitorsAndFrames();
} catch (Exception e) {
setSuccess(false);
log.complain("Unexpected exception: " + e);
e.printStackTrace(log.getOutStream());
}
List<DebugMonitorInfo> expectedData = getDebugMonitorsInfo();
compare(actualData, expectedData);
}
}