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 }