test/hotspot/jtreg/vmTestbase/nsk/share/jpda/AbstractDebuggeeTest.java
changeset 49934 44839fbb20db
equal deleted inserted replaced
49933:c63bdf53a1a7 49934:44839fbb20db
       
     1 /*
       
     2  * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.
       
     8  *
       
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    12  * version 2 for more details (a copy is included in the LICENSE file that
       
    13  * accompanied this code).
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License version
       
    16  * 2 along with this work; if not, write to the Free Software Foundation,
       
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    18  *
       
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    20  * or visit www.oracle.com if you need additional information or have any
       
    21  * questions.
       
    22  */
       
    23 
       
    24 //    THIS TEST IS LINE NUMBER SENSITIVE
       
    25 
       
    26 package nsk.share.jpda;
       
    27 
       
    28 import java.io.*;
       
    29 import java.util.*;
       
    30 import nsk.share.*;
       
    31 import nsk.share.test.*;
       
    32 import java.lang.management.GarbageCollectorMXBean;
       
    33 import java.lang.management.ManagementFactory;
       
    34 /*
       
    35  * Class can be used as base debuggee class in jdi and jdwp tests.
       
    36  * Class contains common method for initializing log, pipe, vm, and several common auxiliary methods.  Subclass should implement parseCommand() and, if needed, doInit(parse command line parameters)
       
    37  * !!! Edit carefully, value of 'DEFAULT_BREAKPOINT_LINE' is hardcoded !!!
       
    38  */
       
    39 public class AbstractDebuggeeTest {
       
    40     protected DebugeeArgumentHandler argHandler;
       
    41 
       
    42     protected IOPipe pipe;
       
    43 
       
    44     protected Log log;
       
    45 
       
    46     protected boolean callExit = true;
       
    47 
       
    48     private boolean success = true;
       
    49 
       
    50     protected void setSuccess(boolean value) {
       
    51         success = value;
       
    52     }
       
    53 
       
    54     public boolean getSuccess() {
       
    55         return success;
       
    56     }
       
    57 
       
    58     public final static int DEFAULT_BREAKPOINT_LINE = 63;
       
    59 
       
    60     public final static String DEFAULT_BREAKPOINT_METHOD_NAME = "breakpointMethod";
       
    61 
       
    62     public void breakpointMethod() {
       
    63         log.display("In breakpoint method: 'AbstractDebuggeeTest.breakpointMethod()'"); // DEFAULT_BREAKPOINT_LINE
       
    64     }
       
    65 
       
    66     protected Map<String, ClassUnloader> loadedClasses = new TreeMap<String, ClassUnloader>();
       
    67 
       
    68     public final static String COMMAND_FORCE_BREAKPOINT = "forceBreakpoint";
       
    69 
       
    70     //load class with given name with possibility to unload it
       
    71     static public final String COMMAND_LOAD_CLASS = "loadClass";
       
    72 
       
    73     // unload class with given name(it is possible for classes loaded via loadTestClass method)
       
    74     // command:className[:<unloadResult>], <unloadResult> - one of UNLOAD_RESULT_TRUE or UNLOAD_RESULT_FALSE
       
    75     static public final String COMMAND_UNLOAD_CLASS = "unloadClass";
       
    76 
       
    77     // Optional arguments of COMMAND_UNLOAD_CLASS
       
    78     // (is after unloading class should be really unloaded, default value is UNLOAD_RESULT_TRUE)
       
    79     static public final String UNLOAD_RESULT_TRUE = "unloadResultTrue";
       
    80 
       
    81     static public final String UNLOAD_RESULT_FALSE = "unloadResultFalse";
       
    82 
       
    83     static public final String COMMAND_CREATE_STATETESTTHREAD = "createStateTestThread";
       
    84 
       
    85     static public final String COMMAND_NEXTSTATE_STATETESTTHREAD = "stateTestThreadNextState";
       
    86 
       
    87     //force GC using AbstractDebuggeeTest.eatMemory()
       
    88     static public final String COMMAND_FORCE_GC = "forceGC";
       
    89     // GCcount is used to get information about GC activity during test
       
    90     static public final String COMMAND_GC_COUNT = "GCcount";
       
    91     private int lastGCCount;
       
    92 
       
    93 
       
    94     static public final String stateTestThreadName = "stateTestThread";
       
    95 
       
    96     static public final String stateTestThreadClassName = StateTestThread.class.getName();
       
    97 
       
    98     // path to classes intended for loading/unloading
       
    99     protected String classpath;
       
   100 
       
   101     // classloader loads only test classes from nsk.*
       
   102     public static class TestClassLoader extends CustomClassLoader {
       
   103         public Class<?> loadClass(String name) throws ClassNotFoundException {
       
   104             if (name.startsWith("nsk."))
       
   105                 return findClass(name);
       
   106             else
       
   107                 return super.loadClass(name);
       
   108         }
       
   109     }
       
   110 
       
   111     protected StressOptions stressOptions;
       
   112     protected Stresser stresser;
       
   113 
       
   114     // initialize test and remove unsupported by nsk.share.jdi.ArgumentHandler arguments
       
   115     // (ArgumentHandler constructor throws BadOption exception if command line contains unrecognized by ArgumentHandler options)
       
   116     // support -testClassPath parameter: path to find classes for custom classloader
       
   117     protected String[] doInit(String[] args) {
       
   118         stressOptions = new StressOptions(args);
       
   119         stresser = new Stresser(stressOptions);
       
   120 
       
   121         ArrayList<String> standardArgs = new ArrayList<String>();
       
   122 
       
   123         for (int i = 0; i < args.length; i++) {
       
   124             if (args[i].equals("-testClassPath") && (i < args.length - 1)) {
       
   125                 classpath = args[i + 1];
       
   126                 i++;
       
   127             } else
       
   128                 standardArgs.add(args[i]);
       
   129         }
       
   130 
       
   131         return standardArgs.toArray(new String[] {});
       
   132     }
       
   133 
       
   134     public void loadTestClass(String className) {
       
   135         if (classpath == null) {
       
   136             throw new TestBug("Debuggee requires 'testClassPath' parameter");
       
   137         }
       
   138 
       
   139         try {
       
   140             ClassUnloader classUnloader = new ClassUnloader();
       
   141 
       
   142             classUnloader.setClassLoader(new TestClassLoader());
       
   143             classUnloader.loadClass(className, classpath);
       
   144             loadedClasses.put(className, classUnloader);
       
   145         } catch (ClassNotFoundException e) {
       
   146             log.complain("Unexpected 'ClassNotFoundException' on loading of the requested class(" + className + ")");
       
   147             e.printStackTrace(log.getOutStream());
       
   148             throw new TestBug("Unexpected 'ClassNotFoundException' on loading of the requested class(" + className + ")");
       
   149         }
       
   150     }
       
   151 
       
   152     public static final int MAX_UNLOAD_ATTEMPS = 5;
       
   153 
       
   154     public void unloadTestClass(String className, boolean expectedUnloadingResult) {
       
   155         ClassUnloader classUnloader = loadedClasses.get(className);
       
   156 
       
   157         int unloadAttemps = 0;
       
   158 
       
   159         if (classUnloader != null) {
       
   160             boolean wasUnloaded = false;
       
   161 
       
   162             while (!wasUnloaded && (unloadAttemps++ < MAX_UNLOAD_ATTEMPS)) {
       
   163                 wasUnloaded = classUnloader.unloadClass();
       
   164             }
       
   165 
       
   166             if (wasUnloaded)
       
   167                 loadedClasses.remove(className);
       
   168             else {
       
   169                 log.display("Class " + className + " was not unloaded");
       
   170             }
       
   171 
       
   172             if (wasUnloaded != expectedUnloadingResult) {
       
   173                 setSuccess(false);
       
   174 
       
   175                 if (wasUnloaded)
       
   176                     log.complain("Class " + className + " was unloaded!");
       
   177                 else
       
   178                     log.complain("Class " + className + " wasn't unloaded!");
       
   179             }
       
   180         } else {
       
   181             log.complain("Invalid command 'unloadClass' is requested: class " + className + " was not loaded via ClassUnloader");
       
   182             throw new TestBug("Invalid command 'unloadClass' is requested: class " + className + " was not loaded via ClassUnloader");
       
   183         }
       
   184     }
       
   185 
       
   186     static public void sleep1sec() {
       
   187         try {
       
   188             Thread.sleep(1000);
       
   189         } catch (InterruptedException e) {
       
   190         }
       
   191     }
       
   192 
       
   193     private StateTestThread stateTestThread;
       
   194 
       
   195     public static final String COMMAND_QUIT = "quit";
       
   196 
       
   197     public static final String COMMAND_READY = "ready";
       
   198 
       
   199     private void createStateTestThread() {
       
   200         if (stateTestThread != null)
       
   201             throw new TestBug("StateTestThread already created");
       
   202 
       
   203         stateTestThread = new StateTestThread(stateTestThreadName);
       
   204     }
       
   205 
       
   206     private void stateTestThreadNextState() {
       
   207         if (stateTestThread == null)
       
   208             throw new TestBug("StateTestThread not created");
       
   209 
       
   210         stateTestThread.nextState();
       
   211     }
       
   212 
       
   213     public boolean parseCommand(String command) {
       
   214         try {
       
   215             StreamTokenizer tokenizer = new StreamTokenizer(new StringReader(command));
       
   216             tokenizer.whitespaceChars(':', ':');
       
   217             tokenizer.wordChars('_', '_');
       
   218             tokenizer.wordChars('$', '$');
       
   219             tokenizer.wordChars('[', ']');
       
   220 
       
   221             if (command.equals(COMMAND_FORCE_GC)) {
       
   222                 forceGC();
       
   223                 lastGCCount = getCurrentGCCount();
       
   224                 return true;
       
   225             } else if (command.equals(COMMAND_GC_COUNT)) {
       
   226                 pipe.println(COMMAND_GC_COUNT + ":" + (getCurrentGCCount() - lastGCCount));
       
   227                 return true;
       
   228             }   else if (command.equals(COMMAND_FORCE_BREAKPOINT)) {
       
   229                 breakpointMethod();
       
   230                 return true;
       
   231             } else if (command.equals(COMMAND_CREATE_STATETESTTHREAD)) {
       
   232                 createStateTestThread();
       
   233 
       
   234                 return true;
       
   235             } else if (command.equals(COMMAND_NEXTSTATE_STATETESTTHREAD)) {
       
   236                 stateTestThreadNextState();
       
   237 
       
   238                 return true;
       
   239             } else if (command.startsWith(COMMAND_LOAD_CLASS)) {
       
   240                 tokenizer.nextToken();
       
   241 
       
   242                 if (tokenizer.nextToken() != StreamTokenizer.TT_WORD)
       
   243                     throw new TestBug("Invalid command format: " + command);
       
   244 
       
   245                 String className = tokenizer.sval;
       
   246 
       
   247                 loadTestClass(className);
       
   248 
       
   249                 return true;
       
   250             } else if (command.startsWith(COMMAND_UNLOAD_CLASS)) {
       
   251                 tokenizer.nextToken();
       
   252 
       
   253                 if (tokenizer.nextToken() != StreamTokenizer.TT_WORD)
       
   254                     throw new TestBug("Invalid command format: " + command);
       
   255 
       
   256                 String className = tokenizer.sval;
       
   257 
       
   258                 boolean expectedUnloadingResult = true;
       
   259 
       
   260                 if (tokenizer.nextToken() == StreamTokenizer.TT_WORD) {
       
   261                     if (tokenizer.sval.equals(UNLOAD_RESULT_TRUE))
       
   262                         expectedUnloadingResult = true;
       
   263                     else if (tokenizer.sval.equals(UNLOAD_RESULT_FALSE))
       
   264                         expectedUnloadingResult = false;
       
   265                     else
       
   266                         throw new TestBug("Invalid command format: " + command);
       
   267                 }
       
   268 
       
   269                 unloadTestClass(className, expectedUnloadingResult);
       
   270 
       
   271                 return true;
       
   272             }
       
   273         } catch (IOException e) {
       
   274             throw new TestBug("Invalid command format: " + command);
       
   275         }
       
   276 
       
   277         return false;
       
   278     }
       
   279 
       
   280     protected DebugeeArgumentHandler createArgumentHandler(String args[]) {
       
   281         return new DebugeeArgumentHandler(args);
       
   282     }
       
   283 
       
   284     protected void init(String args[]) {
       
   285         argHandler = createArgumentHandler(doInit(args));
       
   286         pipe = argHandler.createDebugeeIOPipe();
       
   287         log = argHandler.createDebugeeLog();
       
   288         lastGCCount = getCurrentGCCount();
       
   289     }
       
   290 
       
   291     public void initDebuggee(DebugeeArgumentHandler argHandler, Log log, IOPipe pipe, String[] args, boolean callExit) {
       
   292         this.argHandler = argHandler;
       
   293         this.log = log;
       
   294         this.pipe = pipe;
       
   295         this.callExit = callExit;
       
   296         doInit(args);
       
   297     }
       
   298 
       
   299     public void doTest(String args[]) {
       
   300         init(args);
       
   301         doTest();
       
   302     }
       
   303 
       
   304     public void doTest() {
       
   305         do {
       
   306             log.display("Debuggee " + getClass().getName() + " : sending the command: " + AbstractDebuggeeTest.COMMAND_READY);
       
   307             pipe.println(AbstractDebuggeeTest.COMMAND_READY);
       
   308 
       
   309             String command = pipe.readln();
       
   310             log.display("Debuggee: received the command: " + command);
       
   311 
       
   312             if (command.equals(AbstractDebuggeeTest.COMMAND_QUIT)) {
       
   313                 break;
       
   314             } else {
       
   315                 try {
       
   316                     if (!parseCommand(command)) {
       
   317                         log.complain("TEST BUG: unknown debugger command: " + command);
       
   318                         System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED);
       
   319                     }
       
   320                 } catch (Throwable t) {
       
   321                     log.complain("Unexpected exception in debuggee: " + t);
       
   322                     t.printStackTrace(log.getOutStream());
       
   323                     System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED);
       
   324                 }
       
   325             }
       
   326         } while (true);
       
   327 
       
   328         log.display("Debuggee: exiting");
       
   329 
       
   330         if (callExit) {
       
   331             if (success)
       
   332                 System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_PASSED);
       
   333             else
       
   334                 System.exit(Consts.JCK_STATUS_BASE + Consts.TEST_FAILED);
       
   335         }
       
   336     }
       
   337 
       
   338     public static void eatMemory() {
       
   339         Runtime runtime = Runtime.getRuntime();
       
   340         long maxMemory = runtime.maxMemory();
       
   341         int memoryChunk = (int) (maxMemory / 50);
       
   342         try {
       
   343             List<Object> list = new ArrayList<Object>();
       
   344             while (true) {
       
   345                 list.add(new byte[memoryChunk]);
       
   346             }
       
   347         } catch (OutOfMemoryError e) {
       
   348             // expected exception
       
   349         }
       
   350     }
       
   351 
       
   352     public static int getCurrentGCCount() {
       
   353         int result = 0;
       
   354         List<GarbageCollectorMXBean> gcBeans = ManagementFactory.getGarbageCollectorMXBeans();
       
   355         for (GarbageCollectorMXBean bean : gcBeans) {
       
   356             result += bean.getCollectionCount();
       
   357         }
       
   358         return result;
       
   359     }
       
   360 
       
   361     public void forceGC() {
       
   362         eatMemory();
       
   363     }
       
   364 
       
   365     public void voidValueMethod() {
       
   366     }
       
   367 
       
   368     public void unexpectedException(Throwable t) {
       
   369         setSuccess(false);
       
   370         t.printStackTrace(log.getOutStream());
       
   371         log.complain("Unexpected exception: " + t);
       
   372     }
       
   373 
       
   374 }