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 package nsk.share.jdi;
  24 
  25 import java.io.*;
  26 import java.util.*;
  27 import nsk.share.TestBug;
  28 
  29 /*
  30  *  Subclasses of this class generate events and if needed
  31  *  save debug information about generated events
  32  */
  33 abstract class EventActionsExecutor {
  34     // should this event generator save information about generated events
  35     public boolean saveEventData;
  36 
  37     // information about generated events(this data available for debugger)
  38     public List<DebuggeeEventData.DebugEventData> debugEventDataList = new ArrayList<DebuggeeEventData.DebugEventData>();
  39 
  40     public abstract void doEventAction();
  41 
  42     protected void addEventData(DebuggeeEventData.DebugEventData eventData) {
  43         if (saveEventData)
  44             debugEventDataList.add(eventData);
  45     }
  46 
  47     public void clearDebugData() {
  48         debugEventDataList.clear();
  49     }
  50 }
  51 
  52 /*
  53  * Class handles commands for running given number of threads which generate
  54  * given events. Objects which generate events save information about generated
  55  * events and this data available for debugger
  56  *
  57  * Class was written to test monitor evens(MonitorWaitEvent, MonitorWaitedEvent,
  58  * MonitorContendedEnterEvent, MonitorContendedEnteredEvent), possible it can be
  59  * used in tests for other events
  60  */
  61 abstract public class JDIEventsDebuggee extends AbstractJDIDebuggee {
  62     protected String[] doInit(String[] args) {
  63         Thread.currentThread().setName(MAIN_THREAD_NAME);
  64         return super.doInit(args);
  65     }
  66 
  67     public static final String MAIN_THREAD_NAME = "JDIEventsDebuggee_MainThread";
  68 
  69     // command:events_count:event types
  70     public static final String COMMAND_CREATE_ACTIONS_EXECUTORS = "createActionsExecutors";
  71 
  72     // command
  73     public static final String COMMAND_START_EXECUTION = "startExecution";
  74 
  75     // command
  76     public static final String COMMAND_WAIT_EXECUTION_COMPLETION = "waitExecutionCompletion";
  77 
  78     // command
  79     public static final String COMMAND_STOP_EXECUTION = "stopExecution";
  80 
  81     protected List<EventActionsThread> eventActionsExecutorsPool = new ArrayList<EventActionsThread>();
  82 
  83     // initialize with empty array
  84     public static DebuggeeEventData.DebugEventData generatedEvents[] = new DebuggeeEventData.DebugEventData[0];
  85 
  86     // debuggee's main thread also can generate events and information about
  87     // this events should be saved (like for event generators)
  88     protected boolean saveEventData;
  89 
  90     public boolean parseCommand(String command) {
  91         if (super.parseCommand(command))
  92             return true;
  93 
  94         StreamTokenizer tokenizer = new StreamTokenizer(new StringReader(
  95                 command));
  96         tokenizer.whitespaceChars(':', ':');
  97         tokenizer.wordChars('_', '_');
  98         tokenizer.wordChars(' ', ' ');
  99 
 100         try {
 101             if (command.startsWith(COMMAND_CREATE_ACTIONS_EXECUTORS)) {
 102                 tokenizer.nextToken();
 103 
 104                 if (tokenizer.nextToken() != StreamTokenizer.TT_NUMBER)
 105                     throw new TestBug("Invalid command format: " + command);
 106 
 107                 int eventsCount = (int) tokenizer.nval;
 108 
 109                 if (tokenizer.nextToken() != StreamTokenizer.TT_WORD)
 110                     throw new TestBug("Invalid command format: " + command);
 111 
 112                 // pass to the createActionsExecutors() string describing types
 113                 // of tested events
 114                 createActionsExecutors(tokenizer.sval, eventsCount);
 115 
 116                 return true;
 117             } else if (command.equals(COMMAND_START_EXECUTION)) {
 118                 startExecution();
 119 
 120                 return true;
 121             } else if (command.equals(COMMAND_WAIT_EXECUTION_COMPLETION)) {
 122                 if (executionControllingThread == null)
 123                     throw new TestBug("executionControllingThread wasn't started");
 124 
 125                 try {
 126                     executionControllingThread.join();
 127                     executionControllingThread = null;
 128                 } catch (InterruptedException e) {
 129                     unexpectedException(e);
 130                 }
 131 
 132                 return true;
 133             } else if (command.equals(COMMAND_STOP_EXECUTION)) {
 134                 if (executionControllingThread == null)
 135                     throw new TestBug("executionControllingThread wasn't started");
 136 
 137                 for (EventActionsThread thread : eventActionsExecutorsPool) {
 138                     thread.stopExecution();
 139                 }
 140 
 141                 return true;
 142             }
 143 
 144         } catch (IOException e) {
 145             throw new TestBug("Invalid command format: " + command);
 146         }
 147 
 148         return false;
 149     }
 150 
 151     // debugee waits completion of test threads in separate thread to free thread listening commands
 152     protected Thread executionControllingThread;
 153 
 154     protected void startExecution() {
 155         if (eventActionsExecutorsPool.size() == 0) {
 156             throw new TestBug("ActionsExecutors were not created");
 157         }
 158 
 159         for (EventActionsThread thread : eventActionsExecutorsPool) {
 160             thread.startExecution();
 161         }
 162 
 163         // debugee waits completion of test threads in separate thread to free thread listening commands
 164         executionControllingThread = new Thread(
 165                 new Runnable() {
 166                     public void run() {
 167                         for (EventActionsThread thread : eventActionsExecutorsPool) {
 168                             try {
 169                                 thread.join();
 170                             } catch (InterruptedException e) {
 171                                 unexpectedException(e);
 172                             }
 173                         }
 174 
 175                         completeExecution();
 176                     }
 177                 });
 178 
 179         executionControllingThread.start();
 180     }
 181 
 182     protected void completeExecution() {
 183         // save information about all generated events in array 'generatedEvents'
 184         List<DebuggeeEventData.DebugEventData> generatedEventsList = new ArrayList<DebuggeeEventData.DebugEventData>();
 185 
 186         for (EventActionsThread thread : eventActionsExecutorsPool)
 187             generatedEventsList.addAll(thread.executor.debugEventDataList);
 188 
 189         generatedEvents = generatedEventsList.toArray(new DebuggeeEventData.DebugEventData[]{});
 190 
 191         // stop at breakpoint when all events was generated
 192         breakpointMethod();
 193 
 194         // clear data about generated events to allow execute command
 195         // several times
 196         clearResults();
 197     }
 198 
 199     // clear data about generated events to allow execute test several times
 200     protected void clearResults() {
 201         for (EventActionsThread thread : eventActionsExecutorsPool)
 202             thread.executor.clearDebugData();
 203 
 204         eventActionsExecutorsPool.clear();
 205 
 206         generatedEvents = new DebuggeeEventData.DebugEventData[0];
 207     }
 208 
 209     // create threads generating events
 210     abstract protected void createActionsExecutors(String description,
 211             int eventsCount);
 212 
 213     /*
 214      * Thread generating events, call in loop
 215      * EventActionsExecutor.doEventAction()
 216      */
 217     static class EventActionsThread extends Thread {
 218         // how many times call executor.doMonitorAction()
 219         private int actionsNumber;
 220 
 221         // object generating events
 222         public EventActionsExecutor executor;
 223 
 224         public EventActionsThread(EventActionsExecutor executor,
 225                 int actionsNumber) {
 226             this.actionsNumber = actionsNumber;
 227             this.executor = executor;
 228         }
 229 
 230         private volatile boolean startExecution;
 231         private volatile boolean stopExecution;
 232 
 233         public void run() {
 234             while (!startExecution)
 235                 yield();
 236 
 237             for (int i = 0; (i < actionsNumber) && !stopExecution; i++)
 238                 executor.doEventAction();
 239         }
 240 
 241         public void startExecution() {
 242             startExecution = true;
 243         }
 244 
 245         public void stopExecution() {
 246             stopExecution = true;
 247         }
 248     }
 249 
 250 }