Path: blob/master/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/MonitorEventsDebuggee.java
41162 views
/*1* Copyright (c) 2006, 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*/22package nsk.share.jdi;2324import java.util.*;25import nsk.share.TestBug;26import nsk.share.locks.MonitorLockingThread;2728/*29* This class generates MonitorWaitEvent and MonitorWaitedEvent30*/31class MonitorWaitExecutor extends EventActionsExecutor {32// MonitorWaited event may occurs when waiting thread was interrupted,33// notified by notify or notifyAll, or when timeout expired34enum ExitFromWaitType {35EXIT_WITH_TIMEOUT,36INTERRUPT,37NOTIFY,38NOTIFY_ALL39}4041// this thread forces MonitorWaitExecutor to exit from wait()42class AuxiliaryThread extends Thread {43private Thread threadToInterrupt;4445private Object monitor;4647public AuxiliaryThread(Thread threadToInterrupt, Object monitor) {48this.threadToInterrupt = threadToInterrupt;49this.monitor = monitor;50}5152public void run() {53// wait when interrupted thread switches state to 'TIMED_WAITING'54while ((threadToInterrupt.getState() != Thread.State.WAITING) && !exitedFromWait) {55Thread.yield();56}5758// threadToInterrupt 'spuriously' exited from wait()59if(exitedFromWait)60return;6162if (exitFromWaitType == ExitFromWaitType.INTERRUPT) {63threadToInterrupt.interrupt();64} else if ((exitFromWaitType == ExitFromWaitType.NOTIFY)65|| (exitFromWaitType == ExitFromWaitType.NOTIFY_ALL)) {66/*67* NOTE: thread's state WAITING doesn't guarantee that thread released68* monitor, and entering to the next synchronized block may cause MonitorContentedEnterEvent69* (if corresponding request was created).70*71* Debugger should take in account this issue.72*/73synchronized (monitor) {74if (exitFromWaitType == ExitFromWaitType.NOTIFY)75monitor.notify();76else if (exitFromWaitType == ExitFromWaitType.NOTIFY_ALL)77monitor.notifyAll();78}79}80}81}8283// thread may 'spuriously' exit from wait(), in this case AuxiliaryThread shouldn't wait 'WAITING' state84private volatile boolean exitedFromWait;8586// save data about MonitorWait events87private boolean monitorWait;8889// save data about MonitorWaited events90private boolean monitorWaited;9192public MonitorWaitExecutor(boolean monitorWait, boolean monitorWaited) {93this.monitorWait = monitorWait;94this.monitorWaited = monitorWaited;95}9697protected ExitFromWaitType exitFromWaitType;9899public void doEventAction() {100for (ExitFromWaitType exitType : ExitFromWaitType.values()) {101exitFromWaitType = exitType;102103monitorWait();104}105}106107protected void monitorWait() {108109exitedFromWait = false;110111long timeout;112113if (exitFromWaitType == ExitFromWaitType.EXIT_WITH_TIMEOUT)114timeout = 100;115else116timeout = 0;117118if (monitorWait) {119DebuggeeEventData.DebugMonitorWaitEventData eventData = new DebuggeeEventData.DebugMonitorWaitEventData(120this, Thread.currentThread(), timeout, this);121addEventData(eventData);122}123124if (monitorWaited) {125DebuggeeEventData.DebugMonitorWaitedEventData eventData = new DebuggeeEventData.DebugMonitorWaitedEventData(126this, Thread.currentThread(),127(exitFromWaitType == ExitFromWaitType.EXIT_WITH_TIMEOUT),128this);129addEventData(eventData);130}131132AuxiliaryThread auxiliaryThread = null;133134if (exitFromWaitType != ExitFromWaitType.EXIT_WITH_TIMEOUT) {135auxiliaryThread = new AuxiliaryThread(Thread.currentThread(), this);136auxiliaryThread.start();137}138139try {140eventMethod(timeout);141} catch (InterruptedException e) {142// expected exception143}144145exitedFromWait = true;146147if (auxiliaryThread != null) {148// don't using join, because of join is realized with using of149// wait(), and this method can generate unexpected events150while (auxiliaryThread.getState() != Thread.State.TERMINATED)151Thread.yield();152}153}154155// move event actions to the separate method to simplify method redifinition156// in subclasses157synchronized protected void eventMethod(long timeout)158throws InterruptedException {159wait(timeout);160}161162}163164/*165* Subclass of MonitorWaitExecutor, define its own event method(copy of parent166* method), intended for event filters test167*/168class MonitorWaitExecutor_1Subclass extends MonitorWaitExecutor {169public MonitorWaitExecutor_1Subclass(boolean monitorWait,170boolean monitorWaited) {171super(monitorWait, monitorWaited);172}173174synchronized protected void eventMethod(long timeout)175throws InterruptedException {176wait(timeout);177}178}179180/*181* Subclass of MonitorWaitExecutor, define its own event method(copy of parent182* method), intended for event filters test183*/184class MonitorWaitExecutor_2Subclass extends MonitorWaitExecutor_1Subclass {185public MonitorWaitExecutor_2Subclass(boolean monitorWait,186boolean monitorWaited) {187super(monitorWait, monitorWaited);188}189190synchronized protected void eventMethod(long timeout)191throws InterruptedException {192wait(timeout);193}194}195196/*197* This class generates MonitorContendedEnterEvent and198* MonitorContendedEnteredEvent199*/200class MonitorEnterExecutor extends EventActionsExecutor {201/*202* Types of monitor acquiring:203* - through synchronized block204* - through synchronized method205* - through JNI MonitorEnter206*/207static enum MonitorAcquireType {208SYNCHRONIZED_BLOCK,209SYNCHRONIZED_METHOD,210JNI_MONITOR_ENTER211}212213// native method uses this class214private static final Class<?> jniError = nsk.share.TestJNIError.class;215216217static final String nativeLibararyName = "MonitorEnterExecutor";218219static {220System.loadLibrary(nativeLibararyName);221}222223// this thread forces MonitorLockingThread to release holding lock224static class LockFreeThread extends Thread {225private Thread blockedThread;226227private MonitorLockingThread lockingThread;228229public LockFreeThread(Thread blockedThread,230MonitorLockingThread lockingThread) {231this.blockedThread = blockedThread;232this.lockingThread = lockingThread;233}234235public void run() {236// wait when blocked thread switches state to 'BLOCKED'237while (blockedThread.getState() != Thread.State.BLOCKED)238Thread.yield();239240lockingThread.releaseLock();241}242}243244private boolean monitorEnter;245246private boolean monitorEntered;247248public MonitorEnterExecutor(boolean monitorEnter, boolean monitorEntered) {249this.monitorEnter = monitorEnter;250this.monitorEntered = monitorEntered;251}252253protected void monitorEnter() {254// locking thread acquires 'this' lock255MonitorLockingThread lockingThread = new MonitorLockingThread(this);256lockingThread.acquireLock();257258if (monitorEnter) {259DebuggeeEventData.DebugMonitorEnterEventData eventData = new DebuggeeEventData.DebugMonitorEnterEventData(260this, Thread.currentThread(), this);261addEventData(eventData);262}263if (monitorEntered) {264DebuggeeEventData.DebugMonitorEnteredEventData eventData = new DebuggeeEventData.DebugMonitorEnteredEventData(265this, Thread.currentThread(), this);266addEventData(eventData);267}268269/*270* This thread forces lockingThread to free 'this' lock when current thread's state will change to 'BLOCKED'271*272* NOTE: this method to provoke MonitorContended events isn't 100% robust273* Tests should take in account this issue.274*275*/276LockFreeThread lockFreeThread = new LockFreeThread(Thread.currentThread(), lockingThread);277lockFreeThread.start();278279// try to acquire 'this' lock280eventMethod();281282while(lockingThread.getState() != Thread.State.TERMINATED)283Thread.yield();284285while(lockFreeThread.getState() != Thread.State.TERMINATED)286Thread.yield();287}288289private MonitorAcquireType monitorAcquireType;290291// generate events in different ways292public void doEventAction() {293for (MonitorAcquireType monitorAcquireType : MonitorAcquireType.values()) {294this.monitorAcquireType = monitorAcquireType;295monitorEnter();296}297}298299protected void eventMethod() {300switch (monitorAcquireType) {301case SYNCHRONIZED_BLOCK:302synchronizedBlock();303break;304case SYNCHRONIZED_METHOD:305synchronizedMethod();306break;307case JNI_MONITOR_ENTER:308nativeJNIMonitorEnter();309break;310311default:312throw new TestBug("Invalid monitorAcquireType: "313+ monitorAcquireType);314}315}316317// move event actions to the separate methods to simplify method318// redifinition in subclasses:319320protected void synchronizedBlock() {321// MonitorContendedEnterEvent and MonitorContendedEnteredEvent should occur here322synchronized (this) {323// don't expect events for following synchronized block324synchronized (this) {325}326}327}328329// MonitorContendedEnterEvent and MonitorContendedEnteredEvent should occur here330synchronized protected void synchronizedMethod() {331// don't expect events for following synchronized block332synchronized (this) {333}334}335336// call JNI methods MonitorEnter and MonitorExit for 'this' object337protected native void nativeJNIMonitorEnter();338339}340341/*342* Subclass of MonitorEnterExecutor, defines its own event methods(copy of parent343* method), intended for event filters test344*/345class MonitorEnterExecutor_1Subclass extends MonitorEnterExecutor {346static {347System.loadLibrary(nativeLibararyName);348}349350public MonitorEnterExecutor_1Subclass(boolean monitorEnter,351boolean monitorEntered) {352super(monitorEnter, monitorEntered);353}354355protected void synchronizedBlock() {356// MonitorContendedEnterEvent and MonitorContendedEnteredEvent should occur here357synchronized (this) {358}359}360361// MonitorContendedEnterEvent and MonitorContendedEnteredEvent should occur here362synchronized protected void synchronizedMethod() {363}364365// call JNI methods MonitorEnter and MonitorExit for 'this' object366protected native void nativeJNIMonitorEnter();367}368369/*370* Subclass of MonitorEnterExecutor, defines its own event methods(copy of parent371* method), intended for event filters test372*/373class MonitorEnterExecutor_2Subclass extends MonitorEnterExecutor_1Subclass {374static {375System.loadLibrary(nativeLibararyName);376}377378public MonitorEnterExecutor_2Subclass(boolean monitorEnter,379boolean monitorEntered) {380super(monitorEnter, monitorEntered);381}382383protected void synchronizedBlock() {384// MonitorContendedEnterEvent and MonitorContendedEnteredEvent should occur here385synchronized (this) {386}387}388389// MonitorContendedEnterEvent and MonitorContendedEnteredEvent should occur here390synchronized protected void synchronizedMethod() {391}392393// call JNI methods MonitorEnter and MonitorExit for 'this' object394protected native void nativeJNIMonitorEnter();395}396397/*398* Class is used as base debuggee in tests for following events and event requests:399* - MonitorContendedEnterRequest / MonitorContendedEnterEvent400* - MonitorContendedEnteredRequest / MonitorContendedEnteredEvent401* - MonitorWaitRequest / MonitorWaitEvent402* - MonitorWaitedRequest / MonitorWaitedEvent403*/404public class MonitorEventsDebuggee extends JDIEventsDebuggee {405public static void main(String[] args) {406MonitorEventsDebuggee debuggee = new MonitorEventsDebuggee();407debuggee.doTest(args);408}409410protected void createActionsExecutors(String description, int eventsCount) {411boolean monitorEnter = description412.contains(JDIEventsDebugger.EventType.MONITOR_CONTENTED_ENTER413.name());414boolean monitorEntered = description415.contains(JDIEventsDebugger.EventType.MONITOR_CONTENTED_ENTERED416.name());417boolean monitorWait = description418.contains(JDIEventsDebugger.EventType.MONITOR_WAIT.name());419boolean monitorWaited = description420.contains(JDIEventsDebugger.EventType.MONITOR_WAITED.name());421422if (monitorEnter || monitorEntered || monitorWait || monitorWaited) {423createActionsExecutors(monitorEnter, monitorEntered, monitorWait,424monitorWaited, eventsCount);425} else426throw new TestBug(427"Invalid command format (required event not specified)");428}429430private List<DebuggeeEventData.DebugMonitorEventData> eventsData = new ArrayList<DebuggeeEventData.DebugMonitorEventData>();431432protected void clearResults() {433super.clearResults();434eventsData.clear();435}436437private void createActionsExecutors(boolean monitorEnter,438boolean monitorEntered, boolean monitorWait, boolean monitorWaited,439int actionsCount) {440EventActionsThread thread;441442// create 3 instances of generating objects of 3 different classes (for443// event filters tests)444if (monitorEnter || monitorEntered) {445thread = new EventActionsThread(new MonitorEnterExecutor(446monitorEnter, monitorEntered), actionsCount);447thread.start();448eventActionsExecutorsPool.add(thread);449450thread = new EventActionsThread(new MonitorEnterExecutor_1Subclass(451monitorEnter, monitorEntered), actionsCount);452thread.start();453eventActionsExecutorsPool.add(thread);454455thread = new EventActionsThread(new MonitorEnterExecutor_2Subclass(456monitorEnter, monitorEntered), actionsCount);457thread.start();458eventActionsExecutorsPool.add(thread);459}460461// create 3 instances of generating objects of 3 different classes (for462// event filters tests)463if (monitorWait || monitorWaited) {464thread = new EventActionsThread(new MonitorWaitExecutor(465monitorWait, monitorWaited), actionsCount);466thread.start();467eventActionsExecutorsPool.add(thread);468469thread = new EventActionsThread(new MonitorWaitExecutor_1Subclass(470monitorWait, monitorWaited), actionsCount);471thread.start();472eventActionsExecutorsPool.add(thread);473474thread = new EventActionsThread(new MonitorWaitExecutor_2Subclass(475monitorWait, monitorWaited), actionsCount);476thread.start();477eventActionsExecutorsPool.add(thread);478}479}480481// start event generating threads and wait when all this threads finish482// execution483// override parent method because of Thread.join() used in parent method484// generates unexpected MonitorWait/MonitorWaited events485protected void startExecution() {486if (eventActionsExecutorsPool.size() == 0) {487throw new TestBug("ActionsExecutors were not created");488}489490for (EventActionsThread thread : eventActionsExecutorsPool) {491thread.startExecution();492}493494// wait completion of test threads in separate thread to free thread listening commands495executionControllingThread = new Thread(496new Runnable() {497public void run() {498boolean executionCompleted;499do {500try {501// give time to event generators502Thread.sleep(500);503} catch (InterruptedException e) {504unexpectedException(e);505}506executionCompleted = true;507for (EventActionsThread thread : eventActionsExecutorsPool) {508if (thread.isAlive()) {509executionCompleted = false;510break;511}512}513} while (!executionCompleted);514515completeExecution();516}517});518519executionControllingThread.start();520}521522}523524525