Repository navigation
fix: close and disconnect zmc's monitors when stopped during startup - #5221
Merged
connortechnology merged 1 commit intoOct 12, 2026
Merged
Conversation
A SIGTERM while zmc is still connecting or priming its monitors broke out of the outer loop at the "if (zm_terminate) break;" after the startup loop, skipping the Close()/disconnect() loop. Monitors that had connected kept their decoder, analysis, poller and ONVIF threads running through dbQueue.stop(), zmDbClose() and logTerm() at the end of main, and were never destroyed: each Zone holds a shared_ptr to its Monitor and only disconnect() clears the zones. Drop that break. With zm_terminate set the capture loop doesn't run, so the Close()/disconnect() loop runs next and the outer loop ends as it does on a normal stop. Close() and disconnect() already run on monitors that never connected or are already disconnected (reconnects do that). fixes ZoneMinder#5220 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
TL;DR
Close()/disconnect()and leaves the monitor threads running past logger and database teardown.if (zm_terminate) break;after the startup loop; withzm_terminateset the capture loop doesn't run, so the existingClose()/disconnect()loop runs and the outer loop ends as on a normal stop; 1 file, +3/-1Close()/disconnect()now also run on monitors that never connected in this pass; both already handle that (reconnects run them on every monitor); stop times unchangedDetails: reproduction, change, checks
Before
Upstream master
c3d2e542b, ThreadSanitizer build, 640x360 cameras;zmc -m 4(ONVIF monitor)started and stopped 0.5-3 s later, 20 times; reports from those processes:
Change
src/zmc.cpp: remove theif (zm_terminate) break;after the startup loop (:328), with acomment saying why. The
breaks inside the startup loop (:276,:312) only leave theforand now reach the
Close()/disconnect()loop too. For a monitor that never got that far,Close()→Pause()finds no decoder, analysis thread, camera or event, anddisconnect()returns early on
mem_ptr == nullptrafter clearing the zones (the same calls a reconnectmakes on every monitor).
zmc'smain(). Covered by the TSan probe above and holodeck'se2e/signals.pystartup-stop scenario.Behaviour changes
~Monitor→Close(), but a larger change touching every Zone user, and the loop is skipped anyway;Close()/disconnect()in a second loop after the outer loop: runs them twice on a normal stop!zm_terminate: a further change for no visible effectSide fixes in this PR: none.
After
Branch
fix/b65-zmc-stop-during-startupat856cb250e(basec3d2e542b), tested in a merge withtwo other fixes from the same lab session (
combo= master + this +fix/b55-usr-level-signal-safe+fix/b77-monitorlink-token-leak; no shared files):check-changed.py: unit-tests, script-tests, smoke, resilience, events, dblog --quick, signals --quick; plain build ofcombo)zmonvif-probe.pldiscovery, known), resilience PASS=5, events PASS=10, dblog --quick PASS=1 XFAIL=2 (known on master, #5197/#5208), signals --quick PASS=4 (hup-default, usr, usr-threads, startup-stop)Not run: the deep set. Backport to release-1.38: same code, the commit cherry-picks cleanly (not built).
Tested as
8cf52ca5c;856cb250eis the same tree withfixes #5220added to the message.fixes #5220
🤖 Generated with Claude Code