/* * 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 getDebugMonitorsInfo() { List result = new ArrayList(); 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 actualData, List 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 actualData, List 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 actualData = null; try { actualData = threadReference.ownedMonitorsAndFrames(); } catch (Exception e) { setSuccess(false); log.complain("Unexpected exception: " + e); e.printStackTrace(log.getOutStream()); } List expectedData = getDebugMonitorsInfo(); compare(actualData, expectedData); } }