From 5603d025be581fbeeee20bcd4bb96ebfea1aad1a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 4 May 2026 13:22:13 +0000 Subject: [PATCH] fix: ensure trigger_state written last in zmTriggerEventOn to fix 1/3 event trigger rate Agent-Logs-Url: https://github.com/ZoneMinder/zoneminder/sessions/68794b2b-7137-4888-b66e-20c629112a57 Co-authored-by: connortechnology <925519+connortechnology@users.noreply.github.com> --- scripts/ZoneMinder/lib/ZoneMinder/Memory.pm.in | 7 +++++-- src/zm_monitor.cpp | 4 +++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Memory.pm.in b/scripts/ZoneMinder/lib/ZoneMinder/Memory.pm.in index 27a084e21..5eb24f389 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Memory.pm.in +++ b/scripts/ZoneMinder/lib/ZoneMinder/Memory.pm.in @@ -605,15 +605,18 @@ sub zmTriggerEventOn { my $text = shift; my $showtext = shift; + # Write score/cause/text before trigger_state so the analysis process always + # reads complete trigger data when it sees TRIGGER_ON. Perl hash iteration + # order is non-deterministic, so trigger_state must be written in a separate + # call that executes after all data fields are already in shared memory. my $values = { 'trigger_data:trigger_score' => $score, 'trigger_data:trigger_cause' => $cause, }; $values->{'trigger_data:trigger_text'} = $text if defined($text); $values->{'trigger_data:trigger_showtext'} = $showtext if defined($showtext); - $values->{'trigger_data:trigger_state'} = TRIGGER_ON; # Write state last so event not read incomplete - zmMemWrite($monitor, $values); + zmMemWrite($monitor, {'trigger_data:trigger_state' => TRIGGER_ON}); # Write state last so event not read incomplete } sub zmTriggerEventOff { diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 27591b0d1..7fe6af380 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1452,10 +1452,12 @@ void Monitor::UpdateAdaptiveSkip() { } void Monitor::ForceAlarmOn( int force_score, const char *force_cause, const char *force_text ) { - trigger_data->trigger_state = TriggerState::TRIGGER_ON; + // Write score/cause/text before trigger_state so the analysis thread always + // reads complete trigger data when it observes TRIGGER_ON. trigger_data->trigger_score = force_score; strncpy(trigger_data->trigger_cause, force_cause, sizeof(trigger_data->trigger_cause)-1); strncpy(trigger_data->trigger_text, force_text, sizeof(trigger_data->trigger_text)-1); + trigger_data->trigger_state = TriggerState::TRIGGER_ON; } void Monitor::ForceAlarmOff() {