Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commita81661f

Browse files
committed
fix: ignore zombie processes when terminating the browser
1 parentd3160cf commita81661f

File tree

2 files changed

+47
-16
lines changed

2 files changed

+47
-16
lines changed

‎src/ffpuppet/process_tree.py‎

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,14 @@
1919
exceptImportError:
2020
COVERAGE_SIGNAL=None
2121

22-
frompsutilimportAccessDenied,NoSuchProcess,Process,TimeoutExpired,wait_procs
22+
frompsutilimport (
23+
STATUS_ZOMBIE,
24+
AccessDenied,
25+
NoSuchProcess,
26+
Process,
27+
TimeoutExpired,
28+
wait_procs,
29+
)
2330

2431
from .exceptionsimportTerminateError
2532

@@ -30,6 +37,23 @@
3037
LOG=getLogger(__name__)
3138

3239

40+
def_filter_zombies(procs:Iterable[Process])->Generator[Process]:
41+
"""Filter out zombie processes from a collection of processes.
42+
43+
Args:
44+
procs: Processes to check.
45+
46+
Yields:
47+
Processes that are not zombies.
48+
"""
49+
forprocinprocs:
50+
withsuppress(AccessDenied,NoSuchProcess):
51+
ifproc.status()==STATUS_ZOMBIE:
52+
LOG.debug("filtering zombie: %d - %s",proc.pid,proc.name())
53+
continue
54+
yieldproc
55+
56+
3357
def_last_modified(scan_dir:Path)->float|None:
3458
"""Scan directory recursively and find the latest modified date of all .gcda files.
3559
@@ -88,11 +112,11 @@ def _safe_wait_procs(
88112
return (gone,alive)
89113

90114

91-
def_writing_coverage(procs:list[Process])->bool:
115+
def_writing_coverage(procs:Iterable[Process])->bool:
92116
"""Check if any processes have open .gcda files.
93117
94118
Args:
95-
procs:List of processes to check.
119+
procs:Processes to check.
96120
97121
Returns:
98122
True if processes with open .gcda files are found.
@@ -278,7 +302,7 @@ def processes(self, recursive: bool = False) -> list[Process]:
278302
"""Processes in the process tree.
279303
280304
Args:
281-
recursive:if False only the parent and child processes are returned.
305+
recursive:If False only the parent and child processes are returned.
282306
283307
Returns:
284308
Processes in the process tree.
@@ -312,7 +336,7 @@ def terminate(self) -> None:
312336
LOG.debug("attempting to terminate parent (%d)",self.parent.pid)
313337
self.parent.terminate()
314338
self.parent.wait(timeout=10)
315-
procs=_safe_wait_procs(procs,timeout=0)[1]
339+
procs=list(_filter_zombies(_safe_wait_procs(procs,timeout=0)[1]))
316340

317341
use_kill=False
318342
whileprocs:
@@ -329,7 +353,7 @@ def terminate(self) -> None:
329353
else:
330354
proc.terminate()
331355
# wait for processes to terminate
332-
procs=_safe_wait_procs(procs,timeout=30)[1]
356+
procs=list(_filter_zombies(_safe_wait_procs(procs,timeout=30)[1]))
333357
ifuse_kill:
334358
break
335359
use_kill=True
@@ -350,12 +374,9 @@ def wait(self, timeout: int = 300) -> int:
350374
Returns:
351375
Process exit code.
352376
"""
353-
try:
354-
exit_code=self.parent.wait(timeout=timeout)or0
355-
except (AccessDenied,NoSuchProcess):# pragma: no cover
356-
# this is triggered sometimes when the process goes away
357-
exit_code=0
358-
returnexit_code
377+
withsuppress(AccessDenied,NoSuchProcess):
378+
returnself.parent.wait(timeout=timeout)or0
379+
return0# pragma: no cover
359380

360381
defwait_procs(self,timeout:float|None=0)->int:
361382
"""Wait for process tree to exit.

‎src/ffpuppet/test_process_tree.py‎

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,13 @@
1010
fromtimeimportsleep
1111
fromunittestimportmock
1212

13-
frompsutilimportAccessDenied,NoSuchProcess,Process,TimeoutExpired
13+
frompsutilimportSTATUS_ZOMBIE,AccessDenied,NoSuchProcess,Process,TimeoutExpired
1414
frompytestimportmark,raises
1515

1616
from .exceptionsimportTerminateError
1717
from .process_treeimport (
1818
ProcessTree,
19+
_filter_zombies,
1920
_last_modified,
2021
_safe_wait_procs,
2122
_writing_coverage,
@@ -219,7 +220,7 @@ def processes(self, recursive=False):
219220

220221

221222
deftest_last_modified_01(tmp_path):
222-
"""testProcessTree._last_modified()"""
223+
"""test _last_modified()"""
223224
# scan missing path
224225
assert_last_modified(tmp_path/"missing")isNone
225226
# scan empty path
@@ -234,7 +235,7 @@ def test_last_modified_01(tmp_path):
234235

235236

236237
deftest_writing_coverage_01(mocker):
237-
"""testProcessTree._writing_coverage()"""
238+
"""test _writing_coverage()"""
238239
openfile=namedtuple("openfile", ["path","fd"])
239240
# empty list
240241
assertnot_writing_coverage([])
@@ -302,11 +303,20 @@ def test_writing_coverage_01(mocker):
302303
],
303304
)
304305
deftest_safe_wait_procs_01(mocker,wait_side_effect,procs,alive_count,gone_count):
305-
"""testProcessTree._safe_wait_procs()"""
306+
"""test _safe_wait_procs()"""
306307
mocker.patch("ffpuppet.process_tree.perf_counter",side_effect=count(step=0.25))
307308
mocker.patch("ffpuppet.process_tree.sleep",autospec=True)
308309
mocker.patch("ffpuppet.process_tree.wait_procs",side_effect=wait_side_effect)
309310

310311
result=_safe_wait_procs(procs,timeout=1)
311312
assertlen(result[0])==gone_count
312313
assertlen(result[1])==alive_count
314+
315+
316+
deftest_filter_zombies_01(mocker):
317+
"""test _filter_zombies()"""
318+
zombie=mocker.Mock(spec_set=Process,pid=123)
319+
zombie.status.return_value=STATUS_ZOMBIE
320+
procs=tuple(_filter_zombies([zombie,mocker.Mock(spec_set=Process)]))
321+
assertlen(procs)==1
322+
assertnotany(xforxinprocsifx.status()==STATUS_ZOMBIE)

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp