Repository: microsoft/ptvsd

Issue:
Debuggee no longer terminates
* Python program
![image](https://user-images.githubusercontent.com/11925432/38463040-5f8fec72-3b23-11e8-90e7-b7137748045f.png)
* Add a break point at line 4
* Debug the above code
* Stop debugging
* You'll notice that the 4th and 5th lines are executed.

Here's the original issue https://github.com/Microsoft/vscode-python/issues/1345

**This used to work in PTVSD**. 
**Here's a commit that it used to work in 608ca082dad71b4394fdb2e5d0615a78970c0f0f**

Note:
* The above commit in PTVSD works with VSC. I.e. its a PTVSD bug. 
* Seems like we're continuing the code



Debuggee no longer terminates
* Python program
![image](https://user-images.githubusercontent.com/11925432/38463040-5f8fec72-3b23-11e8-90e7-b7137748045f.png)
* Add a break point at line 4
* Debug the above code
* Stop debugging
* You'll notice that the 4th and 5th lines are executed.

Here's the original issue https://github.com/Microsoft/vscode-python/issues/1345

**This used to work in PTVSD**. 
**Here's a commit that it used to work in 608ca082dad71b4394fdb2e5d0615a78970c0f0f**

Note:
* The above commit in PTVSD works with VSC. I.e. its a PTVSD bug. 
* Seems like we're continuing the code





Discussion:
Is this for launch, or for attach?
Launch
@DonJayamanne looks like the request does not contain `terminateDebuggee=true`. So this is the right behavior? Interestingly the request contains `restart`, could not find that in the DAP. https://github.com/Microsoft/ptvsd/blob/master/debugger_protocol/schema/debugProtocol.json#L782
```
{"command":"disconnect","arguments":{"restart":false},"type":"request","seq":13}
```
VSCode doesn't send that (`terminateDebuggee=true`).
As per the protocol, the debugger can [do what ever it wants](https://github.com/Microsoft/ptvsd/blob/master/debugger_protocol/schema/debugProtocol.json#L784), on this case it should terminate. 
I think vs may be sending that. Also our (python) extension doesn't indicate the fact that it supports this terminate debugee feature (see [supportTerminateDebuggee](https://github.com/Microsoft/ptvsd/blob/master/debugger_protocol/schema/debugProtocol.json#L2253), this is not initialized in the [vs code extension](https://github.com/Microsoft/vscode-python/blob/master/src/client/debugger/mainV2.ts#L62)).
Please remember, this used to work. It's broken now.
@int19h  - ping since it is P0
Is this for launch, or for attach?
Launch
@DonJayamanne looks like the request does not contain `terminateDebuggee=true`. So this is the right behavior? Interestingly the request contains `restart`, could not find that in the DAP. https://github.com/Microsoft/ptvsd/blob/master/debugger_protocol/schema/debugProtocol.json#L782
```
{"command":"disconnect","arguments":{"restart":false},"type":"request","seq":13}
```
VSCode doesn't send that (`terminateDebuggee=true`).
As per the protocol, the debugger can [do what ever it wants](https://github.com/Microsoft/ptvsd/blob/master/debugger_protocol/schema/debugProtocol.json#L784), on this case it should terminate. 
I think vs may be sending that. Also our (python) extension doesn't indicate the fact that it supports this terminate debugee feature (see [supportTerminateDebuggee](https://github.com/Microsoft/ptvsd/blob/master/debugger_protocol/schema/debugProtocol.json#L2253), this is not initialized in the [vs code extension](https://github.com/Microsoft/vscode-python/blob/master/src/client/debugger/mainV2.ts#L62)).
Please remember, this used to work. It's broken now.
@int19h  - ping since it is P0

Resolving patch:
diff --git a/ptvsd/_vendored/__init__.py b/ptvsd/_vendored/__init__.py
--- a/ptvsd/_vendored/__init__.py
+++ b/ptvsd/_vendored/__init__.py
@@ -113,7 +113,6 @@ def vendored(project, root=None):
     try:
         yield root
     finally:
-        #del sys.path[0]
         sys.path.remove(root)
 
 
diff --git a/ptvsd/_vendored/force_pydevd.py b/ptvsd/_vendored/force_pydevd.py
--- a/ptvsd/_vendored/force_pydevd.py
+++ b/ptvsd/_vendored/force_pydevd.py
@@ -1,6 +1,7 @@
+from importlib import import_module
 import warnings
 
-from . import check_modules, prefix_matcher, preimport
+from . import check_modules, prefix_matcher, preimport, vendored
 
 
 # Ensure that pydevd is our vendored copy.
@@ -13,6 +14,16 @@
     warnings.warn(msg + ':\n {}'.format('\n  '.join(_unvendored)))
 
 
+# Constants must be set before importing any other pydevd module
+# # due to heavy use of "from" in them.
+with vendored('pydevd'):
+    pydevd_constants = import_module('_pydevd_bundle.pydevd_constants')
+# Disable this, since we aren't packaging the Cython modules at the moment.
+pydevd_constants.CYTHON_SUPPORTED = False
+# We limit representation size in our representation provider when needed.
+pydevd_constants.MAXIMUM_VARIABLE_REPRESENTATION_SIZE = 2**32
+
+
 # Now make sure all the top-level modules and packages in pydevd are
 # loaded.  Any pydevd modules that aren't loaded at this point, will
 # be loaded using their parent package's __path__ (i.e. one of the
diff --git a/ptvsd/wrapper.py b/ptvsd/wrapper.py
--- a/ptvsd/wrapper.py
+++ b/ptvsd/wrapper.py
@@ -27,12 +27,6 @@
 import warnings
 from xml.sax import SAXParseException
 
-import _pydevd_bundle.pydevd_constants as pydevd_constants
-# Disable this, since we aren't packaging the Cython modules at the moment.
-pydevd_constants.CYTHON_SUPPORTED = False
-# We limit representation size in our representation provider when needed.
-pydevd_constants.MAXIMUM_VARIABLE_REPRESENTATION_SIZE = 2**32
-
 import _pydevd_bundle.pydevd_comm as pydevd_comm  # noqa
 import _pydevd_bundle.pydevd_extension_api as pydevd_extapi  # noqa
 import _pydevd_bundle.pydevd_extension_utils as pydevd_extutil  # noqa
@@ -67,6 +61,7 @@
     supportsSetExpression=True,
     supportsModulesRequest=True,
     supportsLogPoints=True,
+    supportTerminateDebuggee=True,
     exceptionBreakpointFilters=[
         {
             'filter': 'raised',
@@ -853,7 +848,9 @@ def _handle_disconnect(self, request):
         self.disconnect_request_event.set()
         self._notify_disconnecting(not self._closed)
         if not self._closed:
-            self.close()
+            # Closing the socket causes pydevd to resume all threads,
+            # so just terminate the process altogether.
+            sys.exit(0)
 
     def _wait_for_server_thread(self):
         if self.server_thread is None:


Test patch: