package bluej.debugger.jdi;
import java.util.LinkedList;
import java.util.Queue;
import threadchecker.OnThread;
import threadchecker.Tag;
import bluej.debugger.DebuggerEvent;
import com.sun.jdi.ReferenceType;
import com.sun.jdi.VMDisconnectedException;
import com.sun.jdi.VirtualMachine;
import com.sun.jdi.event.BreakpointEvent;
import com.sun.jdi.event.ClassPrepareEvent;
import com.sun.jdi.event.Event;
import com.sun.jdi.event.EventIterator;
import com.sun.jdi.event.EventQueue;
import com.sun.jdi.event.EventSet;
import com.sun.jdi.event.ExceptionEvent;
import com.sun.jdi.event.LocatableEvent;
import com.sun.jdi.event.StepEvent;
import com.sun.jdi.event.ThreadDeathEvent;
import com.sun.jdi.event.ThreadStartEvent;
import com.sun.jdi.event.VMDeathEvent;
import com.sun.jdi.event.VMDisconnectEvent;
import com.sun.jdi.event.VMStartEvent;
import com.sun.jdi.request.EventRequest;
import com.sun.jdi.request.StepRequest;
| Event handler class to handle events coming from the remote VM.
|
| @author Michael Kolling
|
@OnThread(Tag.Any)
class VMEventHandler
extends Thread{
final static String DONT_RESUME = "dontResume";
private VMReference vm;
private EventQueue queue;
@OnThread(value = Tag.Any, requireSynchronized = true)
private boolean queueEmpty;
| A class to represent a thread halted/resumed event.
|
@OnThread(Tag.Any)
private class ThreadEvent
{
ThreadEvent(JdiThread thread, boolean state)
{
this.thread = thread;
this.state = state;
}
JdiThread thread;
boolean state;
}
private Queue<ThreadEvent> haltedThreads = new LinkedList<ThreadEvent>();
@OnThread(Tag.Any)
volatile boolean exiting = false;
VMEventHandler(VMReference vm, VirtualMachine vmm)
{
super("vm-event-handler");
this.vm = vm;
queue = vmm.eventQueue();
start();
}
@OnThread(value = Tag.Worker, ignoreParent = true)
public void run()
{
while (!exiting){
try {
EventSet eventSet = queue.remove(1);
if (eventSet == null) {
synchronized (this) {
queueEmpty = true;
notifyAll();
}
handleThreadEvents();
try {
eventSet = queue.remove();
}
catch (InterruptedException ie) {
handleThreadEvents();
continue;
}
synchronized (this) {
isInterrupted();
queueEmpty = false;
}
}
else {
handleThreadEvents();
}
boolean addToSuspendCount = true;
EventIterator it = eventSet.eventIterator();
boolean examineSaidSkipUpdates = false;
boolean gotBPEvent = false;
while (it.hasNext()){
Event ev = it.nextEvent();
examineSaidSkipUpdates |= screenEvent(ev);
if (ev.request() != null) {
if (addToSuspendCount && ev.request().getProperty(DONT_RESUME) != null) {
if (ev instanceof LocatableEvent) {
LocatableEvent le = (LocatableEvent) ev;
le.thread().suspend();
addToSuspendCount = false;
gotBPEvent |= (ev instanceof BreakpointEvent);
}
}
}
}
it = eventSet.eventIterator();
while (it.hasNext()){
Event ev = it.nextEvent();
handleEvent(ev, examineSaidSkipUpdates, gotBPEvent);
}
eventSet.resume();
}
catch (InterruptedException exc) {
}
catch (VMDisconnectedException discExc) { exiting = true;
}
}
}
| Deliver thread halted/resumed events.
|
private synchronized void handleThreadEvents()
{
ThreadEvent halted = haltedThreads.poll();
while (halted != null){
if (halted.state) {
vm.threadHaltedEvent(halted.thread);
}
else {
vm.threadResumedEvent(halted.thread);
}
halted = haltedThreads.poll();
}
}
| Emit a thread halted/resumed event.
|
| @param thr The thread for which the event occurred
| @param halted True if the thread was halted, false if resumed
|
@OnThread(Tag.Any)
public synchronized void emitThreadEvent(JdiThread thr, boolean halted)
{
haltedThreads.add(new ThreadEvent(thr, halted));
if (queueEmpty) {
interrupt();
}
}
| Wait until the event queue is empty (all pending events have been dispatched).
|
@OnThread(Tag.Any)
public void waitQueueEmpty()
{
synchronized (this) {
try {
while (! queueEmpty){
wait();
}
}
catch (InterruptedException ie) {
}
}
}
private static int getStepType(StepEvent ev)
{
EventRequest req = ev.request();
if (req instanceof StepRequest)
{
int stepDepth = ((StepRequest)req).depth();
if (stepDepth == StepRequest.STEP_INTO)
return DebuggerEvent.THREAD_HALT_STEP_INTO;
else if (stepDepth == StepRequest.STEP_OVER)
return DebuggerEvent.THREAD_HALT_STEP_OVER;
}
return DebuggerEvent.THREAD_HALT_UNKNOWN;
}
private boolean screenEvent(Event event)
{
if (event instanceof BreakpointEvent) {
return vm.screenBreakpointEvent((LocatableEvent)event, DebuggerEvent.THREAD_BREAKPOINT);
}
else if (event instanceof StepEvent) {
return vm.screenBreakpointEvent((LocatableEvent)event, getStepType((StepEvent)event));
}
return false;
}
private void handleEvent(Event event, boolean skipUpdate, boolean gotBP)
{
if (event instanceof VMStartEvent) {
vm.vmStartEvent((VMStartEvent) event);
}
else if (event instanceof VMDeathEvent) {
}
else if (event instanceof VMDisconnectEvent) {
vm.vmDisconnectEvent();
}
else if (event instanceof ExceptionEvent) {
vm.exceptionEvent((ExceptionEvent)event);
}
else if (event instanceof BreakpointEvent) {
vm.breakpointEvent((LocatableEvent)event, DebuggerEvent.THREAD_BREAKPOINT, skipUpdate);
}
else if (event instanceof StepEvent) {
if (! gotBP) {
vm.breakpointEvent((LocatableEvent)event, getStepType((StepEvent)event), skipUpdate);
}
}
else if (event instanceof ThreadStartEvent) {
vm.threadStartEvent((ThreadStartEvent)event);
}
else if (event instanceof ThreadDeathEvent) {
vm.threadDeathEvent((ThreadDeathEvent)event);
}
else if (event instanceof ClassPrepareEvent) {
classPrepareEvent(event);
}
else {
}
}
private boolean classPrepareEvent(Event event)
{
ClassPrepareEvent cle = (ClassPrepareEvent)event;
ReferenceType refType = cle.referenceType();
if (refType.name().equals(VMReference.SERVER_CLASSNAME)) {
vm.serverClassPrepared();
}
return true;
}
}
top,
use,
map,
class VMEventHandler
top,
use,
map,
class VMEventHandler . ThreadEvent
. run
. handleThreadEvents
. emitThreadEvent
. waitQueueEmpty
. getStepType
. screenEvent
. handleEvent
. classPrepareEvent
390 neLoCode
+ 8 LoComm