Fix SDR device lock-up from unreleased device registry on process crash

Stream threads for sensor, pager, acars, rtlamr, dmr, and dsc modes
never called release_sdr_device() when their SDR process crashed,
leaving devices permanently locked in the registry. Also fixes orphaned
companion processes (rtl_fm, rtl_tcp) not being killed on crash, start
path failures leaking processes, DMR stop handler missing lock, and
listening post/audio websocket pkill nuking all system-wide rtl_fm
processes. Wires up register_process()/unregister_process() so the
atexit/signal cleanup safety net actually works, and adds rtl_tcp,
rtl_power, rtlamr, ffmpeg to the killall endpoint.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Smittix
2026-02-07 15:18:15 +00:00
parent b208576068
commit 60d3cff5e7
9 changed files with 196 additions and 45 deletions

View File

@@ -19,7 +19,7 @@ from utils.validation import (
validate_rtl_tcp_host, validate_rtl_tcp_port
)
from utils.sse import format_sse
from utils.process import safe_terminate, register_process
from utils.process import safe_terminate, register_process, unregister_process
from utils.sdr import SDRFactory, SDRType
sensor_bp = Blueprint('sensor', __name__)
@@ -59,10 +59,24 @@ def stream_sensor_output(process: subprocess.Popen[bytes]) -> None:
except Exception as e:
app_module.sensor_queue.put({'type': 'error', 'text': str(e)})
finally:
process.wait()
global sensor_active_device
# Ensure process is terminated
try:
process.terminate()
process.wait(timeout=2)
except Exception:
try:
process.kill()
except Exception:
pass
unregister_process(process)
app_module.sensor_queue.put({'type': 'status', 'text': 'stopped'})
with app_module.sensor_lock:
app_module.sensor_process = None
# Release SDR device
if sensor_active_device is not None:
app_module.release_sdr_device(sensor_active_device)
sensor_active_device = None
@sensor_bp.route('/start_sensor', methods=['POST'])
@@ -149,6 +163,7 @@ def start_sensor() -> Response:
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
register_process(app_module.sensor_process)
# Start output thread
thread = threading.Thread(target=stream_sensor_output, args=(app_module.sensor_process,))