Fixed an issue in the debugger backend related to debugging threads.

Sat, 11 Nov 2017 18:44:04 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Sat, 11 Nov 2017 18:44:04 +0100
changeset 5966
3325ecd87c7c
parent 5965
b8d53f4149c8
child 5967
da72832f7c22

Fixed an issue in the debugger backend related to debugging threads.

APIs/Python3/eric6.api file | annotate | diff | comparison | revisions
DebugClients/Python/AsyncFile.py file | annotate | diff | comparison | revisions
DebugClients/Python/DebugBase.py file | annotate | diff | comparison | revisions
DebugClients/Python/DebugClientBase.py file | annotate | diff | comparison | revisions
Debugger/DebuggerInterfacePython.py file | annotate | diff | comparison | revisions
Documentation/Help/source.qch file | annotate | diff | comparison | revisions
Documentation/Help/source.qhp file | annotate | diff | comparison | revisions
Documentation/Source/eric6.DebugClients.Python.AsyncFile.html file | annotate | diff | comparison | revisions
Documentation/Source/eric6.DebugClients.Python.DebugClientBase.html file | annotate | diff | comparison | revisions
Documentation/Source/eric6.Debugger.DebuggerInterfacePython.html file | annotate | diff | comparison | revisions
--- a/APIs/Python3/eric6.api	Thu Nov 09 18:31:34 2017 +0100
+++ b/APIs/Python3/eric6.api	Sat Nov 11 18:44:04 2017 +0100
@@ -125,6 +125,7 @@
 eric6.DebugClients.Python.AsyncFile.AsyncFile.maxtries?7
 eric6.DebugClients.Python.AsyncFile.AsyncFile.pendingWrite?4()
 eric6.DebugClients.Python.AsyncFile.AsyncFile.read?4(size=-1)
+eric6.DebugClients.Python.AsyncFile.AsyncFile.readCommand?4()
 eric6.DebugClients.Python.AsyncFile.AsyncFile.read_p?4(size=-1)
 eric6.DebugClients.Python.AsyncFile.AsyncFile.readable?4()
 eric6.DebugClients.Python.AsyncFile.AsyncFile.readline?4(sizehint=-1)
@@ -217,7 +218,6 @@
 eric6.DebugClients.Python.DebugClientBase.DebugClientBase.getCoding?4()
 eric6.DebugClients.Python.DebugClientBase.DebugClientBase.getRunning?4()
 eric6.DebugClients.Python.DebugClientBase.DebugClientBase.handleJsonCommand?4(jsonStr)
-eric6.DebugClients.Python.DebugClientBase.DebugClientBase.handleLine?4(line)
 eric6.DebugClients.Python.DebugClientBase.DebugClientBase.input?4(prompt)
 eric6.DebugClients.Python.DebugClientBase.DebugClientBase.main?4()
 eric6.DebugClients.Python.DebugClientBase.DebugClientBase.progTerminated?4(status, message="")
--- a/DebugClients/Python/AsyncFile.py	Thu Nov 09 18:31:34 2017 +0100
+++ b/DebugClients/Python/AsyncFile.py	Sat Nov 11 18:44:04 2017 +0100
@@ -184,7 +184,25 @@
         if size >= 0:
             buf = buf[:size]
         return buf
-
+    
+    def readCommand(self):
+        """
+        Public method to read a length prefixed command string.
+        
+        @return command string
+        @rtype str
+        """
+        # The command string is prefixed by a 9 character long length field.
+        length = self.sock.recv(9)
+        length = int(length)
+        data = b''
+        while len(data) < length:
+            newData = self.sock.recv(length - len(data))
+            data += newData
+        
+        # step 2: convert the data
+        return data.decode('utf8', 'backslashreplace')
+    
     def readline_p(self, size=-1):
         """
         Public method to read a line from this file.
--- a/DebugClients/Python/DebugBase.py	Thu Nov 09 18:31:34 2017 +0100
+++ b/DebugClients/Python/DebugBase.py	Sat Nov 11 18:44:04 2017 +0100
@@ -382,14 +382,14 @@
             frame = sys._getframe().f_back  # Skip set_trace method
         
         if sys.version_info[0] == 2:
-            stopOnHandleLine = self._dbgClient.handleLine.func_code
+            stopOnHandleCommand = self._dbgClient.handleJsonCommand.func_code
         else:
-            stopOnHandleLine = self._dbgClient.handleLine.__code__
+            stopOnHandleCommand = self._dbgClient.handleJsonCommand.__code__
         
         frame.f_trace = self.trace_dispatch
         while frame.f_back is not None:
-            # stop at erics debugger frame or a threading bootstrap
-            if (frame.f_back.f_code == stopOnHandleLine):
+            # stop at eric's debugger frame or a threading bootstrap
+            if (frame.f_back.f_code == stopOnHandleCommand):
                 frame.f_trace = self.trace_dispatch
                 break
             
--- a/DebugClients/Python/DebugClientBase.py	Thu Nov 09 18:31:34 2017 +0100
+++ b/DebugClients/Python/DebugClientBase.py	Sat Nov 11 18:44:04 2017 +0100
@@ -187,7 +187,6 @@
         """
         self.breakpoints = {}
         self.redirect = True
