Repository: microsoft/ptvsd

Issue:
Suspended event can occur between continue request and response
```
D00005.402: IDE --> {
                "type": "request", 
                "command": "continue", 
                "arguments": {
                    "threadId": 1
                }, 
                "seq": 24
            }

D00005.403: (while handling {u'command': u'continue', u'type': u'request', u'seq': 24})
            PYD <-- {
                "command": "continue", 
                "type": "request", 
                "arguments": {
                    "threadId": "*"
                }, 
                "seq": 1000000024
            }

D00005.428: PYD --> CMD_THREAD_RUN 44
            pid_31048_id_55701680	-1

D00005.429: PYD --> CMD_THREAD_RESUME_SINGLE_NOTIFICATION 46
            {"thread_id": "pid_31048_id_55701680"}

D00005.429: (while handling ('CMD_THREAD_RESUME_SINGLE_NOTIFICATION', 46))
            IDE <-- {
                "body": {
                    "threadId": 1
                }, 
                "type": "event", 
                "event": "continued", 
                "seq": 33
            }

D00005.429: (requested while handling {u'command': u'continue', u'type': u'request', u'seq': 24})
            PYD --> {
                "request_seq": 1000000024, 
                "body": {
                    "allThreadsContinued": true
                }, 
                "pydevd_cmd_id": 502, 
                "success": true, 
                "seq": 48, 
                "command": "continue", 
                "type": "response"
            }

D00005.429: PYD --> {
                "body": {
                    "category": "stdout", 
                    "output": "1", 
                    "source": {}
                }, 
                "type": "event", 
                "pydevd_cmd_id": 116, 
                "event": "output", 
                "seq": 50
            }

D00005.429: (while handling ('CMD_WRITE_TO_CONSOLE', 50))
            IDE <-- {
                "body": {
                    "category": "stdout", 
                    "output": "1", 
                    "source": {}
                }, 
                "type": "event", 
                "event": "output", 
                "seq": 34
            }

D00005.429: PYD --> {
                "body": {
                    "category": "stdout", 
                    "output": "\n", 
                    "source": {}
                }, 
                "type": "event", 
                "pydevd_cmd_id": 116, 
                "event": "output", 
                "seq": 52
            }

D00005.429: (while handling ('CMD_WRITE_TO_CONSOLE', 52))
            IDE <-- {
                "body": {
                    "category": "stdout", 
                    "output": "\n", 
                    "source": {}
                }, 
                "type": "event", 
                "event": "output", 
                "seq": 35
            }

D00005.430: PYD --> CMD_THREAD_SUSPEND 54
            <xml><thread id="pid_31048_id_55701680" stop_reason="111" message="" suspend_type="trace"><frame id="69735136" name="f" file="C%3A%5CUsers%5Chuvalo%5Csource%5Crepos%5CPythonApplication25%5Cmodule1.py" line="3"></frame><frame id="68245184" name="&lt;module&gt;" file="C%3A%5CUsers%5Chuvalo%5Csource%5Crepos%5CPythonApplication25%5Cmodule1.py" line="5"></frame></thread></xml>

D00005.430: PYD --> CMD_THREAD_SUSPEND_SINGLE_NOTIFICATION 56
            {"stop_reason": 111, "thread_id": "pid_31048_id_55701680"}

D00005.431: (while handling ('CMD_THREAD_SUSPEND_SINGLE_NOTIFICATION', 56))
            IDE <-- {
                "body": {
                    "preserveFocusHint": false, 
                    "description": null, 
                    "text": null, 
                    "allThreadsStopped": true, 
                    "reason": "breakpoint", 
                    "threadId": 1
                }, 
                "type": "event", 
                "event": "stopped", 
                "seq": 36
            }

D00005.435: IDE --> {
                "type": "request", 
                "command": "threads", 
                "arguments": {}, 
                "seq": 25
            }

D00005.436: (while handling {u'command': u'threads', u'type': u'request', u'seq': 25})
            PYD <-- CMD_LIST_THREADS 1000000025 

D00005.441: (requested while handling {u'command': u'threads', u'type': u'request', u'seq': 25})
            PYD --> {
                "request_seq": 1000000025, 
                "body": {
                    "threads": [
                        {
                            "id": "pid_31048_id_55701680", 
                            "name": "MainThread"
                        }
                    ]
                }, 
                "pydevd_cmd_id": 502, 
                "success": true, 
                "seq": 58, 
                "command": "threads", 
                "type": "response"
            }

D00005.461: (while handling {u'command': u'continue', u'type': u'request', u'seq': 24})
            IDE <-- {
                "request_seq": 24, 
                "body": {
                    "allThreadsContinued": true
                }, 
                "seq": 37, 
                "success": true, 
                "command": "continue", 
                "message": "", 
                "type": "response"
            }

```


