From 19d7a488def074757275ceca6e5391e44d564ac2 Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Wed, 14 Nov 2018 16:19:30 +0100 Subject: [PATCH] init: health monitoring of child components Fixes #3039 --- repos/base-fiasco/lib/mk/core-fiasco.inc | 4 +- repos/base-foc/lib/mk/core-foc.inc | 4 +- repos/base-hw/lib/mk/core-hw.inc | 1 + repos/base-linux/src/core/linux/target.mk | 2 + repos/base-nova/lib/mk/core-nova.inc | 4 +- repos/base-okl4/lib/mk/core-okl4.inc | 4 +- .../base-pistachio/lib/mk/core-pistachio.inc | 4 +- repos/base-sel4/lib/mk/core-sel4.inc | 3 +- repos/base/include/base/child.h | 17 ++++ repos/base/include/parent/client.h | 5 ++ repos/base/include/parent/parent.h | 24 ++++- repos/base/lib/mk/base.inc | 2 +- repos/base/lib/symbols/ld | 4 +- repos/base/src/core/heartbeat.cc | 23 +++++ .../base/src/include/base/internal/globals.h | 2 + repos/base/src/lib/base/child.cc | 36 ++++++++ repos/base/src/lib/base/entrypoint.cc | 4 + repos/base/src/lib/base/heartbeat.cc | 71 +++++++++++++++ .../os/recipes/raw/test-init/test-init.config | 63 +++++++++++++ repos/os/src/app/dummy/main.cc | 3 + repos/os/src/init/child.cc | 6 ++ repos/os/src/init/child.h | 14 +++ repos/os/src/init/heartbeat.h | 89 +++++++++++++++++++ repos/os/src/init/main.cc | 6 +- 24 files changed, 384 insertions(+), 11 deletions(-) create mode 100644 repos/base/src/core/heartbeat.cc create mode 100644 repos/base/src/lib/base/heartbeat.cc create mode 100644 repos/os/src/init/heartbeat.h diff --git a/repos/base-fiasco/lib/mk/core-fiasco.inc b/repos/base-fiasco/lib/mk/core-fiasco.inc index 15bdadef5b..6ff7746720 100644 --- a/repos/base-fiasco/lib/mk/core-fiasco.inc +++ b/repos/base-fiasco/lib/mk/core-fiasco.inc @@ -38,7 +38,8 @@ SRC_CC += stack_area.cc \ signal_transmitter_proxy.cc \ signal_receiver.cc \ thread_start.cc \ - trace_session_component.cc + trace_session_component.cc \ + heartbeat.cc INC_DIR += $(REP_DIR)/src/core/include \ $(GEN_CORE_DIR)/include \ @@ -77,3 +78,4 @@ vpath dump_alloc.cc $(GEN_CORE_DIR) vpath stack_area.cc $(GEN_CORE_DIR) vpath pager_ep.cc $(GEN_CORE_DIR) vpath platform_rom_modules.cc $(GEN_CORE_DIR) +vpath heartbeat.cc $(GEN_CORE_DIR) diff --git a/repos/base-foc/lib/mk/core-foc.inc b/repos/base-foc/lib/mk/core-foc.inc index 036999a8ca..8f8942b77e 100644 --- a/repos/base-foc/lib/mk/core-foc.inc +++ b/repos/base-foc/lib/mk/core-foc.inc @@ -38,7 +38,8 @@ SRC_CC += stack_area.cc \ signal_transmitter_proxy.cc \ signal_receiver.cc \ thread_start.cc \ - trace_session_component.cc + trace_session_component.cc \ + heartbeat.cc INC_DIR += $(REP_DIR)/src/core/include \ $(GEN_CORE_DIR)/include \ @@ -70,5 +71,6 @@ vpath signal_receiver.cc $(GEN_CORE_DIR) vpath core_rpc_cap_alloc.cc $(GEN_CORE_DIR) vpath core_region_map.cc $(GEN_CORE_DIR) vpath platform_rom_modules.cc $(GEN_CORE_DIR) +vpath heartbeat.cc $(GEN_CORE_DIR) vpath %.cc $(REP_DIR)/src/core vpath %.cc $(REP_DIR)/src/lib/base diff --git a/repos/base-hw/lib/mk/core-hw.inc b/repos/base-hw/lib/mk/core-hw.inc index be82f9d34d..21b8ac4c78 100644 --- a/repos/base-hw/lib/mk/core-hw.inc +++ b/repos/base-hw/lib/mk/core-hw.inc @@ -64,6 +64,7 @@ SRC_CC += kernel/object.cc SRC_CC += init_main_thread.cc SRC_CC += capability.cc SRC_CC += stack_area_addr.cc +SRC_CC += heartbeat.cc # provide Genode version information include $(BASE_DIR)/src/core/version.inc diff --git a/repos/base-linux/src/core/linux/target.mk b/repos/base-linux/src/core/linux/target.mk index d3cd205c05..dc747b1709 100644 --- a/repos/base-linux/src/core/linux/target.mk +++ b/repos/base-linux/src/core/linux/target.mk @@ -33,6 +33,7 @@ SRC_CC = main.cc \ core_log_out.cc \ default_log.cc \ env_reinit.cc \ + heartbeat.cc \ thread.cc thread_myself.cc INC_DIR += $(REP_DIR)/src/core/include \ @@ -65,6 +66,7 @@ vpath signal_receiver.cc $(GEN_CORE_DIR) vpath trace_session_component.cc $(GEN_CORE_DIR) vpath core_rpc_cap_alloc.cc $(GEN_CORE_DIR) vpath default_log.cc $(GEN_CORE_DIR) +vpath heartbeat.cc $(GEN_CORE_DIR) vpath thread.cc $(BASE_DIR)/src/lib/base vpath thread_myself.cc $(BASE_DIR)/src/lib/base vpath trace.cc $(BASE_DIR)/src/lib/base diff --git a/repos/base-nova/lib/mk/core-nova.inc b/repos/base-nova/lib/mk/core-nova.inc index cdd9229580..cd815fe127 100644 --- a/repos/base-nova/lib/mk/core-nova.inc +++ b/repos/base-nova/lib/mk/core-nova.inc @@ -40,7 +40,8 @@ SRC_CC += stack_area.cc \ bios_data_area.cc \ trace_session_component.cc \ signal_transmitter_noinit.cc \ - signal_receiver.cc + signal_receiver.cc \ + heartbeat.cc INC_DIR = $(REP_DIR)/src/core/include \ $(REP_DIR)/src/include \ @@ -73,4 +74,5 @@ vpath dump_alloc.cc $(GEN_CORE_DIR) vpath platform_rom_modules.cc $(GEN_CORE_DIR) vpath platform_services.cc $(GEN_CORE_DIR)/spec/x86 vpath stack_area.cc $(GEN_CORE_DIR) +vpath heartbeat.cc $(GEN_CORE_DIR) vpath %.cc $(REP_DIR)/src/core diff --git a/repos/base-okl4/lib/mk/core-okl4.inc b/repos/base-okl4/lib/mk/core-okl4.inc index eed4e855bd..0c2bcc4948 100644 --- a/repos/base-okl4/lib/mk/core-okl4.inc +++ b/repos/base-okl4/lib/mk/core-okl4.inc @@ -41,7 +41,8 @@ SRC_CC += stack_area.cc \ signal_transmitter_proxy.cc \ signal_receiver.cc \ thread_start.cc \ - trace_session_component.cc + trace_session_component.cc \ + heartbeat.cc INC_DIR += $(REP_DIR)/src/core/include $(GEN_CORE_DIR)/include \ $(REP_DIR)/src/include $(GEN_SRC_DIR)/include @@ -75,3 +76,4 @@ vpath default_log.cc $(GEN_CORE_DIR) vpath stack_area.cc $(GEN_CORE_DIR) vpath pager_ep.cc $(GEN_CORE_DIR) vpath platform_rom_modules.cc $(GEN_CORE_DIR) +vpath heartbeat.cc $(GEN_CORE_DIR) diff --git a/repos/base-pistachio/lib/mk/core-pistachio.inc b/repos/base-pistachio/lib/mk/core-pistachio.inc index f39fd036bd..85c0c3fbff 100644 --- a/repos/base-pistachio/lib/mk/core-pistachio.inc +++ b/repos/base-pistachio/lib/mk/core-pistachio.inc @@ -39,7 +39,8 @@ SRC_CC = stack_area.cc \ signal_transmitter_proxy.cc \ signal_receiver.cc \ thread_start.cc \ - trace_session_component.cc + trace_session_component.cc \ + heartbeat.cc INC_DIR += $(REP_DIR)/src/core/include $(GEN_CORE_DIR)/include \ $(REP_DIR)/src/include $(GEN_SRC_DIR)/include @@ -73,3 +74,4 @@ vpath core_region_map.cc $(GEN_CORE_DIR) vpath stack_area.cc $(GEN_CORE_DIR) vpath pager_ep.cc $(GEN_CORE_DIR) vpath platform_rom_modules.cc $(GEN_CORE_DIR) +vpath heartbeat.cc $(GEN_CORE_DIR) diff --git a/repos/base-sel4/lib/mk/core-sel4.inc b/repos/base-sel4/lib/mk/core-sel4.inc index d729de0bcc..c1d17e1895 100644 --- a/repos/base-sel4/lib/mk/core-sel4.inc +++ b/repos/base-sel4/lib/mk/core-sel4.inc @@ -21,7 +21,8 @@ GEN_SRC_CC += \ rom_session_component.cc \ signal_receiver.cc \ signal_transmitter_proxy.cc \ - trace_session_component.cc + trace_session_component.cc \ + heartbeat.cc REP_SRC_CC += \ capability_space.cc \ diff --git a/repos/base/include/base/child.h b/repos/base/include/base/child.h index 8ea9065c9a..52ca5e9d61 100644 --- a/repos/base/include/base/child.h +++ b/repos/base/include/base/child.h @@ -312,11 +312,15 @@ class Genode::Child : protected Rpc_object, Signal_context_capability _resource_avail_sigh { }; Signal_context_capability _yield_sigh { }; Signal_context_capability _session_sigh { }; + Signal_context_capability _heartbeat_sigh { }; /* arguments fetched by the child in response to a yield signal */ Lock _yield_request_lock { }; Resource_args _yield_request_args { }; + /* number of unanswered heartbeat signals */ + unsigned _outstanding_heartbeats = 0; + /* sessions opened by the child */ Id_space _id_space { }; @@ -799,6 +803,17 @@ class Genode::Child : protected Rpc_object, */ void notify_resource_avail() const; + /** + * Notify the child to give a lifesign + */ + void heartbeat(); + + /** + * Return number of missing heartbeats since the last response from + * the child + */ + unsigned skipped_heartbeats() const; + /********************** ** Parent interface ** @@ -820,6 +835,8 @@ class Genode::Child : protected Rpc_object, void yield_sigh(Signal_context_capability) override; Resource_args yield_request() override; void yield_response() override; + void heartbeat_sigh(Signal_context_capability) override; + void heartbeat_response() override; }; #endif /* _INCLUDE__BASE__CHILD_H_ */ diff --git a/repos/base/include/parent/client.h b/repos/base/include/parent/client.h index 61604dcc63..5a6fc949c3 100644 --- a/repos/base/include/parent/client.h +++ b/repos/base/include/parent/client.h @@ -69,6 +69,11 @@ struct Genode::Parent_client : Rpc_client Resource_args yield_request() override { return call(); } void yield_response() override { call(); } + + void heartbeat_sigh(Signal_context_capability sigh) override { + call(sigh); } + + void heartbeat_response() override { call(); } }; #endif /* _INCLUDE__PARENT__CLIENT_H_ */ diff --git a/repos/base/include/parent/parent.h b/repos/base/include/parent/parent.h index b0d758584f..b4141d8a12 100644 --- a/repos/base/include/parent/parent.h +++ b/repos/base/include/parent/parent.h @@ -280,6 +280,25 @@ class Genode::Parent */ virtual void yield_response() = 0; + /* + * Health monitoring + */ + + /** + * Register heartbeat handler + * + * The parent may issue heartbeat signals to the child at any time + * and expects a call of the 'heartbeat_response' RPC function as + * response. When oberving the RPC call, the parent infers that the + * child is still able to respond to external events. + */ + virtual void heartbeat_sigh(Signal_context_capability sigh) = 0; + + /** + * Deliver response to a heartbeat signal + */ + virtual void heartbeat_response() = 0; + /********************* ** RPC declaration ** @@ -315,13 +334,16 @@ class Genode::Parent GENODE_RPC(Rpc_yield_sigh, void, yield_sigh, Signal_context_capability); GENODE_RPC(Rpc_yield_request, Resource_args, yield_request); GENODE_RPC(Rpc_yield_response, void, yield_response); + GENODE_RPC(Rpc_heartbeat_sigh, void, heartbeat_sigh, Signal_context_capability); + GENODE_RPC(Rpc_heartbeat_response, void, heartbeat_response); GENODE_RPC_INTERFACE(Rpc_exit, Rpc_announce, Rpc_session_sigh, Rpc_session, Rpc_session_cap, Rpc_upgrade, Rpc_close, Rpc_session_response, Rpc_main_thread, Rpc_deliver_session_cap, Rpc_resource_avail_sigh, Rpc_resource_request, Rpc_yield_sigh, - Rpc_yield_request, Rpc_yield_response); + Rpc_yield_request, Rpc_yield_response, + Rpc_heartbeat_sigh, Rpc_heartbeat_response); }; diff --git a/repos/base/lib/mk/base.inc b/repos/base/lib/mk/base.inc index 79b6af2a65..7b2b5a9d9b 100644 --- a/repos/base/lib/mk/base.inc +++ b/repos/base/lib/mk/base.inc @@ -1,6 +1,6 @@ SRC_CC += log_console.cc default_log.cc SRC_CC += env_deprecated.cc stack_area.cc env_reinit.cc main_thread_cap.cc -SRC_CC += rpc_cap_alloc.cc +SRC_CC += rpc_cap_alloc.cc heartbeat.cc vpath %.cc $(REP_DIR)/src/lib/base vpath %.cc $(BASE_DIR)/src/lib/base diff --git a/repos/base/lib/symbols/ld b/repos/base/lib/symbols/ld index a1e553f5c3..2fb4e1f0a4 100644 --- a/repos/base/lib/symbols/ld +++ b/repos/base/lib/symbols/ld @@ -236,6 +236,8 @@ _ZN6Genode4SlabD2Ev T _ZN6Genode5AlarmD0Ev T _ZN6Genode5AlarmD1Ev T _ZN6Genode5AlarmD2Ev T +_ZN6Genode5Child9heartbeatEv T +_ZNK6Genode5Child18skipped_heartbeatsEv T _ZN6Genode5Child10yield_sighENS_10CapabilityINS_14Signal_contextEEE T _ZN6Genode5Child11session_capENS_8Id_spaceINS_6Parent6ClientEE2IdE T _ZN6Genode5Child12session_sighENS_10CapabilityINS_14Signal_contextEEE T @@ -557,7 +559,7 @@ _ZTVN6Genode4HeapE D 72 _ZTVN6Genode4SlabE D 72 _ZTVN6Genode5AlarmE D 40 _ZTVN6Genode5Child14Initial_threadE D 48 -_ZTVN6Genode5ChildE D 408 +_ZTVN6Genode5ChildE D 440 _ZTVN6Genode6OutputE D 48 _ZTVN6Genode6ThreadE D 48 _ZTVN6Genode7ConsoleE D 48 diff --git a/repos/base/src/core/heartbeat.cc b/repos/base/src/core/heartbeat.cc new file mode 100644 index 0000000000..146d827cf4 --- /dev/null +++ b/repos/base/src/core/heartbeat.cc @@ -0,0 +1,23 @@ +/* + * \brief Omit heartbeat monitoring because core has no parent + * \author Norman Feske + * \date 2018-11-15 + */ + +/* + * Copyright (C) 2018 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* Genode includes */ +#include + +/* base-internal includes */ +#include + + +void Genode::init_heartbeat_monitoring(Env &) { } +void Genode::deinit_heartbeat_monitoring() { } + diff --git a/repos/base/src/include/base/internal/globals.h b/repos/base/src/include/base/internal/globals.h index 7b873d7c1f..d842bc91a6 100644 --- a/repos/base/src/include/base/internal/globals.h +++ b/repos/base/src/include/base/internal/globals.h @@ -37,6 +37,8 @@ namespace Genode { void init_root_proxy(Env &); void init_log(); void init_parent_resource_requests(Env &); + void init_heartbeat_monitoring(Env &); + void deinit_heartbeat_monitoring(); void exec_static_constructors(); void destroy_signal_thread(); diff --git a/repos/base/src/lib/base/child.cc b/repos/base/src/lib/base/child.cc index b2132f1e3f..96341e704e 100644 --- a/repos/base/src/lib/base/child.cc +++ b/repos/base/src/lib/base/child.cc @@ -721,6 +721,42 @@ Parent::Resource_args Child::yield_request() void Child::yield_response() { _policy.yield_response(); } +void Child::heartbeat() +{ + /* + * Issue heartbeat requests not before the component has registered a + * handler + */ + if (!_heartbeat_sigh.valid()) + return; + + _outstanding_heartbeats++; + + Signal_transmitter(_heartbeat_sigh).submit(); +} + + +unsigned Child::skipped_heartbeats() const +{ + /* + * An '_outstanding_heartbeats' value of 1 is fine because the child needs + * some time to respond to the heartbeat signal. However, at the time when + * the second (or later) heartbeat signal is triggered, the first one + * should have been answered. + */ + return (_outstanding_heartbeats > 1) ? _outstanding_heartbeats - 1 : 0; +} + + +void Child::heartbeat_sigh(Signal_context_capability sigh) +{ + _heartbeat_sigh = sigh; +} + + +void Child::heartbeat_response() { _outstanding_heartbeats = 0; } + + namespace { /** diff --git a/repos/base/src/lib/base/entrypoint.cc b/repos/base/src/lib/base/entrypoint.cc index 54466c57e4..88fc3bbd79 100644 --- a/repos/base/src/lib/base/entrypoint.cc +++ b/repos/base/src/lib/base/entrypoint.cc @@ -146,6 +146,7 @@ void Entrypoint::_process_incoming_signals() _suspend_dispatcher.destruct(); _sig_rec.destruct(); dissolve(_signal_proxy); + deinit_heartbeat_monitoring(); _signal_proxy_cap = Capability(); _rpc_ep.destruct(); destroy_signal_thread(); @@ -156,6 +157,7 @@ void Entrypoint::_process_incoming_signals() init_signal_thread(_env); _rpc_ep.construct(&_env.pd(), Component::stack_size(), initial_ep_name()); + init_heartbeat_monitoring(_env); _signal_proxy_cap = manage(_signal_proxy); _sig_rec.construct(); @@ -289,6 +291,8 @@ namespace { */ init_parent_resource_requests(env); + init_heartbeat_monitoring(env); + Component::construct(env); } }; diff --git a/repos/base/src/lib/base/heartbeat.cc b/repos/base/src/lib/base/heartbeat.cc new file mode 100644 index 0000000000..cf89434f6a --- /dev/null +++ b/repos/base/src/lib/base/heartbeat.cc @@ -0,0 +1,71 @@ +/* + * \brief Heartbeat monitoring support + * \author Norman Feske + * \date 2018-11-15 + */ + +/* + * Copyright (C) 2018 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* Genode includes */ +#include +#include + +/* base-internal includes */ +#include +#include + +using namespace Genode; + +namespace { + + /* + * Respond to heartbeat requests from the parent + */ + struct Heartbeat_handler + { + Env &_env; + + void _handle() { _env.parent().heartbeat_response(); } + + Io_signal_handler _handler { + _env.ep(), *this, &Heartbeat_handler::_handle }; + + Heartbeat_handler(Env &env) : _env(env) + { + _env.parent().heartbeat_sigh(_handler); + } + + ~Heartbeat_handler() + { + _env.parent().heartbeat_sigh(Signal_context_capability()); + } + }; +} + + +static Constructible *_heartbeat_handler_ptr = nullptr; + + +void Genode::init_heartbeat_monitoring(Env &env) +{ + if (_heartbeat_handler_ptr) + return; + + _heartbeat_handler_ptr = unmanaged_singleton>(); + _heartbeat_handler_ptr->construct(env); +} + + +void Genode::deinit_heartbeat_monitoring() +{ + if (!_heartbeat_handler_ptr) + return; + + _heartbeat_handler_ptr->destruct(); + _heartbeat_handler_ptr = nullptr; +} diff --git a/repos/os/recipes/raw/test-init/test-init.config b/repos/os/recipes/raw/test-init/test-init.config index 22e6b23af7..be630285f6 100644 --- a/repos/os/recipes/raw/test-init/test-init.config +++ b/repos/os/recipes/raw/test-init/test-init.config @@ -1400,6 +1400,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/repos/os/src/app/dummy/main.cc b/repos/os/src/app/dummy/main.cc index a1d88fd318..3c937638c6 100644 --- a/repos/os/src/app/dummy/main.cc +++ b/repos/os/src/app/dummy/main.cc @@ -332,6 +332,9 @@ struct Dummy::Main _timer->msleep(node.attribute_value("ms", 100UL)); } + if (node.type() == "sleep_forever") + sleep_forever(); + if (node.type() == "log") log(node.attribute_value("string", String<50>())); diff --git a/repos/os/src/init/child.cc b/repos/os/src/init/child.cc index eaa7a72418..7647b125c4 100644 --- a/repos/os/src/init/child.cc +++ b/repos/os/src/init/child.cc @@ -135,6 +135,8 @@ Init::Child::apply_config(Xml_node start_node) */ _binary_name = _binary_from_xml(start_node, _unique_name); + _heartbeat_enabled = start_node.has_sub_node("heartbeat"); + /* import new start node */ _start_node.construct(_alloc, start_node); } @@ -349,6 +351,9 @@ void Init::Child::report_state(Xml_generator &xml, Report_detail const &detail) if (_exited) xml.attribute("exited", _exit_value); + if (_heartbeat_enabled && _child.skipped_heartbeats()) + xml.attribute("skipped_heartbeats", _child.skipped_heartbeats()); + if (detail.child_ram() && _child.ram_session_cap().valid()) { xml.node("ram", [&] () { @@ -730,6 +735,7 @@ Init::Child::Child(Env &env, _ram_limit_accessor(ram_limit_accessor), _cap_limit_accessor(cap_limit_accessor), _name_registry(name_registry), + _heartbeat_enabled(start_node.has_sub_node("heartbeat")), _resources(_resources_from_start_node(start_node, prio_levels, affinity_space, default_caps_accessor.default_caps(), cap_limit)), _resources_clamped_to_limit((_clamp_resources(ram_limit, cap_limit), true)), diff --git a/repos/os/src/init/child.h b/repos/os/src/init/child.h index 140a3f7e03..e93dcc54a6 100644 --- a/repos/os/src/init/child.h +++ b/repos/os/src/init/child.h @@ -132,6 +132,9 @@ class Init::Child : Child_policy, Routed_service::Wakeup /* updated on configuration update */ Binary_name _binary_name { _binary_from_xml(_start_node->xml(), _unique_name) }; + /* initialized in constructor, updated by 'apply_config' */ + bool _heartbeat_enabled; + /** * Resources assigned to the child */ @@ -527,6 +530,17 @@ class Init::Child : Child_policy, Routed_service::Wakeup void apply_upgrade(); void apply_downgrade(); + void heartbeat() + { + if (_heartbeat_enabled) + _child.heartbeat(); + } + + unsigned skipped_heartbeats() const + { + return _heartbeat_enabled ? _child.skipped_heartbeats() : 0; + } + void report_state(Xml_generator &xml, Report_detail const &detail) const; diff --git a/repos/os/src/init/heartbeat.h b/repos/os/src/init/heartbeat.h new file mode 100644 index 0000000000..d8ad137df4 --- /dev/null +++ b/repos/os/src/init/heartbeat.h @@ -0,0 +1,89 @@ +/* + * \brief Heartbeat monitoring + * \author Norman Feske + * \date 2018-11-15 + */ + +/* + * Copyright (C) 2018 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _SRC__INIT__HEARTBEAT_H_ +#define _SRC__INIT__HEARTBEAT_H_ + +/* local includes */ +#include +#include +#include + +namespace Init { class Heartbeat; } + + +class Init::Heartbeat : Genode::Noncopyable +{ + private: + + Env &_env; + + Child_registry &_children; + + Report_update_trigger &_report_update_trigger; + + Constructible _timer { }; + + unsigned _rate_ms = 0; + + Signal_handler _timer_handler; + + void _handle_timer() + { + bool any_skipped_heartbeats = false; + + _children.for_each_child([&] (Child &child) { + + if (child.skipped_heartbeats()) + any_skipped_heartbeats = true; + + child.heartbeat(); + }); + + if (any_skipped_heartbeats) + _report_update_trigger.trigger_report_update(); + } + + public: + + Heartbeat(Env &env, Child_registry &children, + Report_update_trigger &report_update_trigger) + : + _env(env), _children(children), + _report_update_trigger(report_update_trigger), + _timer_handler(_env.ep(), *this, &Heartbeat::_handle_timer) + { } + + void apply_config(Xml_node config) + { + bool const enabled = config.has_sub_node("heartbeat"); + + _timer.conditional(enabled, _env); + + if (!enabled) { + _rate_ms = 0; + return; + } + + unsigned const rate_ms = + config.sub_node("heartbeat").attribute_value("rate_ms", 1000UL); + + if (rate_ms != _rate_ms) { + _rate_ms = rate_ms; + _timer->sigh(_timer_handler); + _timer->trigger_periodic(_rate_ms*1000); + } + } +}; + +#endif /* _SRC__INIT__HEARTBEAT_H_ */ diff --git a/repos/os/src/init/main.cc b/repos/os/src/init/main.cc index 3868303a63..dd0aa71c1a 100644 --- a/repos/os/src/init/main.cc +++ b/repos/os/src/init/main.cc @@ -16,11 +16,10 @@ #include /* local includes */ -#include #include #include -#include #include +#include namespace Init { struct Main; } @@ -141,6 +140,8 @@ struct Init::Main : State_reporter::Producer, State_reporter _state_reporter { _env, *this }; + Heartbeat _heartbeat { _env, _children, _state_reporter }; + Signal_handler
_resource_avail_handler { _env.ep(), *this, &Main::_handle_resource_avail }; @@ -304,6 +305,7 @@ void Init::Main::_handle_config() _verbose.construct(_config_xml); _state_reporter.apply_config(_config_xml); + _heartbeat.apply_config(_config_xml); /* determine default route for resolving service requests */ try {