-        self.__receiveBuffer = ""
         
         # special objects representing the main scripts thread and frame
         self.mainThread = self
@@ -355,23 +354,6 @@
         
         return code
     
-    def handleLine(self, line):
-        """
-        Public method to handle the receipt of a complete line.
-
-        It first looks for a valid protocol token at the start of the line.
-        Thereafter it trys to execute the lines accumulated so far.
-        
-        @param line the received line
-        """
-        # Remove any newline.
-        if line[-1] == '\n':
-            line = line[:-1]
-
-##        printerr(line)          ##debug
-        
-        self.handleJsonCommand(line)
-    
     def handleJsonCommand(self, jsonStr):
         """
         Public method to handle a command serialized as a JSON string.
@@ -379,9 +361,12 @@
         @param jsonStr string containing the command received from the IDE
         @type str
         """
+##        printerr(jsonStr)          ##debug
+        
         try:
             commandDict = json.loads(jsonStr.strip())
         except (TypeError, ValueError) as err:
+            printerr("Error handling command: " + jsonStr)
             printerr(str(err))
             return
         
@@ -1031,23 +1016,17 @@
         @param stream file like object that has data to be written
         """
         try:
-            got = stream.readline_p()
+            self.lockClient()
+            command = stream.readCommand()
+            self.unlockClient()
         except Exception:
             return
 
-        if len(got) == 0:
+        if len(command) == 0:
             self.sessionClose()
             return
-
-        self.__receiveBuffer = self.__receiveBuffer + got
-
-        # Call handleLine for the line if it is complete.
-        eol = self.__receiveBuffer.find('\n')
-        while eol >= 0:
-            line = self.__receiveBuffer[:eol + 1]
-            self.__receiveBuffer = self.__receiveBuffer[eol + 1:]
-            self.handleLine(line)
-            eol = self.__receiveBuffer.find('\n')
+        
+        self.handleJsonCommand(command)
 
     def writeReady(self, stream):
         """
@@ -2071,7 +2050,7 @@
                 redirect = True
             elif sys.argv[2] == "False":
                 redirect = False
-            else: 
+            else:
                 try:
                     redirect = int(sys.argv[2])
                 except (ValueError, IndexError):
