From 4f316cffbca2aaa135adc071a7152475b95cd7c0 Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Tue, 18 Dec 2018 14:35:14 +0100 Subject: [PATCH] init: update state reports on heartbeat responses Init's state reports are updated whenever an interesting part of init's internal state changes (e.g., when sessions are established, or when children are started/removed). However, until now, a change of a skipped heartbeat counter was not taken as trigger for state-report updates. In scenarios where no other intersting event happened, the last reported state did no reflect the current heartbeat state. In particular, when the last report was issued during the construction of a new child just before the child became able to respond to heartbeat requests, the stale report hinted at heartbeat problems that were just an initialization artifact. This problem became visible on some Qemu platform where the child startup takes a long time. The patch tracks the observed skipped-heartbeat counter and triggers a report whenever the counter value changes. Issue #3079 --- repos/os/src/init/child.h | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/repos/os/src/init/child.h b/repos/os/src/init/child.h index e93dcc54a6..cc819a523e 100644 --- a/repos/os/src/init/child.h +++ b/repos/os/src/init/child.h @@ -135,6 +135,21 @@ class Init::Child : Child_policy, Routed_service::Wakeup /* initialized in constructor, updated by 'apply_config' */ bool _heartbeat_enabled; + /* + * Number of skipped heartbeats when last checked + * + * This variable is used for the triggering of state-report updates + * due to heartbeat events. + */ + unsigned _last_skipped_heartbeats = 0; + + /* return true if heartbeat tracking is active */ + bool _heartbeat_expected() const + { + /* don't expect heartbeats from a child that is not yet complete */ + return _heartbeat_enabled && (_state == STATE_ALIVE); + } + /** * Resources assigned to the child */ @@ -532,13 +547,21 @@ class Init::Child : Child_policy, Routed_service::Wakeup void heartbeat() { - if (_heartbeat_enabled) + if (_heartbeat_expected()) _child.heartbeat(); + + unsigned const skipped_heartbeats = _child.skipped_heartbeats(); + + if (_last_skipped_heartbeats != skipped_heartbeats) + _report_update_trigger.trigger_report_update(); + + _last_skipped_heartbeats = skipped_heartbeats; + } unsigned skipped_heartbeats() const { - return _heartbeat_enabled ? _child.skipped_heartbeats() : 0; + return _heartbeat_expected() ? _child.skipped_heartbeats() : 0; } void report_state(Xml_generator &xml, Report_detail const &detail) const;