diff options
Diffstat (limited to 'org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/model/PDAThread.java')
-rw-r--r-- | org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/model/PDAThread.java | 426 |
1 files changed, 426 insertions, 0 deletions
diff --git a/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/model/PDAThread.java b/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/model/PDAThread.java new file mode 100644 index 000000000..6a4102ac3 --- /dev/null +++ b/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/model/PDAThread.java @@ -0,0 +1,426 @@ +/******************************************************************************* + * Copyright (c) 2005, 2007 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Bjorn Freeman-Benson - initial API and implementation + *******************************************************************************/ +package org.eclipse.debug.examples.core.pda.model; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.debug.core.DebugEvent; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.IBreakpoint; +import org.eclipse.debug.core.model.IStackFrame; +import org.eclipse.debug.core.model.IThread; +import org.eclipse.debug.core.model.IVariable; + +/** + * A PDA thread. A PDA VM is single threaded. + */ +public class PDAThread extends PDADebugElement implements IThread, IPDAEventListener { + + /** + * Breakpoint this thread is suspended at or <code>null</code> + * if none. + */ + private IBreakpoint fBreakpoint; + + /** + * Whether this thread is stepping + */ + private boolean fStepping = false; + + /** + * Wether this thread is suspended + */ + private boolean fSuspended = false; + + /** + * Most recent error event or <code>null</code> + */ + private String fErrorEvent; + + /** + * Table mapping stack frames to current variables + */ + private Map fVariables = new HashMap(); + + /** + * Constructs a new thread for the given target + * + * @param target VM + */ + public PDAThread(PDADebugTarget target) { + super(target); + getPDADebugTarget().addEventListener(this); + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IThread#getStackFrames() + */ + public IStackFrame[] getStackFrames() throws DebugException { + if (isSuspended()) { + String framesData = sendRequest("stack"); + if (framesData != null) { + String[] frames = framesData.split("#"); + IStackFrame[] theFrames = new IStackFrame[frames.length]; + for (int i = 0; i < frames.length; i++) { + String data = frames[i]; + theFrames[frames.length - i - 1] = new PDAStackFrame(this, data, i); + } + return theFrames; + } + } + return new IStackFrame[0]; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IThread#hasStackFrames() + */ + public boolean hasStackFrames() throws DebugException { + return isSuspended(); + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IThread#getPriority() + */ + public int getPriority() throws DebugException { + return 0; + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IThread#getTopStackFrame() + */ + public IStackFrame getTopStackFrame() throws DebugException { + IStackFrame[] frames = getStackFrames(); + if (frames.length > 0) { + return frames[0]; + } + return null; + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IThread#getName() + */ + public String getName() { + return "Main thread"; + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IThread#getBreakpoints() + */ + public IBreakpoint[] getBreakpoints() { + if (fBreakpoint == null) { + return new IBreakpoint[0]; + } + return new IBreakpoint[]{fBreakpoint}; + } + + /** + * Notifies this thread it has been suspended by the given breakpoint. + * + * @param breakpoint breakpoint + */ + public void suspendedBy(IBreakpoint breakpoint) { + fBreakpoint = breakpoint; + suspended(DebugEvent.BREAKPOINT); + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.ISuspendResume#canResume() + */ + public boolean canResume() { + return isSuspended(); + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.ISuspendResume#canSuspend() + */ + public boolean canSuspend() { + return !isSuspended(); + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.ISuspendResume#isSuspended() + */ + public boolean isSuspended() { + return fSuspended && !isTerminated(); + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.ISuspendResume#resume() + */ + public void resume() throws DebugException { + //#ifdef ex2 +//# // TODO: Exercise 2 - send resume request to interpreter + //#else + sendRequest("resume"); + //#endif + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.ISuspendResume#suspend() + */ + public void suspend() throws DebugException { + //#ifdef ex2 +//# // TODO: Exercise 2 - send suspend request to interpreter + //#else + sendRequest("suspend"); + //#endif + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IStep#canStepInto() + */ + public boolean canStepInto() { + return false; + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IStep#canStepOver() + */ + public boolean canStepOver() { + return isSuspended(); + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IStep#canStepReturn() + */ + public boolean canStepReturn() { + return false; + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IStep#isStepping() + */ + public boolean isStepping() { + return fStepping; + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IStep#stepInto() + */ + public void stepInto() throws DebugException { + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IStep#stepOver() + */ + public void stepOver() throws DebugException { + sendRequest("step"); + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IStep#stepReturn() + */ + public void stepReturn() throws DebugException { + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.ITerminate#canTerminate() + */ + public boolean canTerminate() { + return !isTerminated(); + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.ITerminate#isTerminated() + */ + public boolean isTerminated() { + return getDebugTarget().isTerminated(); + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.ITerminate#terminate() + */ + public void terminate() throws DebugException { + //#ifdef ex2 +//# // TODO: Exercise 2 - send termination request to interpreter + //#else + sendRequest("exit"); + //#endif + } + + /** + * Sets whether this thread is stepping + * + * @param stepping whether stepping + */ + private void setStepping(boolean stepping) { + fStepping = stepping; + } + + /** + * Sets whether this thread is suspended + * + * @param suspended whether suspended + */ + private void setSuspended(boolean suspended) { + fSuspended = suspended; + } + + /** + * Sets the most recent error event encountered, or <code>null</code> + * to clear the most recent error + * + * @param event one of 'unimpinstr' or 'nosuchlabel' or <code>null</code> + */ + private void setError(String event) { + fErrorEvent = event; + } + + /** + * Returns the most revent error event encountered since the last + * suspend, or <code>null</code> if none. + * + * @return the most revent error event encountered since the last + * suspend, or <code>null</code> if none + */ + public Object getError() { + return fErrorEvent; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.examples.core.pda.model.IPDAEventListener#handleEvent(java.lang.String) + */ + public void handleEvent(String event) { + // clear previous state + fBreakpoint = null; + setStepping(false); + + // handle events + if (event.startsWith("resumed")) { + setSuspended(false); + if (event.endsWith("step")) { + setStepping(true); + resumed(DebugEvent.STEP_OVER); + //#ifdef ex2 +//# } +//# // TODO: Exercise 2 - handle/fire "client" resume event + //#else + } else if (event.endsWith("client")) { + resumed(DebugEvent.CLIENT_REQUEST); + } + //#endif + //#ifdef ex5 +//# // TODO: Exercise 5 - handle start of drop event + //#else + else if (event.endsWith("drop")) { + resumed(DebugEvent.STEP_RETURN); + } + //#endif + } else if (event.startsWith("suspended")) { + setSuspended(true); + //#ifdef ex2 +//# // TODO: Exercise 2 - handle/fire "client" suspend event +//# if (event.endsWith("step")) { +//# suspended(DebugEvent.STEP_END); +//# } else if (event.startsWith("suspended event") && getError() != null) { +//# exceptionHit(); +//# } + //#else + if (event.endsWith("client")) { + suspended(DebugEvent.CLIENT_REQUEST); + } else if (event.endsWith("step")) { + suspended(DebugEvent.STEP_END); + } else if (event.startsWith("suspended event") && getError() != null) { + exceptionHit(); + } + //#endif + //#ifdef ex5 +//# // TODO: Exercise 5 - handle end of drop event + //#else + else if (event.endsWith("drop")) { + suspended(DebugEvent.STEP_END); + } + //#endif + } else if (event.equals("started")) { + fireCreationEvent(); + } else { + setError(event); + } + + } + + /** + * Notification the target has resumed for the given reason. + * Clears any error condition that was last encountered and + * fires a resume event, and clears all cached variables + * for stack frames. + * + * @param detail reason for the resume + */ + private void resumed(int detail) { + setError(null); + synchronized (fVariables) { + fVariables.clear(); + } + fireResumeEvent(detail); + } + + /** + * Notification the target has suspended for the given reason + * + * @param detail reason for the suspend + */ + private void suspended(int detail) { + fireSuspendEvent(detail); + } + + /** + * Notification an error was encountered. Fires a breakpoint + * suspend event. + */ + private void exceptionHit() { + suspended(DebugEvent.BREAKPOINT); + } + + /** + * Sets the current variables for the given stack frame. Called + * by PDA stack frame when it is created. + * + * @param frame + * @param variables + */ + protected void setVariables(IStackFrame frame, IVariable[] variables) { + synchronized (fVariables) { + fVariables.put(frame, variables); + } + } + + /** + * Returns the current variables for the given stack frame, or + * <code>null</code> if none. + * + * @param frame stack frame + * @return variables or <code>null</code> + */ + protected IVariable[] getVariables(IStackFrame frame) { + synchronized (fVariables) { + IVariable[] variables = (IVariable[]) fVariables.get(frame); + if (variables == null) { + return new IVariable[0]; + } + return variables; + } + } + + /** + * Pops the top frame off the callstack. + * + * @throws DebugException + */ + public void pop() throws DebugException { + //#ifdef ex5 +//# // TODO: Exercise 5 - send drop request + //#else + sendRequest("drop"); + //#endif + } + + /** + * Returns whether this thread can pop the top stack frame. + * + * @return whether this thread can pop the top stack frame + */ + public boolean canPop() { + //#ifdef ex5 +//# // TODO: Exercise 5 - allow pop if there is more than 1 frame on the stack + //#else + try { + return getStackFrames().length > 1; + } catch (DebugException e) { + } + //#endif + return false; + } +} |