1 /* 2 * Copyright (c) 1998, 2014, 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 jdk.internal.jshell.jdi; 27 28 import java.util.function.Consumer; 29 import com.sun.jdi.*; 30 import com.sun.jdi.event.*; 31 32 /** 33 * Handler of Java Debug Interface events. 34 * Adapted from jdb EventHandler; Handling of events not used by JShell stubbed out. 35 */ 36 class JDIEventHandler implements Runnable { 37 38 private final Thread thread; 39 private volatile boolean connected = true; 40 private boolean completed = false; 41 private final VirtualMachine vm; 42 private final Consumer<Boolean> reportVMExit; 43 44 JDIEventHandler(VirtualMachine vm, Consumer<Boolean> reportVMExit) { 45 this.vm = vm; 46 this.reportVMExit = reportVMExit; 47 this.thread = new Thread(this, "event-handler"); 48 } 49 50 void start() { 51 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 @Override 63 public void run() { 64 EventQueue queue = vm.eventQueue(); 65 while (connected) { 66 try { 67 EventSet eventSet = queue.remove(); 68 boolean resumeStoppedApp = false; 69 EventIterator it = eventSet.eventIterator(); 70 while (it.hasNext()) { 71 resumeStoppedApp |= handleEvent(it.nextEvent()); 72 } 73 74 if (resumeStoppedApp) { 75 eventSet.resume(); 76 } 77 } catch (InterruptedException exc) { 78 // Do nothing. Any changes will be seen at top of loop. 79 } catch (VMDisconnectedException discExc) { 80 handleDisconnectedException(); 81 break; 82 } 83 } 84 synchronized (this) { 85 completed = true; 86 notifyAll(); 87 } 88 } 89 90 private boolean handleEvent(Event event) { 91 if (event instanceof ExceptionEvent) { 92 exceptionEvent(event); 93 } else if (event instanceof WatchpointEvent) { 94 fieldWatchEvent(event); 95 } else if (event instanceof MethodEntryEvent) { 96 methodEntryEvent(event); 97 } else if (event instanceof MethodExitEvent) { 98 methodExitEvent(event); 99 } else if (event instanceof ClassPrepareEvent) { 100 classPrepareEvent(event); 101 } else if (event instanceof ThreadStartEvent) { 102 threadStartEvent(event); 103 } else if (event instanceof ThreadDeathEvent) { 104 threadDeathEvent(event); 105 } else if (event instanceof VMStartEvent) { 106 vmStartEvent(event); 107 return true; 108 } else { 109 handleExitEvent(event); 110 } 111 return true; 112 } 113 114 private boolean vmDied = false; 115 116 private void handleExitEvent(Event event) { 117 if (event instanceof VMDeathEvent) { 118 vmDied = true; 119 } else if (event instanceof VMDisconnectEvent) { 120 connected = false; 121 } else { 122 throw new InternalError("Unexpected event type: " + 123 event.getClass()); 124 } 125 reportVMExit.accept(vmDied); 126 } 127 128 private synchronized void handleDisconnectedException() { 129 /* 130 * A VMDisconnectedException has happened while dealing with 131 * another event. We need to flush the event queue, dealing only 132 * with exit events (VMDeath, VMDisconnect) so that we terminate 133 * correctly. 134 */ 135 EventQueue queue = vm.eventQueue(); 136 while (connected) { 137 try { 138 EventSet eventSet = queue.remove(); 139 EventIterator iter = eventSet.eventIterator(); 140 while (iter.hasNext()) { 141 handleExitEvent(iter.next()); 142 } 143 } catch (InterruptedException exc) { 144 // ignore 145 } catch (InternalError exc) { 146 // ignore 147 } 148 } 149 } 150 151 private void vmStartEvent(Event event) { 152 VMStartEvent se = (VMStartEvent)event; 153 } 154 155 private void methodEntryEvent(Event event) { 156 MethodEntryEvent me = (MethodEntryEvent)event; 157 } 158 159 private void methodExitEvent(Event event) { 160 MethodExitEvent me = (MethodExitEvent)event; 161 } 162 163 private void fieldWatchEvent(Event event) { 164 WatchpointEvent fwe = (WatchpointEvent)event; 165 } 166 167 private void classPrepareEvent(Event event) { 168 ClassPrepareEvent cle = (ClassPrepareEvent)event; 169 } 170 171 private void exceptionEvent(Event event) { 172 ExceptionEvent ee = (ExceptionEvent)event; 173 } 174 175 private void threadDeathEvent(Event event) { 176 ThreadDeathEvent tee = (ThreadDeathEvent)event; 177 } 178 179 private void threadStartEvent(Event event) { 180 ThreadStartEvent tse = (ThreadStartEvent)event; 181 } 182 }