Skip to content

Commit 10242ca

Browse files
committed
fix: protect launcher cleanup process from signals
1 parent 3985dbc commit 10242ca

2 files changed

Lines changed: 22 additions & 0 deletions

File tree

lightllm/utils/service_shm_cleanup.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import ctypes
2727
import json
2828
import os
29+
import signal
2930
import subprocess
3031
import sys
3132
import time
@@ -146,6 +147,9 @@ def is_process_active(pid):
146147

147148
def run_launcher_shm_cleanup_process(service_name, parent_pid):
148149
"""每 2 秒检查 launcher,launcher 退出后清理其服务资源。"""
150+
signal.signal(signal.SIGINT, signal.SIG_IGN)
151+
signal.signal(signal.SIGTERM, signal.SIG_IGN)
152+
signal.signal(signal.SIGHUP, signal.SIG_IGN)
149153
while is_process_active(parent_pid):
150154
time.sleep(PARENT_CHECK_INTERVAL)
151155
logger.info(f"Launcher {parent_pid} exited; cleaning service {service_name}")

unit_tests/utils/test_service_shm_cleanup.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,10 @@ def test_cleanup_process_checks_parent_every_two_seconds(monkeypatch):
145145
states = iter([object(), object(), None])
146146
sleeps = []
147147
cleanup_calls = []
148+
signal_calls = []
148149
monkeypatch.setattr(service_shm_cleanup, "is_process_active", lambda pid: next(states))
149150
monkeypatch.setattr(service_shm_cleanup.time, "sleep", sleeps.append)
151+
monkeypatch.setattr(service_shm_cleanup.signal, "signal", lambda sig, handler: signal_calls.append((sig, handler)))
150152
monkeypatch.setattr(
151153
service_shm_cleanup.ServiceShmCleanup,
152154
"cleanup_service_resources",
@@ -157,6 +159,11 @@ def test_cleanup_process_checks_parent_every_two_seconds(monkeypatch):
157159

158160
assert sleeps == [2.0, 2.0]
159161
assert cleanup_calls == ["service_0"]
162+
assert signal_calls == [
163+
(signal.SIGINT, signal.SIG_IGN),
164+
(signal.SIGTERM, signal.SIG_IGN),
165+
(signal.SIGHUP, signal.SIG_IGN),
166+
]
160167

161168

162169
def test_start_cleanup_process_is_independent_session(monkeypatch):
@@ -210,6 +217,12 @@ def _process_stopped(pid):
210217
return True
211218

212219

220+
def _cleanup_signals_are_ignored(pid):
221+
status = Path(f"/proc/{pid}/status").read_text()
222+
ignored = int(next(line.split()[1] for line in status.splitlines() if line.startswith("SigIgn:")), 16)
223+
return all(ignored & (1 << (sig.value - 1)) for sig in [signal.SIGINT, signal.SIGTERM, signal.SIGHUP])
224+
225+
213226
@pytest.mark.parametrize("exit_mode", ["normal", "exception", "os_exit", "SIGKILL", "SIGINT", "SIGTERM", "SIGHUP"])
214227
def test_cleanup_process_after_real_launcher_exit(tmp_path, exit_mode):
215228
service = "cleanup_test_" + uuid.uuid4().hex
@@ -237,8 +250,13 @@ def test_cleanup_process_after_real_launcher_exit(tmp_path, exit_mode):
237250
watcher_pid = json.loads((tmp_path / "launcher.json").read_text())["watcher"]
238251
assert os.getsid(watcher_pid) == watcher_pid
239252
assert os.getsid(watcher_pid) != os.getsid(process.pid)
253+
_wait_until(lambda: _cleanup_signals_are_ignored(watcher_pid))
240254
assert (Path("/dev/shm") / (service + "_req_pool")).exists()
241255
assert libc.shmget(key, 0, 0) == shmid
256+
if exit_mode == "normal":
257+
os.kill(watcher_pid, signal.SIGTERM)
258+
time.sleep(0.1)
259+
assert not _process_stopped(watcher_pid)
242260
if exit_mode.startswith("SIG"):
243261
if exit_mode == "SIGKILL":
244262
process.kill()

0 commit comments

Comments
 (0)