1 /* 2 * Copyright (c) 1998, 2004, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.tools.example.debug.tty; 27 28 import com.sun.jdi.*; 29 import com.sun.jdi.event.*; 30 import com.sun.jdi.request.EventRequestManager; 31 import com.sun.jdi.request.EventRequest; 32 33 import java.io.PrintStream; 34 import java.util.StringTokenizer; 35 import java.util.Collection; 36 import java.util.Iterator; 37 38 public class EventHandler implements Runnable { 39 40 EventNotifier notifier; 41 Thread thread; 42 volatile boolean connected = true; 43 boolean completed = false; 44 String shutdownMessageKey; 45 boolean stopOnVMStart; 46 47 EventHandler(EventNotifier notifier, boolean stopOnVMStart) { 48 this.notifier = notifier; 49 this.stopOnVMStart = stopOnVMStart; 50 this.thread = new Thread(this, "event-handler"); 51 this.thread.start(); 52 } 53 54 synchronized void shutdown() { 55 connected = false; // force run() loop termination 56 thread.interrupt(); 57 while (!completed) { 58 try {wait();} catch (InterruptedException exc) {} 59 } 60 } 61 62 public void run() { 63 EventQueue queue = Env.vm().eventQueue(); 64 while (connected) { 65 try { 66 EventSet eventSet = queue.remove(); 67 boolean resumeStoppedApp = false; 68 EventIterator it = eventSet.eventIterator(); 69 while (it.hasNext()) { 70 resumeStoppedApp |= !handleEvent(it.nextEvent()); 71 } 72 73 if (resumeStoppedApp) { 74 eventSet.resume(); 75 } else if (eventSet.suspendPolicy() == EventRequest.SUSPEND_ALL) { 76 setCurrentThread(eventSet); 77 notifier.vmInterrupted(); 78 } 79 } catch (InterruptedException exc) { 80 // Do nothing. Any changes will be seen at top of loop. 81 } catch (VMDisconnectedException discExc) { 82 handleDisconnectedException(); 83 break; 84 } 85 } 86 synchronized (this) { 87 completed = true; 88 notifyAll(); 89 } 90 } 91 92 private boolean handleEvent(Event event) { 93 notifier.receivedEvent(event); 94 95 if (event instanceof ExceptionEvent) { 96 return exceptionEvent(event); 97 } else if (event instanceof BreakpointEvent) { 98 return breakpointEvent(event); 99 } else if (event instanceof WatchpointEvent) { 100 return fieldWatchEvent(event); 101 } else if (event instanceof StepEvent) { 102 return stepEvent(event); 103 } else if (event instanceof MethodEntryEvent) { 104 return methodEntryEvent(event); 105 } else if (event instanceof MethodExitEvent) { 106 return methodExitEvent(event); 107 } else if (event instanceof ClassPrepareEvent) { 108 return classPrepareEvent(event); 109 } else if (event instanceof ClassUnloadEvent) { 110 return classUnloadEvent(event); 111 } else if (event instanceof ThreadStartEvent) { 112 return threadStartEvent(event); 113 } else if (event instanceof ThreadDeathEvent) { 114 return threadDeathEvent(event); 115 } else if (event instanceof VMStartEvent) { 116 return vmStartEvent(event); 117 } else { 118 return handleExitEvent(event); 119 } 120 } 121 122 private boolean vmDied = false; 123 private boolean handleExitEvent(Event event) { 124 if (event instanceof VMDeathEvent) { 125 vmDied = true; 126 return vmDeathEvent(event); 127 } else if (event instanceof VMDisconnectEvent) { 128 connected = false; 129 if (!vmDied) { 130 vmDisconnectEvent(event); 131 } 132 Env.shutdown(shutdownMessageKey); 133 return false; 134 } else { 135 throw new InternalError(MessageOutput.format("Unexpected event type", 136 new Object[] {event.getClass()})); 137 } 138 } 139 140 synchronized void handleDisconnectedException() { 141 /* 142 * A VMDisconnectedException has happened while dealing with 143 * another event. We need to flush the event queue, dealing only 144 * with exit events (VMDeath, VMDisconnect) so that we terminate 145 * correctly. 146 */ 147 EventQueue queue = Env.vm().eventQueue(); 148 while (connected) { 149 try { 150 EventSet eventSet = queue.remove(); 151 EventIterator iter = eventSet.eventIterator(); 152 while (iter.hasNext()) { 153 handleExitEvent(iter.next()); 154 } 155 } catch (InterruptedException exc) { 156 // ignore 157 } catch (InternalError exc) { 158 // ignore 159 } 160 } 161 } 162 163 private ThreadReference eventThread(Event event) { 164 if (event instanceof ClassPrepareEvent) { 165 return ((ClassPrepareEvent)event).thread(); 166 } else if (event instanceof LocatableEvent) { 167 return ((LocatableEvent)event).thread(); 168 } else if (event instanceof ThreadStartEvent) { 169 return ((ThreadStartEvent)event).thread(); 170 } else if (event instanceof ThreadDeathEvent) { 171 return ((ThreadDeathEvent)event).thread(); 172 } else if (event instanceof VMStartEvent) { 173 return ((VMStartEvent)event).thread(); 174 } else { 175 return null; 176 } 177 } 178 179 private void setCurrentThread(EventSet set) { 180 ThreadReference thread; 181 if (set.size() > 0) { 182 /* 183 * If any event in the set has a thread associated with it, 184 * they all will, so just grab the first one. 185 */ 186 Event event = set.iterator().next(); // Is there a better way? 187 thread = eventThread(event); 188 } else { 189 thread = null; 190 } 191 setCurrentThread(thread); 192 } 193 194 private void setCurrentThread(ThreadReference thread) { 195 ThreadInfo.invalidateAll(); 196 ThreadInfo.setCurrentThread(thread); 197 } 198 199 private boolean vmStartEvent(Event event) { 200 VMStartEvent se = (VMStartEvent)event; 201 notifier.vmStartEvent(se); 202 return stopOnVMStart; 203 } 204 205 private boolean breakpointEvent(Event event) { 206 BreakpointEvent be = (BreakpointEvent)event; 207 notifier.breakpointEvent(be); 208 return true; 209 } 210 211 private boolean methodEntryEvent(Event event) { 212 MethodEntryEvent me = (MethodEntryEvent)event; 213 notifier.methodEntryEvent(me); 214 return true; 215 } 216 217 private boolean methodExitEvent(Event event) { 218 MethodExitEvent me = (MethodExitEvent)event; 219 return notifier.methodExitEvent(me); 220 } 221 222 private boolean fieldWatchEvent(Event event) { 223 WatchpointEvent fwe = (WatchpointEvent)event; 224 notifier.fieldWatchEvent(fwe); 225 return true; 226 } 227 228 private boolean stepEvent(Event event) { 229 StepEvent se = (StepEvent)event; 230 notifier.stepEvent(se); 231 return true; 232 } 233 234 private boolean classPrepareEvent(Event event) { 235 ClassPrepareEvent cle = (ClassPrepareEvent)event; 236 notifier.classPrepareEvent(cle); 237 238 if (!Env.specList.resolve(cle)) { 239 MessageOutput.lnprint("Stopping due to deferred breakpoint errors."); 240 return true; 241 } else { 242 return false; 243 } 244 } 245 246 private boolean classUnloadEvent(Event event) { 247 ClassUnloadEvent cue = (ClassUnloadEvent)event; 248 notifier.classUnloadEvent(cue); 249 return false; 250 } 251 252 private boolean exceptionEvent(Event event) { 253 ExceptionEvent ee = (ExceptionEvent)event; 254 notifier.exceptionEvent(ee); 255 return true; 256 } 257 258 private boolean threadDeathEvent(Event event) { 259 ThreadDeathEvent tee = (ThreadDeathEvent)event; 260 ThreadInfo.removeThread(tee.thread()); 261 return false; 262 } 263 264 private boolean threadStartEvent(Event event) { 265 ThreadStartEvent tse = (ThreadStartEvent)event; 266 ThreadInfo.addThread(tse.thread()); 267 notifier.threadStartEvent(tse); 268 return false; 269 } 270 271 public boolean vmDeathEvent(Event event) { 272 shutdownMessageKey = "The application exited"; 273 notifier.vmDeathEvent((VMDeathEvent)event); 274 return false; 275 } 276 277 public boolean vmDisconnectEvent(Event event) { 278 shutdownMessageKey = "The application has been disconnected"; 279 notifier.vmDisconnectEvent((VMDisconnectEvent)event); 280 return false; 281 } 282 }