Repository: microsoft/ptvsd

Issue:
Running program to completion in Python 2.7 prints a thread exception in terminal
I believe the problem here is the daemon threads are raising exceptions.
#59 could be related to this, however I'm no longer able to replicate #59 

```
Exception in thread ptvsd.Client (most likely raised during interpreter shutdown):
Exception in thread ptvsd.EventLoop (most likely raised during interpreter shutdown):
```


Discussion:

Resolving patch:
diff --git a/ptvsd/ipcjson.py b/ptvsd/ipcjson.py
--- a/ptvsd/ipcjson.py
+++ b/ptvsd/ipcjson.py
@@ -286,8 +286,12 @@ def process_one_message(self):
             try:
                 self._wait_for_message()
             except OSError as exc:
-                if exc.errno == errno.EBADF:  # socket closed
-                    return self.__exit
+                if exc.errno == errno.EBADF or self.__exit:  # socket closed
+                    return self.__exit                
+                raise
+            except Exception:
+                if self.__exit:
+                    return True
                 raise
             try:
                 msg = self.__message.pop(0)
diff --git a/ptvsd/wrapper.py b/ptvsd/wrapper.py
--- a/ptvsd/wrapper.py
+++ b/ptvsd/wrapper.py
@@ -37,7 +37,7 @@
 #ipcjson._TRACE = ipcjson_trace
 
 ptvsd_sys_exit_code = 0
-
+WAIT_FOR_THREAD_FINISH_TIMEOUT = 1
 
 def unquote(s):
     if s is None:
@@ -393,10 +393,10 @@ def __init__(self, socket, pydevd, logfile=None):
         pydevd._vscprocessor = self
         self._closed = False
 
-        t = threading.Thread(target=self.loop.run_forever,
+        self.event_loop_thread = threading.Thread(target=self.loop.run_forever,
                              name='ptvsd.EventLoop')
-        t.daemon = True
-        t.start()
+        self.event_loop_thread.daemon = True
+        self.event_loop_thread.start()
 
     def close(self):
         """Stop the message processor and release its resources."""
@@ -413,7 +413,9 @@ def close(self):
         self.send_event('exited', exitCode=ptvsd_sys_exit_code)
         self.send_event('terminated')
 
+        self.set_exit()    
         self.loop.stop()
+        self.event_loop_thread.join(WAIT_FOR_THREAD_FINISH_TIMEOUT)
 
         if self.socket:
             self.socket.shutdown(socket.SHUT_RDWR)
@@ -931,6 +933,11 @@ def _start(client, server):
 ########################
 # pydevd hooks
 
+def exit_handler(proc, server_thread):
+    proc.close()
+    if server_thread.is_alive():
+        server_thread.join(WAIT_FOR_THREAD_FINISH_TIMEOUT)
+
 def start_server(port):
     """Return a socket to a (new) local pydevd-handling daemon.
 
@@ -941,8 +948,8 @@ def start_server(port):
     """
     server = _create_server(port)
     client, _ = server.accept()
-    pydevd, proc, _ = _start(client, server)
-    atexit.register(proc.close)
+    pydevd, proc, server_thread = _start(client, server)
+    atexit.register(lambda: exit_handler(proc, server_thread))
     return pydevd
 
 
@@ -956,8 +963,8 @@ def start_client(host, port):
     """
     client = _create_client()
     client.connect((host, port))
-    pydevd, proc, _ = _start(client, None)
-    atexit.register(proc.close)
+    pydevd, proc, server_thread = _start(client, None)
+    atexit.register(lambda: exit_handler(proc, server_thread))
     return pydevd
 
 


Test patch: