[Pydev-cvs] org.python.pydev.debug/src/org/python/pydev/debug/model ThreadListCommand.java,NONE,1.1
Brought to you by:
fabioz
Update of /cvsroot/pydev/org.python.pydev.debug/src/org/python/pydev/debug/model In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv10447/src/org/python/pydev/debug/model Modified Files: PyThread.java VersionCommand.java PyDebugTarget.java RemoteDebugger.java Added Files: ThreadListCommand.java XMLUtils.java StepCommand.java ThreadSuspendCommand.java AbstractDebuggerCommand.java ThreadRunCommand.java PySourceLocator.java ThreadKillCommand.java PyStackFrame.java Removed Files: ModelUtils.java ListThreadsCommand.java RemoteDebuggerCommand.java Log Message: Stepping works. Index: RemoteDebugger.java =================================================================== RCS file: /cvsroot/pydev/org.python.pydev.debug/src/org/python/pydev/debug/model/RemoteDebugger.java,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** RemoteDebugger.java 22 Apr 2004 10:56:18 -0000 1.2 --- RemoteDebugger.java 27 Apr 2004 19:12:59 -0000 1.3 *************** *** 84,88 **** protected class Writer implements Runnable { ArrayList cmdQueue; // a list of RemoteDebuggerCommands ! PrintWriter out; boolean done; --- 84,88 ---- protected class Writer implements Runnable { ArrayList cmdQueue; // a list of RemoteDebuggerCommands ! OutputStreamWriter out; boolean done; *************** *** 92,96 **** OutputStream sout; sout = s.getOutputStream(); ! out = new PrintWriter(new OutputStreamWriter(sout)); } --- 92,96 ---- OutputStream sout; sout = s.getOutputStream(); ! out = new OutputStreamWriter(sout); } *************** *** 98,102 **** * Add command for processing */ ! public void postCommand(RemoteDebuggerCommand cmd) { synchronized(cmdQueue) { cmdQueue.add(cmd); --- 98,102 ---- * Add command for processing */ ! public void postCommand(AbstractDebuggerCommand cmd) { synchronized(cmdQueue) { cmdQueue.add(cmd); *************** *** 113,133 **** public void run() { while (!done) { ! RemoteDebuggerCommand cmd = null; synchronized (cmdQueue) { if (cmdQueue.size() > 0) ! cmd = (RemoteDebuggerCommand) cmdQueue.remove(0); ! } ! if (cmd != null) { ! cmd.aboutToSend(); ! out.write(cmd.getOutgoing()); ! out.write("\n"); ! out.flush(); } try { Thread.sleep(100); } catch (InterruptedException e) { ! // TODO Auto-generated catch block ! e.printStackTrace(); ! } } } --- 113,134 ---- public void run() { while (!done) { ! AbstractDebuggerCommand cmd = null; synchronized (cmdQueue) { if (cmdQueue.size() > 0) ! cmd = (AbstractDebuggerCommand) cmdQueue.remove(0); } try { + if (cmd != null) { + cmd.aboutToSend(); + out.write(cmd.getOutgoing()); + out.write("\n"); + out.flush(); + } Thread.sleep(100); } catch (InterruptedException e) { ! done = true; ! } catch (IOException e1) { ! done = true; ! } } } *************** *** 153,160 **** } ! public void addToResponseQueue(RemoteDebuggerCommand cmd) { responseQueue.put(new Integer(cmd.getSequence()), cmd); Object o = responseQueue.remove(new Integer(cmd.getSequence())); - System.out.println(o.toString()); responseQueue.put(new Integer(cmd.getSequence()), cmd); } --- 154,160 ---- } ! public void addToResponseQueue(AbstractDebuggerCommand cmd) { responseQueue.put(new Integer(cmd.getSequence()), cmd); Object o = responseQueue.remove(new Integer(cmd.getSequence())); responseQueue.put(new Integer(cmd.getSequence()), cmd); } *************** *** 170,179 **** cmdCode = Integer.parseInt(cmdParsed[0]); seqCode = Integer.parseInt(cmdParsed[1]); ! payload = cmdParsed[2]; // is there a response waiting ! RemoteDebuggerCommand cmd = (RemoteDebuggerCommand)responseQueue.remove(new Integer(seqCode)); if (cmd == null) if (target != null) ! target.processCommand(cmdParsed[0], cmdParsed[1], cmdParsed[2]); else PydevDebugPlugin.log(IStatus.ERROR, "internal error, command received no target", null); --- 170,179 ---- cmdCode = Integer.parseInt(cmdParsed[0]); seqCode = Integer.parseInt(cmdParsed[1]); ! payload = URLDecoder.decode(cmdParsed[2]); // is there a response waiting ! AbstractDebuggerCommand cmd = (AbstractDebuggerCommand)responseQueue.remove(new Integer(seqCode)); if (cmd == null) if (target != null) ! target.processCommand(cmdParsed[0], cmdParsed[1], payload); else PydevDebugPlugin.log(IStatus.ERROR, "internal error, command received no target", null); *************** *** 195,204 **** Thread.sleep(100); } catch (IOException e) { ! PydevDebugPlugin.log(IStatus.WARNING, "Unexpected termination of remote dbg input stream", e); } catch (InterruptedException e1) { e1.printStackTrace(); } ! if (socket.isConnected() == false) ! System.err.println("no longer connected"); } } --- 195,208 ---- Thread.sleep(100); } catch (IOException e) { ! done = true; } catch (InterruptedException e1) { e1.printStackTrace(); } ! if ((socket == null) || !socket.isConnected()) { ! if (target != null) { ! target.debuggerDisconnected(); ! } ! done = true; ! } } } *************** *** 212,215 **** --- 216,230 ---- this.target = target; } + + public void startTransmission() throws IOException { + this.reader = new Reader(socket); + this.writer = new Writer(socket); + Thread t = new Thread(reader, "pydevd.reader"); + t.start(); + t = new Thread(writer, "pydevd.writer"); + t.start(); + writer.postCommand(new VersionCommand(this)); + + } /** *************** *** 269,304 **** public void connected(Socket socket) throws IOException { this.socket = socket; - this.reader = new Reader(socket); - this.writer = new Writer(socket); - Thread t = new Thread(reader, "pydevd.reader"); - t.start(); - t = new Thread(writer, "pydevd.writer"); - t.start(); - writer.postCommand(new VersionCommand(this)); } /** * Dispose must be called to clean up. */ public void dispose() { ! if (connector != null) connector.stopListening(); ! if (reader != null) ! reader.done(); ! if (writer != null) writer.done(); ! if (socket != null && socket.isConnected()) ! try { ! socket.close(); ! } catch (IOException e) { ! // other end might have closed first ! } target = null; } ! public void addToResponseQueue(RemoteDebuggerCommand cmd) { reader.addToResponseQueue(cmd); } ! public void postCommand(RemoteDebuggerCommand cmd) { writer.postCommand(cmd); } --- 284,332 ---- public void connected(Socket socket) throws IOException { this.socket = socket; } + + public void disconnect() { + try { + if (socket != null) { + socket.shutdownInput(); // trying to make my pydevd notice that the socket is gone + socket.shutdownOutput(); + socket.close(); + } + } catch (IOException e) { + e.printStackTrace(); + // it is going away + } + socket = null; + if (target != null) + target.debuggerDisconnected(); + } + /** * Dispose must be called to clean up. + * Because we call this from PyDebugTarget.terminate, we can be called multiple times + * But, once dispose() is called, no other calls will be made. */ public void dispose() { ! if (connector != null) { connector.stopListening(); ! connector = null; ! } ! if (writer != null) { writer.done(); ! writer = null; ! } ! if (reader != null) { ! reader.done(); ! reader = null; ! } ! disconnect(); target = null; } ! public void addToResponseQueue(AbstractDebuggerCommand cmd) { reader.addToResponseQueue(cmd); } ! public void postCommand(AbstractDebuggerCommand cmd) { writer.postCommand(cmd); } --- NEW FILE: PyStackFrame.java --- /* * Author: atotic * Created on Apr 22, 2004 * License: Common Public License v1.0 */ package org.python.pydev.debug.model; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.IPath; import org.eclipse.debug.core.DebugException; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.model.IDebugTarget; import org.eclipse.debug.core.model.IRegisterGroup; import org.eclipse.debug.core.model.IStackFrame; import org.eclipse.debug.core.model.IThread; import org.eclipse.debug.core.model.IVariable; import org.eclipse.ui.views.tasklist.ITaskListResourceAdapter; /** * Represents a stack entry. * * Needs to integrate with the source locator */ public class PyStackFrame implements IStackFrame { private String name; private PyThread thread; private String id; private IPath path; private int line; public PyStackFrame(String id, String name, IPath file, int line) { this.id = id; this.name = name; this.path = file; this.line = line; } public IPath getPath() { return path; } public IThread getThread() { return thread; } public void setThread(PyThread thread) { this.thread = thread; } public IVariable[] getVariables() throws DebugException { // TODO Auto-generated method stub return null; } public boolean hasVariables() throws DebugException { // TODO Auto-generated method stub return false; } public int getLineNumber() throws DebugException { return line; } public int getCharStart() throws DebugException { // TODO Auto-generated method stub return 0; } public int getCharEnd() throws DebugException { // TODO Auto-generated method stub return 0; } public String getName() throws DebugException { return name + " [" + path.lastSegment() + ":" + Integer.toString(line) + "]"; } public IRegisterGroup[] getRegisterGroups() throws DebugException { return null; } public boolean hasRegisterGroups() throws DebugException { return false; } public String getModelIdentifier() { return thread.getModelIdentifier(); } public IDebugTarget getDebugTarget() { return thread.getDebugTarget(); } public ILaunch getLaunch() { return thread.getLaunch(); } public boolean canStepInto() { return thread.canStepInto(); } public boolean canStepOver() { return thread.canStepOver(); } public boolean canStepReturn() { return thread.canStepReturn(); } public boolean isStepping() { return thread.isStepping(); } public void stepInto() throws DebugException { thread.stepInto(); } public void stepOver() throws DebugException { thread.stepOver(); } public void stepReturn() throws DebugException { thread.stepReturn(); } public boolean canResume() { return thread.canResume(); } public boolean canSuspend() { return thread.canSuspend(); } public boolean isSuspended() { return thread.isSuspended(); } public void resume() throws DebugException { thread.resume(); } public void suspend() throws DebugException { thread.suspend(); } public boolean canTerminate() { return thread.canTerminate(); } public boolean isTerminated() { return thread.isTerminated(); } public void terminate() throws DebugException { thread.terminate(); } public Object getAdapter(Class adapter) { if (adapter.equals(ILaunch.class) || adapter.equals(IResource.class)) return thread.getAdapter(adapter); else if (adapter.equals(ITaskListResourceAdapter.class)) return null; // ongoing, I do not fully understand all the interfaces they'd like me to support System.err.println("PyStackFrame Need adapter " + adapter.toString()); return null; } } --- ListThreadsCommand.java DELETED --- --- NEW FILE: ThreadRunCommand.java --- /* * Author: atotic * Created on Apr 22, 2004 * License: Common Public License v1.0 */ package org.python.pydev.debug.model; /** * Run thread network command */ public class ThreadRunCommand extends AbstractDebuggerCommand { String thread; public ThreadRunCommand(RemoteDebugger debugger, String thread) { super(debugger); this.thread = thread; } public String getOutgoing() { return makeCommand(Integer.toString(CMD_THREAD_RUN), sequence, thread); } } --- NEW FILE: ThreadListCommand.java --- /* * Author: atotic * Created on Apr 21, 2004 * License: Common Public License v1.0 */ package org.python.pydev.debug.model; import org.eclipse.core.runtime.IStatus; import org.eclipse.debug.core.model.IThread; import org.python.pydev.debug.core.PydevDebugPlugin; /** * ListThreads command. * * See protocol for more info */ public class ThreadListCommand extends AbstractDebuggerCommand { boolean done; PyDebugTarget target; IThread[] threads; public ThreadListCommand(RemoteDebugger debugger, PyDebugTarget target) { super(debugger); this.target = target; done = false; } public void waitUntilDone(int timeout) throws InterruptedException { while (!done && timeout > 0) { timeout -= 100; Thread.sleep(100); } if (timeout < 0) throw new InterruptedException(); } public IThread[] getThreads() { return threads; } public String getOutgoing() { return makeCommand(Integer.toString(CMD_LIST_THREADS), sequence, ""); } public boolean needResponse() { return true; } /** * The response is a list of threads */ public void processResponse(int cmdCode, String payload) { if (cmdCode != 102) { PydevDebugPlugin.log(IStatus.ERROR, "Unexpected response to LIST THREADS" + payload, null); return; } threads = XMLUtils.ThreadsFromXML(target, payload); done = true; } public void processErrorResponse(int cmdCode, String payload) { PydevDebugPlugin.log(IStatus.ERROR, "LIST THREADS got an error " + payload, null); } } --- NEW FILE: ThreadSuspendCommand.java --- /* * Author: atotic * Created on Apr 22, 2004 * License: Common Public License v1.0 */ package org.python.pydev.debug.model; /** * Suspend thread network command. * * See protocol docs for more info. */ public class ThreadSuspendCommand extends AbstractDebuggerCommand { String thread; public ThreadSuspendCommand(RemoteDebugger debugger, String thread) { super(debugger); this.thread = thread; } public String getOutgoing() { return makeCommand(Integer.toString(CMD_THREAD_SUSPEND), sequence, thread); } } --- ModelUtils.java DELETED --- Index: PyThread.java =================================================================== RCS file: /cvsroot/pydev/org.python.pydev.debug/src/org/python/pydev/debug/model/PyThread.java,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** PyThread.java 22 Apr 2004 10:56:17 -0000 1.1 --- PyThread.java 27 Apr 2004 19:12:59 -0000 1.2 *************** *** 24,40 **** private String name; private String id; public PyThread(PyDebugTarget target, String name, String id) { this.target = target; this.name = name; ! this.id = id; } public String getName() throws DebugException { return name; } public int getPriority() throws DebugException { - // TODO maybe daemon status of the threads? return 0; } --- 24,60 ---- private String name; private String id; + boolean isPydevThread; // true if this is a debugger thread, that can't be killed/suspended + + boolean isSuspended = false; + boolean isStepping = false; + IStackFrame[] stack; public PyThread(PyDebugTarget target, String name, String id) { this.target = target; this.name = name; ! this.id = id; ! isPydevThread = id.equals("-1"); // use a special id for pydev threads } + /** + * If a thread is entering a suspended state, pass in the stack + */ + public void setSuspended(boolean state, IStackFrame[] stack) { + isSuspended = state; + this.stack = stack; + if (stack != null) + for (int i=0; i<stack.length; i++) + ((PyStackFrame)stack[i]).setThread(this); + } + public String getName() throws DebugException { return name; } + + public String getId() { + return id; + } public int getPriority() throws DebugException { return 0; } *************** *** 53,57 **** public boolean canTerminate() { ! return true; } --- 73,77 ---- public boolean canTerminate() { ! return !isPydevThread; } *************** *** 61,139 **** public void terminate() throws DebugException { ! System.out.print("Terminating thread"); } public boolean canResume() { ! // TODO Auto-generated method stub ! return false; } public boolean canSuspend() { ! // TODO Auto-generated method stub ! return true; } public boolean isSuspended() { ! // TODO Auto-generated method stub ! return false; } public void resume() throws DebugException { ! // TODO Auto-generated method stub } public void suspend() throws DebugException { ! // TODO Auto-generated method stub ! } public boolean canStepInto() { ! // TODO Auto-generated method stub ! return false; } public boolean canStepOver() { ! // TODO Auto-generated method stub ! return false; } public boolean canStepReturn() { ! // TODO Auto-generated method stub ! return false; } public boolean isStepping() { ! // TODO Auto-generated method stub ! return false; } public void stepInto() throws DebugException { ! // TODO Auto-generated method stub } public void stepOver() throws DebugException { ! // TODO Auto-generated method stub ! } public void stepReturn() throws DebugException { ! // TODO Auto-generated method stub ! } public IStackFrame[] getStackFrames() throws DebugException { ! // TODO Auto-generated method stub ! return null; } public boolean hasStackFrames() throws DebugException { ! // TODO Auto-generated method stub ! return false; } public IStackFrame getTopStackFrame() throws DebugException { ! // TODO Auto-generated method stub ! return null; } public IBreakpoint[] getBreakpoints() { // TODO Auto-generated method stub --- 81,169 ---- public void terminate() throws DebugException { ! if (!isPydevThread) { ! RemoteDebugger d = target.getDebugger(); ! d.postCommand(new ThreadKillCommand(d, id)); ! } } public boolean canResume() { ! return !isPydevThread && isSuspended; } public boolean canSuspend() { ! return !isPydevThread && !isSuspended; } public boolean isSuspended() { ! return isSuspended; } public void resume() throws DebugException { ! if (!isPydevThread) { ! isStepping = false; ! RemoteDebugger d = target.getDebugger(); ! d.postCommand(new ThreadRunCommand(d, id)); ! } } public void suspend() throws DebugException { ! if (!isPydevThread) { ! RemoteDebugger d = target.getDebugger(); ! d.postCommand(new ThreadSuspendCommand(d, id)); ! } } public boolean canStepInto() { ! return !isPydevThread && isSuspended; } public boolean canStepOver() { ! return !isPydevThread && isSuspended; } public boolean canStepReturn() { ! return !isPydevThread && isSuspended; } public boolean isStepping() { ! return isStepping; } public void stepInto() throws DebugException { ! if (!isPydevThread) { ! isStepping = true; ! RemoteDebugger d = target.getDebugger(); ! d.postCommand(new StepCommand(d, AbstractDebuggerCommand.CMD_STEP_INTO, id)); ! } } public void stepOver() throws DebugException { ! if (!isPydevThread) { ! isStepping = true; ! RemoteDebugger d = target.getDebugger(); ! d.postCommand(new StepCommand(d, AbstractDebuggerCommand.CMD_STEP_OVER, id)); ! } } public void stepReturn() throws DebugException { ! if (!isPydevThread) { ! isStepping = true; ! RemoteDebugger d = target.getDebugger(); ! d.postCommand(new StepCommand(d, AbstractDebuggerCommand.CMD_STEP_RETURN, id)); ! } } public IStackFrame[] getStackFrames() throws DebugException { ! return stack; } public boolean hasStackFrames() throws DebugException { ! return (stack != null && stack.length > 0); } public IStackFrame getTopStackFrame() throws DebugException { ! return stack == null ? stack[0] : null; } + public IBreakpoint[] getBreakpoints() { // TODO Auto-generated method stub --- NEW FILE: StepCommand.java --- /* * Author: atotic * Created on Apr 27, 2004 * License: Common Public License v1.0 */ package org.python.pydev.debug.model; /** * Debugger step command. */ public class StepCommand extends AbstractDebuggerCommand { int command_id; String thread_id; /** * * @param command_id CMD_STEP_INTO CMD_STEP_OVER CMD_STEP_RETURN */ public StepCommand(RemoteDebugger debugger, int command_id, String thread_id) { super(debugger); this.command_id = command_id; this.thread_id = thread_id; } public String getOutgoing() { return makeCommand(Integer.toString(command_id), sequence, thread_id); } } Index: PyDebugTarget.java =================================================================== RCS file: /cvsroot/pydev/org.python.pydev.debug/src/org/python/pydev/debug/model/PyDebugTarget.java,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** PyDebugTarget.java 22 Apr 2004 10:56:18 -0000 1.1 --- PyDebugTarget.java 27 Apr 2004 19:12:59 -0000 1.2 *************** *** 6,9 **** --- 6,12 ---- package org.python.pydev.debug.model; + import java.util.regex.Matcher; + import java.util.regex.Pattern; + import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IMarkerDelta; *************** *** 21,24 **** --- 24,28 ---- import org.eclipse.debug.core.model.IMemoryBlock; import org.eclipse.debug.core.model.IProcess; + import org.eclipse.debug.core.model.IStackFrame; import org.eclipse.debug.core.model.IThread; import org.python.pydev.debug.core.PydevDebugPlugin; *************** *** 36,39 **** --- 40,44 ---- IPath file; IThread[] threads; + boolean disconnected = false; public PyDebugTarget(ILaunch launch, *************** *** 51,54 **** --- 56,68 ---- DebugPlugin.getDefault().getLaunchManager().addLaunchListener(this); } + + public RemoteDebugger getDebugger() { + return debugger; + } + + public void debuggerDisconnected() { + disconnected = true; + fireEvent(new DebugEvent(this, DebugEvent.CHANGE)); + } public void launchRemoved(ILaunch launch) { *************** *** 93,97 **** public boolean canTerminate() { ! // We can always terminate, it makes no harm return true; } --- 107,111 ---- public boolean canTerminate() { ! // We can always terminate, it does no harm return true; } *************** *** 102,152 **** public void terminate() throws DebugException { process.terminate(); } public boolean canDisconnect() { ! // TODO NOW Auto-generated method stub ! return true; } public void disconnect() throws DebugException { ! // TODO Auto-generated method stub ! } public boolean isDisconnected() { ! // TODO NOW Auto-generated method stub ! return false; } public boolean canResume() { ! // TODO NOW Auto-generated method stub return false; } public boolean canSuspend() { ! // TODO NOW Auto-generated method stub ! return true; } public boolean isSuspended() { - // TODO Auto-generated method stub return false; } public void resume() throws DebugException { ! // TODO Auto-generated method stub ! } public void suspend() throws DebugException { ! // TODO Auto-generated method stub ! } public IThread[] getThreads() throws DebugException { if (threads == null) { ! ListThreadsCommand cmd = new ListThreadsCommand(debugger, this); debugger.postCommand(cmd); try { --- 116,170 ---- public void terminate() throws DebugException { + if (debugger != null) + debugger.disconnect(); process.terminate(); } public boolean canDisconnect() { ! return !disconnected; } public void disconnect() throws DebugException { ! if (debugger != null) { ! debugger.disconnect(); ! } } public boolean isDisconnected() { ! return disconnected; } public boolean canResume() { ! for (int i=0; i< threads.length; i++) ! if (threads[i].canResume()) ! return true; return false; } public boolean canSuspend() { ! for (int i=0; i< threads.length; i++) ! if (threads[i].canSuspend()) ! return true; ! return false; } public boolean isSuspended() { return false; } public void resume() throws DebugException { ! for (int i=0; i< threads.length; i++) ! threads[i].resume(); } public void suspend() throws DebugException { ! for (int i=0; i< threads.length; i++) ! threads[i].suspend(); } public IThread[] getThreads() throws DebugException { if (threads == null) { ! ThreadListCommand cmd = new ThreadListCommand(debugger, this); debugger.postCommand(cmd); try { *************** *** 184,188 **** public boolean supportsStorageRetrieval() { - // TODO Auto-generated method stub return false; } --- 202,205 ---- *************** *** 190,199 **** public IMemoryBlock getMemoryBlock(long startAddress, long length) throws DebugException { - // TODO Auto-generated method stub return null; } public Object getAdapter(Class adapter) { ! // TODO Auto-generated method stub if (adapter.equals(ILaunch.class)) return launch; --- 207,215 ---- public IMemoryBlock getMemoryBlock(long startAddress, long length) throws DebugException { return null; } public Object getAdapter(Class adapter) { ! // Not really sure what to do here, but I am trying if (adapter.equals(ILaunch.class)) return launch; *************** *** 219,224 **** int cmdCode = Integer.parseInt(sCmdCode); int seqCode = Integer.parseInt(sSeqCode); ! if (cmdCode == RemoteDebuggerCommand.CMD_THREAD_CREATED) processThreadCreated(payload); else PydevDebugPlugin.log(IStatus.WARNING, "Unexpected debugger command" + sCmdCode, null); --- 235,246 ---- int cmdCode = Integer.parseInt(sCmdCode); int seqCode = Integer.parseInt(sSeqCode); ! if (cmdCode == AbstractDebuggerCommand.CMD_THREAD_CREATED) processThreadCreated(payload); + else if (cmdCode == AbstractDebuggerCommand.CMD_THREAD_KILL) + processThreadKilled(payload); + else if (cmdCode == AbstractDebuggerCommand.CMD_THREAD_SUSPEND) + processThreadSuspended(payload); + else if (cmdCode == AbstractDebuggerCommand.CMD_THREAD_RUN) + processThreadRun(payload); else PydevDebugPlugin.log(IStatus.WARNING, "Unexpected debugger command" + sCmdCode, null); *************** *** 232,237 **** } private void processThreadCreated(String payload) { ! IThread[] newThreads = ModelUtils.ThreadsFromXML(this, payload); if (threads == null) threads = newThreads; --- 254,272 ---- } + /** + * @return an existing thread with a given id (null if none) + */ + private IThread findThreadByID(String thread_id) throws DebugException { + for (int i = 0; i < threads.length; i++) + if (thread_id.equals(((PyThread)threads[i]).getId())) + return threads[i]; + return null; + } + + /** + * Add it to the list of threads + */ private void processThreadCreated(String payload) { ! IThread[] newThreads = XMLUtils.ThreadsFromXML(this, payload); if (threads == null) threads = newThreads; *************** *** 249,251 **** --- 284,372 ---- fireEvent(new DebugEvent(newThreads[i], DebugEvent.CREATE)); } + + // Remote this from our thread list + private void processThreadKilled(String thread_id) { + try { + IThread threadToDelete = findThreadByID(thread_id); + if (threadToDelete != null) { + int j = 0; + IThread[] newThreads = new IThread[threads.length - 1]; + for (int i=0; i < threads.length; i++) + if (threads[i] != threadToDelete) + newThreads[j++] = threads[i]; + threads = newThreads; + fireEvent(new DebugEvent(threadToDelete, DebugEvent.TERMINATE)); + } + } catch (DebugException e) { + PydevDebugPlugin.log(IStatus.ERROR, "Unexpected error thread kill", e); + } + } + + private void processThreadSuspended(String payload) { + try { + Object[] threadNstack = XMLUtils.XMLToStack(payload); + PyThread t = (PyThread)findThreadByID((String)threadNstack[0]); + int reason = DebugEvent.UNSPECIFIED; + String stopReason = (String) threadNstack[1]; + if (stopReason != null) { + int stopReason_i = Integer.parseInt(stopReason); + if (stopReason_i == AbstractDebuggerCommand.CMD_STEP_OVER || + stopReason_i == AbstractDebuggerCommand.CMD_STEP_INTO || + stopReason_i == AbstractDebuggerCommand.CMD_STEP_RETURN) + reason = DebugEvent.STEP_END; + else if (stopReason_i == AbstractDebuggerCommand.CMD_THREAD_SUSPEND) + reason = DebugEvent.CLIENT_REQUEST; + else { + PydevDebugPlugin.log(IStatus.ERROR, "Unexpected reason for suspension", null); + reason = DebugEvent.UNSPECIFIED; + } + } + if (t != null) { + t.setSuspended(true, (IStackFrame[])threadNstack[2]); + fireEvent(new DebugEvent(t, DebugEvent.SUSPEND, reason)); + } + } catch (DebugException e) { + PydevDebugPlugin.log(IStatus.ERROR, "Unexpected error thread suspended", e); + } + } + + static Pattern threadRunPattern = Pattern.compile("(\\d+)\\t(\\w*)"); + private void processThreadRun(String payload) { + try { + String threadID = ""; + int resumeReason = DebugEvent.UNSPECIFIED; + Matcher m = threadRunPattern.matcher(payload); + if (m.matches()) { + threadID = m.group(1); + try { + int raw_reason = Integer.parseInt(m.group(2)); + if (raw_reason == AbstractDebuggerCommand.CMD_STEP_OVER) + resumeReason = DebugEvent.STEP_OVER; + else if (raw_reason == AbstractDebuggerCommand.CMD_STEP_RETURN) + resumeReason = DebugEvent.STEP_RETURN; + else if (raw_reason == AbstractDebuggerCommand.CMD_STEP_INTO) + resumeReason = DebugEvent.STEP_INTO; + else if (raw_reason == AbstractDebuggerCommand.CMD_THREAD_RUN) + resumeReason = DebugEvent.CLIENT_REQUEST; + else { + PydevDebugPlugin.log(IStatus.ERROR, "Unexpected resume reason code", null); + resumeReason = DebugEvent.UNSPECIFIED; + } } + catch (NumberFormatException e) { + // expected, when pydevd reports "None" + resumeReason = DebugEvent.UNSPECIFIED; + } + } + else + PydevDebugPlugin.log(IStatus.ERROR, "Unexpected treadRun payload " + payload, null); + + PyThread t = (PyThread)findThreadByID(threadID); + if (t != null) { + t.setSuspended(false, null); + fireEvent(new DebugEvent(t, DebugEvent.RESUME, resumeReason)); + } + } catch (DebugException e) { + PydevDebugPlugin.log(IStatus.ERROR, "Unexpected error thread run", e); + } + } } Index: VersionCommand.java =================================================================== RCS file: /cvsroot/pydev/org.python.pydev.debug/src/org/python/pydev/debug/model/VersionCommand.java,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** VersionCommand.java 22 Apr 2004 10:56:17 -0000 1.1 --- VersionCommand.java 27 Apr 2004 19:12:59 -0000 1.2 *************** *** 9,19 **** * Version debugger command. * ! * See protocol definition for more info */ ! public class VersionCommand extends RemoteDebuggerCommand { static final String VERSION = "1.0"; - int sequence; /** * @param debugger --- 9,18 ---- * Version debugger command. * ! * See protocol definition for more info. Used as */ ! public class VersionCommand extends AbstractDebuggerCommand { static final String VERSION = "1.0"; /** * @param debugger *************** *** 21,25 **** public VersionCommand(RemoteDebugger debugger) { super(debugger); - sequence = debugger.getNextSequence(); } --- 20,23 ---- *************** *** 31,38 **** return true; } - - public int getSequence() { - return sequence; - } public void processResponse(int cmdCode, String payload) { --- 29,32 ---- --- NEW FILE: ThreadKillCommand.java --- /* * Author: atotic * Created on Apr 22, 2004 * License: Common Public License v1.0 */ package org.python.pydev.debug.model; /** * KILL_THREAD debugger command * */ public class ThreadKillCommand extends AbstractDebuggerCommand { String thread_id; public ThreadKillCommand(RemoteDebugger debugger, String thread_id) { super(debugger); this.thread_id = thread_id; } public String getOutgoing() { return makeCommand(Integer.toString(CMD_THREAD_KILL), sequence, thread_id); } } --- NEW FILE: PySourceLocator.java --- /* * Author: atotic * Created on Apr 23, 2004 * License: Common Public License v1.0 */ package org.python.pydev.debug.model; import org.eclipse.core.runtime.IPath; import org.eclipse.debug.core.model.ISourceLocator; import org.eclipse.debug.core.model.IStackFrame; import org.eclipse.debug.ui.ISourcePresentation; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorPart; import org.python.pydev.plugin.PydevPlugin; /** * * TODO Comment this class * * Take a look at IDebugModelPresentation */ public class PySourceLocator implements ISourceLocator, ISourcePresentation { public Object getSourceElement(IStackFrame stackFrame) { return stackFrame; } public IEditorInput getEditorInput(Object element) { if (element instanceof PyStackFrame) { IPath path = ((PyStackFrame)element).getPath(); if (path != null) { IEditorPart part = PydevPlugin.getDefault().doOpenEditor(path, false); if (part != null) return part.getEditorInput(); } } return null; } public String getEditorId(IEditorInput input, Object element) { return "org.python.pydev.editor.PythonEditor"; } } --- NEW FILE: XMLUtils.java --- /* * Author: atotic * Created on Apr 22, 2004 * License: Common Public License v1.0 */ package org.python.pydev.debug.model; import java.io.IOException; import java.io.StringBufferInputStream; import java.net.URLDecoder; import java.util.ArrayList; import java.util.Iterator; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.debug.core.model.IStackFrame; import org.eclipse.debug.core.model.IThread; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; /** * Various utilities */ public class XMLUtils { static SAXParserFactory parserFactory = SAXParserFactory.newInstance(); /** * SAX parser for thread info * <xml><thread name="name" id="id"/><xml> */ static class XMLToThreadInfo extends DefaultHandler { public PyDebugTarget target; public ArrayList threads = new ArrayList(); public XMLToThreadInfo(PyDebugTarget target) { this.target = target; } public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if (qName.equals("thread")) { String name = attributes.getValue("name"); String id = attributes.getValue("id"); if (name != null) name = URLDecoder.decode(name); threads.add(new PyThread(target, name, id)); } } } /** * Creates IThread[] from the XML response */ static public IThread[] ThreadsFromXML(PyDebugTarget target, String payload) { IThread[] threads = null; try { SAXParser parser; synchronized(parserFactory) { parser = parserFactory.newSAXParser(); } XMLToThreadInfo info = new XMLToThreadInfo(target); parser.parse(new StringBufferInputStream(payload), info); threads = new IThread[info.threads.size()]; Iterator it = info.threads.iterator(); int i = 0; while (it.hasNext()) threads[i++] = (IThread)it.next(); } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return threads; } static class XMLToStackInfo extends DefaultHandler { public String thread_id; public String stop_reason; public ArrayList stack = new ArrayList(); /* """ <xml> <thread id="id"/> <frame id="id" name="functionName " file="file" line="line"> */ public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if (qName.equals("thread")) { thread_id = attributes.getValue("id"); stop_reason = attributes.getValue("stop_reason"); } else if (qName.equals("frame")) { String name = attributes.getValue("name"); String id = attributes.getValue("id"); String file = attributes.getValue("file"); String line = attributes.getValue("line"); IPath filePath = new Path(file); stack.add(new PyStackFrame(id, name, filePath, Integer.parseInt(line))); } } } /** * @param payload * @return an array of [thread_id, stop_reason, IStackFrame[]] */ public static Object[] XMLToStack(String payload) { String thread_id; IStackFrame[] stack; Object[] retVal = new Object[3]; try { SAXParser parser; synchronized(parserFactory) { parser = parserFactory.newSAXParser(); } XMLToStackInfo info = new XMLToStackInfo(); parser.parse(new StringBufferInputStream(payload), info); stack = new IStackFrame[info.stack.size()]; Iterator it = info.stack.iterator(); int i = 0; while (it.hasNext()) stack[i++] = (IStackFrame)it.next(); retVal[0] = info.thread_id; retVal[1] = info.stop_reason; retVal[2] = stack; } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return retVal; } } --- NEW FILE: AbstractDebuggerCommand.java --- /* * Author: atotic * Created on Mar 23, 2004 * License: Common Public License v1.0 */ package org.python.pydev.debug.model; import org.eclipse.core.runtime.IStatus; import org.python.pydev.debug.core.PydevDebugPlugin; /** * Superclass of all debugger commands. * * Debugger commands know how to interact with pydevd.py. * See pydevd.py for protocol information. * * Command lifecycle: * cmd = new Command() // creation * cmd.getSequence() // get the sequence number of the command * cmd.getOutgoing() // asks command for outgoing message * cmd.aboutToSend() // called right before we go on wire * // by default, if command needs response * // it gets posted to in the response queue * if (cmd.needsResponse()) * post the command to response queue, otherwise we are done * when response arrives: * if response is an error * cmd.processResponse() * else * cmd.processErrorResponse() * */ public abstract class AbstractDebuggerCommand { static final int CMD_LIST_THREADS = 102; static final int CMD_THREAD_CREATED = 103; static final int CMD_THREAD_KILL = 104; static final int CMD_THREAD_SUSPEND = 105; static final int CMD_THREAD_RUN = 106; static final int CMD_STEP_INTO = 107; static final int CMD_STEP_OVER = 108; static final int CMD_STEP_RETURN = 109; static final int CMD_ERROR = 901; static final int CMD_VERSION = 501; static final int CMD_RETURN = 502; protected RemoteDebugger debugger; int sequence; public AbstractDebuggerCommand(RemoteDebugger debugger) { this.debugger = debugger; sequence = debugger.getNextSequence(); } /** * @return outgoing message */ public abstract String getOutgoing(); /** * Notification right before the command is sent. * If subclassed, call super() */ public void aboutToSend() { // if we need a response, put me on the waiting queue if (needResponse()) debugger.addToResponseQueue(this); } /** * Does this command require a response? */ public boolean needResponse() { return false; } /** * returns Sequence # */ public final int getSequence() { return sequence; } /** * notification of the response to the command. * You'll get either processResponse or processErrorResponse */ public void processResponse(int cmdCode, String payload) { PydevDebugPlugin.log(IStatus.ERROR, "Debugger command ignored response " + getClass().toString() + payload, null); } /** * notification of the response to the command. * You'll get either processResponse or processErrorResponse */ public void processErrorResponse(int cmdCode, String payload) { PydevDebugPlugin.log(IStatus.ERROR, "Debugger command ignored error response " + getClass().toString() + payload, null); } public static String makeCommand(String code, int sequence, String payload) { StringBuffer s = new StringBuffer(); s.append(code); s.append("\t"); s.append(sequence); s.append("\t"); s.append(payload); return s.toString(); } } --- RemoteDebuggerCommand.java DELETED --- |