mirror of
https://github.com/microsoft/debugpy.git
synced 2025-12-23 08:48:12 +00:00
Fix multithreading stepping in 3.12 and later (#1798)
* Fix multithreaded stepping to not have 'return' events when a thread is already suspended * Update after removing blank line * Remove unnecessary change for start method
This commit is contained in:
parent
7597262c80
commit
02723de140
8 changed files with 1962 additions and 1855 deletions
|
|
@ -171,6 +171,10 @@ That will generate a log from the test run.
|
|||
|
||||
Logging the test output can be tricky so here's some information on how to debug the tests.
|
||||
|
||||
#### Running pydevd tests inside of VS code
|
||||
|
||||
You can also run the pydevd tests inside of VS code using the test explorer (and debug the pytest code). To do so, set PYTHONPATH=. and open the `src/debugpy/_vendored/pydevd` folder in VS code. The test explorer should find all of the pydevd tests.
|
||||
|
||||
#### How to add more logging
|
||||
|
||||
The pydevd tests log everything to the console and to a text file during the test. If you scroll up in the console, it should show the log file it read the logs from:
|
||||
|
|
|
|||
7
src/debugpy/.vscode/settings.json
vendored
Normal file
7
src/debugpy/.vscode/settings.json
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"python.testing.pytestArgs": [
|
||||
"."
|
||||
],
|
||||
"python.testing.unittestEnabled": false,
|
||||
"python.testing.pytestEnabled": true
|
||||
}
|
||||
|
|
@ -1085,6 +1085,11 @@ def _return_event(code, instruction, retval):
|
|||
_plugin_stepping(py_db, step_cmd, "return", frame, thread_info)
|
||||
return
|
||||
|
||||
if info.pydev_state == STATE_SUSPEND:
|
||||
# We're already suspended, don't handle any more events on this thread.
|
||||
_do_wait_suspend(py_db, thread_info, frame, "return", None)
|
||||
return
|
||||
|
||||
# Python line stepping
|
||||
stop_frame = info.pydev_step_stop
|
||||
if step_cmd in (CMD_STEP_INTO, CMD_STEP_INTO_MY_CODE, CMD_STEP_INTO_COROUTINE):
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1091,6 +1091,11 @@ cdef _return_event(code, instruction, retval):
|
|||
_plugin_stepping(py_db, step_cmd, "return", frame, thread_info)
|
||||
return
|
||||
|
||||
if info.pydev_state == STATE_SUSPEND:
|
||||
# We're already suspended, don't handle any more events on this thread.
|
||||
_do_wait_suspend(py_db, thread_info, frame, "return", None)
|
||||
return
|
||||
|
||||
# Python line stepping
|
||||
stop_frame = info.pydev_step_stop
|
||||
if step_cmd in (CMD_STEP_INTO, CMD_STEP_INTO_MY_CODE, CMD_STEP_INTO_COROUTINE):
|
||||
|
|
|
|||
|
|
@ -5,12 +5,18 @@ or should keep waiting for the thread 2 to run if only thread 1 is resumed.
|
|||
"""
|
||||
|
||||
import threading
|
||||
import requests
|
||||
import time
|
||||
|
||||
event0 = threading.Event()
|
||||
event1 = threading.Event()
|
||||
event2 = threading.Event()
|
||||
event3 = threading.Event()
|
||||
|
||||
def request_get(url):
|
||||
# return "abc"
|
||||
with requests.get(url) as data:
|
||||
return data.text
|
||||
|
||||
def _thread1():
|
||||
_event1_set = False
|
||||
|
|
@ -19,6 +25,7 @@ def _thread1():
|
|||
while not event0.is_set():
|
||||
event0.wait(timeout=0.001)
|
||||
|
||||
time.sleep(.1)
|
||||
event1.set() # Break thread 1
|
||||
_event1_set = True
|
||||
|
||||
|
|
@ -33,6 +40,9 @@ def _thread2():
|
|||
event0.set()
|
||||
|
||||
while not event1.is_set():
|
||||
# Do something interesting that takes a while. This verifies we
|
||||
# only get stop events for the thread with a breakpoint.
|
||||
print(len(request_get("https://dns.google//")))
|
||||
event1.wait(timeout=0.001)
|
||||
|
||||
event2.set()
|
||||
|
|
|
|||
|
|
@ -3359,6 +3359,9 @@ def test_step_next_step_in_multi_threads(case_setup_dap, stepping_resumes_all_th
|
|||
thread_name_to_id = dict((t["name"], t["id"]) for t in response.body.threads)
|
||||
assert json_hit.thread_id == thread_name_to_id["thread1"]
|
||||
|
||||
stopped_events = json_facade.mark_messages(StoppedEvent)
|
||||
assert len(stopped_events) == 1
|
||||
|
||||
timeout_at = time.time() + 30
|
||||
checks = 0
|
||||
|
||||
|
|
|
|||
|
|
@ -867,6 +867,8 @@ class Session(object):
|
|||
assert len(expected_frames) <= len(frames)
|
||||
assert expected_frames == frames[0 : len(expected_frames)]
|
||||
|
||||
assert len(frames) > 0
|
||||
|
||||
fid = frames[0]("id", int)
|
||||
return StopInfo(stopped, frames, tid, fid)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue