/* * Copyright (c) 2003, 2019, 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.jvmti.PopFrame; import jdk.test.lib.Utils; import nsk.share.Consts; import nsk.share.Wicket; import java.io.PrintStream; /** * This test checks that after popping a method's frame by the JVMTI * function PopFrame(): *
  • lock acquired by the popped frame will be released *
  • no JVMTI events will be generated by the function PopFrame() */ public class popframe005 { static final long WAIT_TIME = Utils.adjustTimeout(2000); static volatile int testedStep = 0; /* 0- action no yet started 1- a frame is to be popped 2- checking monitors state 3- finishing the test */ static volatile int result = Consts.TEST_PASSED; private PrintStream out; private popFrameCls popFrameClsThr; private objWaiter objWaiterThr1, objWaiterThr2; private Object allThreadsStoppedBarrier = new Object(); private Wicket startGuarantee; private Wicket finishGuarantee; private Wicket allThreadsStoppedGuarantee; static { try { System.loadLibrary("popframe005"); } catch (UnsatisfiedLinkError e) { System.err.println("Could not load popframe005 library"); System.err.println("java.library.path:" + System.getProperty("java.library.path")); throw e; } } native static boolean doPopFrame(popFrameCls popFrameClsThr); public static void main(String[] argv) { argv = nsk.share.jvmti.JVMTITest.commonInit(argv); System.exit(run(argv, System.out) + Consts.JCK_STATUS_BASE); } public static int run(String argv[], PrintStream out) { return new popframe005().runIt(argv, out); } private int runIt(String argv[], PrintStream out) { Object lockObj[] = new Object[2]; this.out = out; lockObj[0] = new Object(); lockObj[1] = new Object(); startGuarantee = new Wicket("startGuarantee", 1, System.out); finishGuarantee = new Wicket("finishGuarantee", 1, System.out); allThreadsStoppedGuarantee = new Wicket("allThreadsStoppedGuarantee", 3, System.out); // start a thread whose top frame is to be popped popFrameClsThr = new popFrameCls("Tested Thread", lockObj); popFrameClsThr.start(); startGuarantee.waitFor(); // start a thread waiting for locked Object lockObj[0] objWaiterThr1 = new objWaiter(lockObj[0], 2); objWaiterThr1.start(); // start a thread waiting for locked Object lockObj[1] objWaiterThr2 = new objWaiter(lockObj[1], 0); objWaiterThr2.start(); // pause until the first thread exit notification-block allThreadsStoppedGuarantee.waitFor(); synchronized (allThreadsStoppedBarrier) { out.println("Passed barrier in main thread"); out.flush(); } /////////////////////// popping a frame //////////////////////// testedStep = 1; out.println("State transition: testedStep: 0->1"); out.println("Going to pop the frame..."); out.flush(); boolean retValue = doPopFrame(popFrameClsThr); popFrameClsThr.letItGo(); if (!retValue) return Consts.TEST_FAILED; ///////////////////// check monitors state ///////////////////// testedStep = 2; out.println("State transition: testedStep: 1->2"); out.flush(); if (!popFrameClsThr.isAlive()) { out.println("TEST FAILURE: thread with the method's popped frame is dead"); return Consts.TEST_FAILED; } try { objWaiterThr2.join(WAIT_TIME); } catch (InterruptedException e) { out.println("Joining the objWaiterThr2's thread: caught " + e); } if (objWaiterThr2.isAlive()) { // objWaiterThr2 should be dead out.println("TEST FAILED: Lock acquired by a popped frame wasn't released\n" + "\twhen the frame had been popped"); result = Consts.TEST_FAILED; } try { // don't want to wait too much if timeout.factor is big objWaiterThr1.join(Math.min(WAIT_TIME, 5000)); } catch (InterruptedException e) { out.println("Joining the objWaiterThr1's thread: caught " + e); out.flush(); } if (!objWaiterThr1.isAlive()) { // objWaiterThr2 should be alive out.println("TEST FAILED: Lock acquired by a frame, different from the popped one,\n" + "\twas released when the popped frame had been popped"); result = Consts.TEST_FAILED; } /////////////////////// finish the test /////////////////////// testedStep = 3; out.println("State transition: testedStep: 2->3"); out.flush(); finishGuarantee.unlock(); try { if (popFrameClsThr.isAlive()) popFrameClsThr.join(WAIT_TIME); } catch (InterruptedException e) { out.println("TEST INCOMPLETE: caught " + e); return Consts.TEST_FAILED; } if (popFrameClsThr.isAlive()) { out.println("TEST FAILED: thread with " + "the popped frame's method is still alive"); result = Consts.TEST_FAILED; } return result; } // a thread whose top frame is to be popped and which locks two Objects class popFrameCls extends Thread { private volatile boolean flag = true; private Object[] lockObj; popFrameCls(String name, Object[] obj) { super(name); lockObj = obj; } public void run() { synchronized(lockObj[0]) { activeMethod(); } out.println("popFrameCls (" + this + "): exiting..."); out.flush(); } public void activeMethod() { boolean compl = true; if (popframe005.testedStep != 0) { // popping has been done out.println("popFrameCls (" + this + "): enter activeMethod() after popping"); out.flush(); // wait for checking monitors state by the main thread finishGuarantee.waitFor(); out.println("popFrameCls (" + this + "): leaving activeMethod()"); out.flush(); return; } try { synchronized(lockObj[1]) { synchronized(allThreadsStoppedBarrier) { out.println("popFrameCls (" + this + "): inside activeMethod()"); out.flush(); // notify the main thread startGuarantee.unlock(); allThreadsStoppedGuarantee.unlock(); } // loop until the main thread pops us int i = 0; int n = 1000; while (flag) { if (n <= 0) { n = 1000; } if (i > n) { i = 0; n--; } i++; } } } catch (Exception e) { out.println("FAILURE: popFrameCls (" + this + "): caught " + e); out.flush(); compl = false; } finally { if (compl) { out.println("TEST FAILED: finally block was executed after popping"); out.flush(); } popframe005.result = Consts.TEST_FAILED; } } public void letItGo() { flag = false; } } // a thread which waits for a specified Object which is locked class objWaiter extends Thread { private Object lockObj; private String objIdent; private int contrVal; objWaiter(Object obj, int stepVal) { lockObj = obj; contrVal = stepVal; if (stepVal == 2) objIdent = "[0]"; else objIdent = "[1]"; } public void run() { // notify the main thread synchronized(allThreadsStoppedBarrier) { out.println("objWaiter(" + this + "): waiting for a lockObj" + objIdent + "'s monitor; testedStep=" + testedStep); out.flush(); allThreadsStoppedGuarantee.unlock(); } try { synchronized(lockObj) { if (testedStep <= contrVal) { out.println("TEST FAILED: the lockObj" + objIdent + "'s monitor became free too early"); result = Consts.TEST_FAILED; } else { out.println("Check PASSED: objWaiter(" + this + "): enter the lockObj" + objIdent + "'s monitor"); out.flush(); } } out.println("objWaiter (" + this + "): exiting..."); out.flush(); } catch (Exception e) { out.println("TEST FAILURE: objWaiter (" + this + "): caught " + e); } } } }