Merge remote-tracking branch 'origin/master' appcode/140.1285 clion/140.1288 idea/140.1295 phpstorm/140.1293 pycharm/140.1286 rubymine/140.1292 webstorm/140.1291 webstorm/140.1296
authorDmitry Trofimov <dmitry.trofimov@jetbrains.com>
Tue, 23 Dec 2014 01:11:10 +0000 (02:11 +0100)
committerDmitry Trofimov <dmitry.trofimov@jetbrains.com>
Tue, 23 Dec 2014 01:11:10 +0000 (02:11 +0100)
python/helpers/pydev/pydevd.py
python/helpers/pydev/pydevd_comm.py
python/helpers/pydev/pydevd_io.py

index 5c0106d4cbd1e2163451dacf68101c346be4e866..17e1751132930c815bbb46c57bf8681c32f422ce 100644 (file)
@@ -244,14 +244,22 @@ def killAllPydevThreads():
 
 
 #=======================================================================================================================
-# PyDBCheckAliveThread
+# CheckOutputThread
+# Non-daemonic thread guaranties that all data is written even if program is finished
 #=======================================================================================================================
-class PyDBCheckAliveThread(PyDBDaemonThread):
+class CheckOutputThread(PyDBDaemonThread):
 
     def __init__(self, pyDb):
         PyDBDaemonThread.__init__(self)
         self.pyDb = pyDb
         self.setName('pydevd.CheckAliveThread')
+        pyDb.output_checker = self
+
+    def start(self):
+        # it should be non daemon
+        thread = threading.Thread(target=self.run)
+        thread.daemon = False
+        thread.start()
 
     def OnRun(self):
             if self.dontTraceMe:
@@ -269,7 +277,8 @@ class PyDBCheckAliveThread(PyDBDaemonThread):
                     pydevd_tracing.SetTrace(None)  # no debugging on this thread
                     
             while not self.killReceived:
-                if not self.pyDb.haveAliveThreads():
+                if not self.pyDb.haveAliveThreads() and self.pyDb.writer.empty() \
+                        and not has_data_to_redirect():
                     try:
                         pydev_log.debug("No alive threads, finishing debug session")
                         self.pyDb.FinishDebuggingSession()
@@ -278,12 +287,13 @@ class PyDBCheckAliveThread(PyDBDaemonThread):
                         traceback.print_exc()
 
                     self.killReceived = True
-                    return
+
+                self.pyDb.checkOutputRedirect()
 
                 time.sleep(0.3)
 
     def doKillPydevThread(self):
-        pass
+        self.killReceived = True
 
 
 
@@ -310,6 +320,7 @@ class PyDB:
         pydevd_tracing.ReplaceSysSetTraceFunc()
         self.reader = None
         self.writer = None
+        self.output_checker = None
         self.quitting = None
         self.cmdFactory = NetCommandFactory()
         self._cmd_queue = {}  # the hash of Queues. Key is thread id, value is thread
@@ -1452,10 +1463,8 @@ class PyDB:
             if self._finishDebuggingSession and not self._terminationEventSent:
                 #that was not working very well because jython gave some socket errors
                 try:
-                    threads = DictKeys(PyDBDaemonThread.created_pydb_daemon_threads)
-                    for t in threads:
-                        if hasattr(t, 'doKillPydevThread'):
-                            t.doKillPydevThread()
+                    if self.output_checker is None:
+                        killAllPydevThreads()
                 except:
                     traceback.print_exc()
                 self._terminationEventSent = True
@@ -1576,7 +1585,9 @@ class PyDB:
 
 
         PyDBCommandThread(self).start()
-        PyDBCheckAliveThread(self).start()
+        if self.signature_factory is not None:
+            # we need all data to be sent to IDE even after program finishes
+            CheckOutputThread(self).start()
 
 
     def patch_threads(self):
@@ -1735,13 +1746,26 @@ def usage(doExit=0):
 def initStdoutRedirect():
     if not getattr(sys, 'stdoutBuf', None):
         sys.stdoutBuf = pydevd_io.IOBuf()
+        sys.stdout_original = sys.stdout
         sys.stdout = pydevd_io.IORedirector(sys.stdout, sys.stdoutBuf) #@UndefinedVariable
 
 def initStderrRedirect():
     if not getattr(sys, 'stderrBuf', None):
         sys.stderrBuf = pydevd_io.IOBuf()
+        sys.stderr_original = sys.stderr
         sys.stderr = pydevd_io.IORedirector(sys.stderr, sys.stderrBuf) #@UndefinedVariable
 
+
+def has_data_to_redirect():
+    if getattr(sys, 'stdoutBuf', None):
+        if not sys.stdoutBuf.empty():
+            return True
+    if getattr(sys, 'stderrBuf', None):
+        if not sys.stderrBuf.empty():
+            return True
+
+    return False
+
 #=======================================================================================================================
 # settrace
 #=======================================================================================================================
@@ -1880,7 +1904,7 @@ def _locked_settrace(
             debugger.setSuspend(t, CMD_THREAD_SUSPEND)
 
         PyDBCommandThread(debugger).start()
-        PyDBCheckAliveThread(debugger).start()
+        CheckOutputThread(debugger).start()
 
     else:
         # ok, we're already in debug mode, with all set, so, let's just set the break
index e00ae732eff3cab366d7967ae334bad868fa5e7a..36bd7c752ac23722144288b2a447afa84820d8ea 100644 (file)
@@ -454,6 +454,8 @@ class WriterThread(PyDBDaemonThread):
             if DebugInfoHolder.DEBUG_TRACE_LEVEL >= 0:
                 traceback.print_exc()
 
+    def empty(self):
+        return self.cmdQueue.empty()
 
 
 
index 2e74154df667f3a8473ea5de9698e85b55c4cfe2..d05eb86eea343a805bc0d5234cb58a668f662d87 100644 (file)
@@ -57,6 +57,8 @@ class IOBuf:
     def flush(self):
         pass
 
+    def empty(self):
+        return len(self.buflist) == 0
 
 class _RedirectionsHolder:
     _stack_stdout = []