--- a/Debugger/DebuggerInterfacePython.py	Thu Nov 09 18:31:34 2017 +0100
+++ b/Debugger/DebuggerInterfacePython.py	Sat Nov 11 18:44:04 2017 +0100
@@ -407,7 +407,7 @@
         """
         # Send commands that were waiting for the connection.
         for cmd in self.queue:
-            self.qsock.write(cmd.encode('utf8', 'backslashreplace'))
+            self.__writeJsonCommandToSocket(cmd)
         
         self.queue = []
     
@@ -1105,9 +1105,21 @@
         }
         cmd = json.dumps(commandDict) + '\n'
         if self.qsock is not None:
-            self.qsock.write(cmd.encode('utf8', 'backslashreplace'))
+            self.__writeJsonCommandToSocket(cmd)
         else:
             self.queue.append(cmd)
+    
+    def __writeJsonCommandToSocket(self, cmd):
+        """
+        Private method to write a JSON command to the socket.
+        
+        @param cmd JSON command to be sent
+        @type str
+        """
+        data = cmd.encode('utf8', 'backslashreplace')
+        length = "{0:09d}".format(len(data))
+        self.qsock.write(length.encode() + data)
+        self.qsock.flush()
 
 
 def createDebuggerInterfacePython2(debugServer, passive):
Binary file Documentation/Help/source.qch has changed
--- a/Documentation/Help/source.qhp	Thu Nov 09 18:31:34 2017 +0100
+++ b/Documentation/Help/source.qhp	Sat Nov 11 18:44:04 2017 +0100
@@ -1911,6 +1911,7 @@
       <keyword name="AsyncFile.isatty" id="AsyncFile.isatty" ref="eric6.DebugClients.Python.AsyncFile.html#AsyncFile.isatty" />
       <keyword name="AsyncFile.pendingWrite" id="AsyncFile.pendingWrite" ref="eric6.DebugClients.Python.AsyncFile.html#AsyncFile.pendingWrite" />
       <keyword name="AsyncFile.read" id="AsyncFile.read" ref="eric6.DebugClients.Python.AsyncFile.html#AsyncFile.read" />
+      <keyword name="AsyncFile.readCommand" id="AsyncFile.readCommand" ref="eric6.DebugClients.Python.AsyncFile.html#AsyncFile.readCommand" />
       <keyword name="AsyncFile.read_p" id="AsyncFile.read_p" ref="eric6.DebugClients.Python.AsyncFile.html#AsyncFile.read_p" />
       <keyword name="AsyncFile.readable" id="AsyncFile.readable" ref="eric6.DebugClients.Python.AsyncFile.html#AsyncFile.readable" />
       <keyword name="AsyncFile.readline" id="AsyncFile.readline" ref="eric6.DebugClients.Python.AsyncFile.html#AsyncFile.readline" />
@@ -3429,7 +3430,6 @@
       <keyword name="DebugClientBase.getCoding" id="DebugClientBase.getCoding" ref="eric6.DebugClients.Python.DebugClientBase.html#DebugClientBase.getCoding" />
       <keyword name="DebugClientBase.getRunning" id="DebugClientBase.getRunning" ref="eric6.DebugClients.Python.DebugClientBase.html#DebugClientBase.getRunning" />
       <keyword name="DebugClientBase.handleJsonCommand" id="DebugClientBase.handleJsonCommand" ref="eric6.DebugClients.Python.DebugClientBase.html#DebugClientBase.handleJsonCommand" />
-      <keyword name="DebugClientBase.handleLine" id="DebugClientBase.handleLine" ref="eric6.DebugClients.Python.DebugClientBase.html#DebugClientBase.handleLine" />
       <keyword name="DebugClientBase.input" id="DebugClientBase.input" ref="eric6.DebugClients.Python.DebugClientBase.html#DebugClientBase.input" />
       <keyword name="DebugClientBase.main" id="DebugClientBase.main" ref="eric6.DebugClients.Python.DebugClientBase.html#DebugClientBase.main" />
       <keyword name="DebugClientBase.progTerminated" id="DebugClientBase.progTerminated" ref="eric6.DebugClients.Python.DebugClientBase.html#DebugClientBase.progTerminated" />
@@ -3725,6 +3725,7 @@
       <keyword name="DebuggerInterfacePython.__remoteTranslation" id="DebuggerInterfacePython.__remoteTranslation" ref="eric6.Debugger.DebuggerInterfacePython.html#DebuggerInterfacePython.__remoteTranslation" />
       <keyword name="DebuggerInterfacePython.__sendJsonCommand" id="DebuggerInterfacePython.__sendJsonCommand" ref="eric6.Debugger.DebuggerInterfacePython.html#DebuggerInterfacePython.__sendJsonCommand" />
       <keyword name="DebuggerInterfacePython.__startProcess" id="DebuggerInterfacePython.__startProcess" ref="eric6.Debugger.DebuggerInterfacePython.html#DebuggerInterfacePython.__startProcess" />
+      <keyword name="DebuggerInterfacePython.__writeJsonCommandToSocket" id="DebuggerInterfacePython.__writeJsonCommandToSocket" ref="eric6.Debugger.DebuggerInterfacePython.html#DebuggerInterfacePython.__writeJsonCommandToSocket" />
       <keyword name="DebuggerInterfacePython.flush" id="DebuggerInterfacePython.flush" ref="eric6.Debugger.DebuggerInterfacePython.html#DebuggerInterfacePython.flush" />
       <keyword name="DebuggerInterfacePython.getClientCapabilities" id="DebuggerInterfacePython.getClientCapabilities" ref="eric6.Debugger.DebuggerInterfacePython.html#DebuggerInterfacePython.getClientCapabilities" />
       <keyword name="DebuggerInterfacePython.isConnected" id="DebuggerInterfacePython.isConnected" ref="eric6.Debugger.DebuggerInterfacePython.html#DebuggerInterfacePython.isConnected" />
--- a/Documentation/Source/eric6.DebugClients.Python.AsyncFile.html	Thu Nov 09 18:31:34 2017 +0100
+++ b/Documentation/Source/eric6.DebugClients.Python.AsyncFile.html	Sat Nov 11 18:44:04 2017 +0100
@@ -85,6 +85,9 @@
 <td><a href="#AsyncFile.read">read</a></td>
 <td>Public method to read bytes from this file.</td>
 </tr><tr>
+<td><a href="#AsyncFile.readCommand">readCommand</a></td>
+<td>Public method to read a length prefixed command string.</td>
+</tr><tr>
 <td><a href="#AsyncFile.read_p">read_p</a></td>
 <td>Public method to read bytes from this file.</td>
 </tr><tr>
@@ -243,6 +246,21 @@
 <dd>
 str
 </dd>
+</dl><a NAME="AsyncFile.readCommand" ID="AsyncFile.readCommand"></a>
+<h4>AsyncFile.readCommand</h4>
+<b>readCommand</b>(<i></i>)
+<p>
+        Public method to read a length prefixed command string.
+</p><dl>
+<dt>Returns:</dt>
+<dd>
+command string
+</dd>
+</dl><dl>
+<dt>Return Type:</dt>
+<dd>
+str
+</dd>
 </dl><a NAME="AsyncFile.read_p" ID="AsyncFile.read_p"></a>
 <h4>AsyncFile.read_p</h4>
 <b>read_p</b>(<i>size=-1</i>)
--- a/Documentation/Source/eric6.DebugClients.Python.DebugClientBase.html	Thu Nov 09 18:31:34 2017 +0100
+++ b/Documentation/Source/eric6.DebugClients.Python.DebugClientBase.html	Sat Nov 11 18:44:04 2017 +0100
@@ -167,9 +167,6 @@
 <td><a href="#DebugClientBase.handleJsonCommand">handleJsonCommand</a></td>
 <td>Public method to handle a command serialized as a JSON string.</td>
 </tr><tr>
-<td><a href="#DebugClientBase.handleLine">handleLine</a></td>
-<td>Public method to handle the receipt of a complete line.</td>
-</tr><tr>
 <td><a href="#DebugClientBase.input">input</a></td>
 <td>Public method to implement input() (Python 2) using the event loop.</td>
 </tr><tr>
@@ -630,19 +627,6 @@
 <dd>
 string containing the command received from the IDE
 </dd>
-</dl><a NAME="DebugClientBase.handleLine" ID="DebugClientBase.handleLine"></a>
-<h4>DebugClientBase.handleLine</h4>
-<b>handleLine</b>(<i>line</i>)
-<p>
-        Public method to handle the receipt of a complete line.
-</p><p>
-        It first looks for a valid protocol token at the start of the line.
-        Thereafter it trys to execute the lines accumulated so far.
-</p><dl>
-<dt><i>line</i></dt>
-<dd>
-the received line
-</dd>
 </dl><a NAME="DebugClientBase.input" ID="DebugClientBase.input"></a>
 <h4>DebugClientBase.input</h4>
 <b>input</b>(<i>prompt</i>)
--- a/Documentation/Source/eric6.Debugger.DebuggerInterfacePython.html	Thu Nov 09 18:31:34 2017 +0100
+++ b/Documentation/Source/eric6.Debugger.DebuggerInterfacePython.html	Sat Nov 11 18:44:04 2017 +0100
@@ -91,6 +91,9 @@
 <td><a href="#DebuggerInterfacePython.__startProcess">__startProcess</a></td>
 <td>Private method to start the debugger client process.</td>
 </tr><tr>
+<td><a href="#DebuggerInterfacePython.__writeJsonCommandToSocket">__writeJsonCommandToSocket</a></td>
+<td>Private method to write a JSON command to the socket.</td>
+</tr><tr>
 <td><a href="#DebuggerInterfacePython.flush">flush</a></td>
 <td>Public slot to flush the queue.</td>
 </tr><tr>
@@ -321,6 +324,16 @@
 <dd>
 the process object (QProcess) or None
 </dd>
+</dl><a NAME="DebuggerInterfacePython.__writeJsonCommandToSocket" ID="DebuggerInterfacePython.__writeJsonCommandToSocket"></a>
+<h4>DebuggerInterfacePython.__writeJsonCommandToSocket</h4>
+<b>__writeJsonCommandToSocket</b>(<i>cmd</i>)
+<p>
+        Private method to write a JSON command to the socket.
+</p><dl>
+<dt><i>cmd</i> (str)</dt>
+<dd>
+JSON command to be sent
+</dd>
 </dl><a NAME="DebuggerInterfacePython.flush" ID="DebuggerInterfacePython.flush"></a>
 <h4>DebuggerInterfacePython.flush</h4>
 <b>flush</b>(<i></i>)

eric ide

mercurial