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
This commit is contained in:
Norman Feske 2018-12-18 14:35:14 +01:00
parent 68f6b9443e
commit 4f316cffbc
1 changed files with 25 additions and 2 deletions

View File

@ -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;