sequence: add keep-going feature

When enabling the 'keep_going' config attribute, the component will
carry on in case a child exited with an error. In addition, if the
'restart' attribute is set it will start executing the children from
the beginning.
This commit is contained in:
Josef Söntgen 2019-05-07 13:25:06 +02:00 committed by Christian Helmuth
parent 1583782446
commit dd6bd0f880
2 changed files with 51 additions and 13 deletions

View File

@ -1,7 +1,7 @@
This directory contains a simple utility to serialize the execution of This directory contains a simple utility to serialize the execution of
multiple components. It is configured with "start" XML nodes much like multiple components. It is configured with '<start>' XML nodes much like
_init_ however this component relies on its parent to manage all routing _init_. However, this component relies on its parent to manage all routing
and resources, with the exception of a "config" ROM. No services are and resources, with the exception of a 'config' ROM. No services are
propagated from children to the parent. propagated from children to the parent.
A sample configuration to start a consumer after a producer has exited: A sample configuration to start a consumer after a producer has exited:
@ -24,3 +24,17 @@ A sample configuration to start a consumer after a producer has exited:
! </start> ! </start>
! </config> ! </config>
! </start> ! </start>
There are a few optional '<config>' attributes that control the way the
component operates:
* 'repeat' will instruct the component to repeat the sequence again
starting from the first '<start>' node when it has reached the end.
The default is 'false'.
* 'keep_going' will instruct the component to start the next child
in case the previous one exited with an error. The default is 'false'.
* 'restart' instructs the component to start from the top of the
sequence. It is only evaluted when 'keep_going' is enabled. The
default is 'false'.

View File

@ -75,6 +75,8 @@ struct Sequence::Child : Genode::Child_policy
Genode::Child _child { _env.rm(), _env.ep().rpc_ep(), *this }; Genode::Child _child { _env.rm(), _env.ep().rpc_ep(), *this };
int _exit_value = -1;
Child(Genode::Env &env, Child(Genode::Env &env,
Xml_node const &start_node, Xml_node const &start_node,
Signal_context_capability exit_handler) Signal_context_capability exit_handler)
@ -96,6 +98,8 @@ struct Sequence::Child : Genode::Child_policy
destroy(_services_heap, &service); }); destroy(_services_heap, &service); });
} }
int exit_value() const { return _exit_value; }
/**************************** /****************************
** Child_policy interface ** ** Child_policy interface **
@ -138,18 +142,14 @@ struct Sequence::Child : Genode::Child_policy
Pd_session_capability ref_pd_cap() const override { return _env.pd_session_cap(); } Pd_session_capability ref_pd_cap() const override { return _env.pd_session_cap(); }
/** /**
* If the exit is successful then queue a child reload via a signal, * Always queue a reload signal and store the exit value. The
* otherwise exit this parent component. * parent will then determine which action to take by looking
* at the exit value.
*/ */
void exit(int exit_value) override void exit(int exit_value) override
{ {
if (exit_value == 0) _exit_value = exit_value;
_exit_transmitter.submit(); _exit_transmitter.submit();
else {
error("child \"", name(), "\" exited with exit value ", exit_value);
_env.parent().exit(exit_value);
sleep_forever();
}
} }
/** /**
@ -230,7 +230,31 @@ struct Sequence::Main
void Sequence::Main::start_next_child() void Sequence::Main::start_next_child()
{ {
if (child.constructed()) bool const constructed = child.constructed();
/*
* In case the child exited with an error check if we
* still should keep-going and when doing so if the
* sequence should be restarted.
*/
if (constructed && child->exit_value()) {
bool const keep_going = config_xml.attribute_value("keep_going", false);
bool const restart = config_xml.attribute_value("restart", false);
warning("child \"", child->name(), "\" exited with exit value ",
child->exit_value());
if (!keep_going) {
env.parent().exit(child->exit_value());
sleep_forever();
}
warning("keep-going", restart ? " starting from the beginning" : "");
if (restart)
next_xml_index = 0;
}
if (constructed)
child.destruct(); child.destruct();
try { while (true) { try { while (true) {