Discussion:

Resolving patch:
diff --git a/src/ptvsd/wrapper.py b/src/ptvsd/wrapper.py
--- a/src/ptvsd/wrapper.py
+++ b/src/ptvsd/wrapper.py
@@ -464,7 +464,12 @@ def pydevd_notify(self, cmd_id, args, is_json=False):
         else:
             seq, s = self.make_packet(cmd_id, args)
         with self.lock:
-            os.write(self.pipe_w, s.encode('utf8'))
+            as_bytes = s
+            if not isinstance(as_bytes, bytes):
+                as_bytes = as_bytes.encode('utf-8')
+            if is_json:
+                os.write(self.pipe_w, ('Content-Length:%s\r\n\r\n' % (len(as_bytes),)).encode('ascii'))
+            os.write(self.pipe_w, as_bytes)
 
     def pydevd_request(self, loop, cmd_id, args, is_json=False):
         '''
@@ -1696,8 +1701,8 @@ def on_pause(self, request, args):
             pydevd_request['arguments'] = {'threadId': '*'}
 
         # Always suspend all threads.
-        yield self.pydevd_request(pydevd_comm.CMD_THREAD_SUSPEND,
-                                  pydevd_request, is_json=True)
+        self.pydevd_request(pydevd_comm.CMD_THREAD_SUSPEND,
+                            pydevd_request, is_json=True)
         self.send_response(request)
 
     @async_handler
@@ -1711,8 +1716,8 @@ def on_continue(self, request, args):
             pydevd_request['arguments'] = {'threadId': '*'}
 
         # Always continue all threads.
-        yield self.pydevd_request(pydevd_comm.CMD_THREAD_RUN,
-                                  pydevd_request, is_json=True)
+        self.pydevd_request(pydevd_comm.CMD_THREAD_RUN,
+                            pydevd_request, is_json=True)
         self.send_response(request, allThreadsContinued=True)
 
     @async_handler
@@ -1725,7 +1730,7 @@ def on_next(self, request, args):
         pydevd_request['arguments']['threadId'] = pyd_tid
         cmd_id = pydevd_comm.CMD_STEP_OVER
 
-        yield self.pydevd_request(cmd_id, pydevd_request, is_json=True)
+        self.pydevd_request(cmd_id, pydevd_request, is_json=True)
         self.send_response(request)
 
     @async_handler
@@ -1738,7 +1743,7 @@ def on_stepIn(self, request, args):
         pydevd_request['arguments']['threadId'] = pyd_tid
         cmd_id = pydevd_comm.CMD_STEP_INTO
 
-        yield self.pydevd_request(cmd_id, pydevd_request, is_json=True)
+        self.pydevd_request(cmd_id, pydevd_request, is_json=True)
         self.send_response(request)
 
     @async_handler
@@ -1751,7 +1756,7 @@ def on_stepOut(self, request, args):
         pydevd_request['arguments']['threadId'] = pyd_tid
         cmd_id = pydevd_comm.CMD_STEP_RETURN
 
-        yield self.pydevd_request(cmd_id, pydevd_request, is_json=True)
+        self.pydevd_request(cmd_id, pydevd_request, is_json=True)
         self.send_response(request)
 
     @async_handler


Test patch: