mirror of
https://github.com/python/cpython.git
synced 2026-06-28 20:00:46 +00:00
[3.15] gh-152356: Fix Windows blocking sampling after target process exit (GH-152471) (#152512)
This commit is contained in:
parent
09013312bb
commit
f08fc4ad51
3 changed files with 65 additions and 1 deletions
|
|
@ -1,6 +1,9 @@
|
|||
"""Tests for blocking mode sampling profiler."""
|
||||
|
||||
import io
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import textwrap
|
||||
import unittest
|
||||
from unittest import mock
|
||||
|
|
@ -15,7 +18,11 @@
|
|||
"Test only runs when _remote_debugging is available"
|
||||
)
|
||||
|
||||
from test.support import requires_remote_subprocess_debugging
|
||||
from test.support import (
|
||||
SHORT_TIMEOUT,
|
||||
os_helper,
|
||||
requires_remote_subprocess_debugging,
|
||||
)
|
||||
|
||||
from .helpers import test_subprocess
|
||||
|
||||
|
|
@ -158,3 +165,51 @@ def test_generator_not_under_consumer_arithmetic(self):
|
|||
f"fibonacci_generator appears in the stack when consume_generator "
|
||||
f"is the leaf frame on an arithmetic line. This indicates "
|
||||
f"torn/inconsistent stack traces are being captured.")
|
||||
|
||||
|
||||
@requires_remote_subprocess_debugging()
|
||||
@unittest.skipUnless(sys.platform == "win32", "Windows only")
|
||||
class TestBlockingModeCLI(unittest.TestCase):
|
||||
def test_run_blocking_exits_after_target_process_exits(self):
|
||||
script = 'print("done")\n'
|
||||
|
||||
tmpdir = os.path.abspath(os_helper.TESTFN + "_profiling_blocking")
|
||||
with os_helper.temp_dir(tmpdir) as tmpdir:
|
||||
script_path = os.path.join(tmpdir, "tiny_target.py")
|
||||
profile_path = os.path.join(tmpdir, "blocking.bin")
|
||||
with open(script_path, "w", encoding="utf-8") as file:
|
||||
file.write(script)
|
||||
|
||||
cmd = [
|
||||
sys.executable, "-m", "profiling.sampling", "run",
|
||||
"--binary", "-o", profile_path,
|
||||
"--mode=cpu", "--blocking", "-r", "100",
|
||||
script_path,
|
||||
]
|
||||
result = subprocess.run(
|
||||
cmd,
|
||||
cwd=tmpdir,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
text=True,
|
||||
timeout=SHORT_TIMEOUT,
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
result.returncode, 0,
|
||||
f"stdout:\n{result.stdout}\nstderr:\n{result.stderr}",
|
||||
)
|
||||
self.assertGreater(os.path.getsize(profile_path), 0)
|
||||
|
||||
replay = subprocess.run(
|
||||
[sys.executable, "-m", "profiling.sampling", "replay",
|
||||
profile_path],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
text=True,
|
||||
timeout=SHORT_TIMEOUT,
|
||||
)
|
||||
self.assertEqual(
|
||||
replay.returncode, 0,
|
||||
f"stdout:\n{replay.stdout}\nstderr:\n{replay.stderr}",
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
Fix a hang in ``profiling.sampling run --blocking`` on Windows when the
|
||||
target process exits. The profiler now finalizes binary profiles instead of
|
||||
continuing to sample the exited process.
|
||||
|
|
@ -862,6 +862,12 @@ _Py_RemoteDebug_StopAllThreads(RemoteUnwinderObject *unwinder, _Py_RemoteDebug_T
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (!is_process_alive(unwinder->handle.hProcess)) {
|
||||
PyErr_Format(PyExc_ProcessLookupError,
|
||||
"Process %d has terminated", unwinder->handle.pid);
|
||||
return -1;
|
||||
}
|
||||
|
||||
PyErr_Format(PyExc_RuntimeError, "NtSuspendProcess failed: 0x%lx", status);
|
||||
return -1;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue