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