|
29 | 29 | except ImportError:
|
30 | 30 | threading = None
|
31 | 31 |
|
| 32 | +try: |
| 33 | + import _testcapi |
| 34 | +except ImportError: |
| 35 | + _testcapi = None |
| 36 | + |
32 | 37 | if support.PGO:
|
33 | 38 | raise unittest.SkipTest("test is not helpful for PGO")
|
34 | 39 |
|
@@ -2567,42 +2572,24 @@ def test_communicate_BrokenPipeError_stdin_close_with_timeout(self):
|
2567 | 2572 | proc.communicate(timeout=999)
|
2568 | 2573 | mock_proc_stdin.close.assert_called_once_with()
|
2569 | 2574 |
|
2570 |
| - @unittest.skipIf(not ctypes, 'ctypes module required') |
2571 |
| - @unittest.skipIf(not sys.executable, 'Test requires sys.executable') |
2572 |
| - def test_child_terminated_in_stopped_state(self): |
| 2575 | + @unittest.skipUnless(_testcapi is not None |
| 2576 | + and hasattr(_testcapi, 'W_STOPCODE'), |
| 2577 | + 'need _testcapi.W_STOPCODE') |
| 2578 | + def test_stopped(self): |
2573 | 2579 | """Test wait() behavior when waitpid returns WIFSTOPPED; issue29335."""
|
2574 |
| - PTRACE_TRACEME = 0 # From glibc and MacOS (PT_TRACE_ME). |
2575 |
| - libc_name = ctypes.util.find_library('c') |
2576 |
| - libc = ctypes.CDLL(libc_name) |
2577 |
| - if not hasattr(libc, 'ptrace'): |
2578 |
| - raise unittest.SkipTest('ptrace() required') |
2579 |
| - |
2580 |
| - code = textwrap.dedent(f""" |
2581 |
| - import ctypes |
2582 |
| - import faulthandler |
2583 |
| - from test.support import SuppressCrashReport |
2584 |
| -
|
2585 |
| - libc = ctypes.CDLL({libc_name!r}) |
2586 |
| - libc.ptrace({PTRACE_TRACEME}, 0, 0) |
2587 |
| - """) |
2588 |
| - |
2589 |
| - child = subprocess.Popen([sys.executable, '-c', code]) |
2590 |
| - if child.wait() != 0: |
2591 |
| - raise unittest.SkipTest('ptrace() failed - unable to test') |
2592 |
| - |
2593 |
| - code += textwrap.dedent(f""" |
2594 |
| - with SuppressCrashReport(): |
2595 |
| - # Crash the process |
2596 |
| - faulthandler._sigsegv() |
2597 |
| - """) |
2598 |
| - child = subprocess.Popen([sys.executable, '-c', code]) |
2599 |
| - try: |
2600 |
| - returncode = child.wait() |
2601 |
| - except: |
2602 |
| - child.kill() # Clean up the hung stopped process. |
2603 |
| - raise |
2604 |
| - self.assertNotEqual(0, returncode) |
2605 |
| - self.assertLess(returncode, 0) # signal death, likely SIGSEGV. |
| 2580 | + args = [sys.executable, '-c', 'pass'] |
| 2581 | + proc = subprocess.Popen(args) |
| 2582 | + |
| 2583 | + # Wait until the real process completes to avoid zombie process |
| 2584 | + pid = proc.pid |
| 2585 | + pid, status = os.waitpid(pid, 0) |
| 2586 | + self.assertEqual(status, 0) |
| 2587 | + |
| 2588 | + status = _testcapi.W_STOPCODE(3) |
| 2589 | + with mock.patch('subprocess.os.waitpid', return_value=(pid, status)): |
| 2590 | + returncode = proc.wait() |
| 2591 | + |
| 2592 | + self.assertEqual(returncode, -3) |
2606 | 2593 |
|
2607 | 2594 |
|
2608 | 2595 | @unittest.skipUnless(mswindows, "Windows specific tests")
|
|
0 commit comments