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
multiple components. It is configured with "start" XML nodes much like
_init_ however this component relies on its parent to manage all routing
and resources, with the exception of a "config" ROM. No services are
multiple components. It is configured with '<start>' XML nodes much like
_init_. However, this component relies on its parent to manage all routing
and resources, with the exception of a 'config' ROM. No services are
propagated from children to the parent.
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>
! </config>
! </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 };
int _exit_value = -1;
Child(Genode::Env &env,
Xml_node const &start_node,
Signal_context_capability exit_handler)
@ -96,6 +98,8 @@ struct Sequence::Child : Genode::Child_policy
destroy(_services_heap, &service); });
}
int exit_value() const { return _exit_value; }
/****************************
** 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(); }
/**
* If the exit is successful then queue a child reload via a signal,
* otherwise exit this parent component.
* Always queue a reload signal and store the exit value. The
* parent will then determine which action to take by looking
* at the exit value.
*/
void exit(int exit_value) override
{
if (exit_value == 0)
_exit_transmitter.submit();
else {
error("child \"", name(), "\" exited with exit value ", exit_value);
_env.parent().exit(exit_value);
sleep_forever();
}
_exit_value = exit_value;
_exit_transmitter.submit();
}
/**
@ -230,7 +230,31 @@ struct Sequence::Main
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();
try { while (true) {