diff --git a/repos/os/src/app/sequence/README b/repos/os/src/app/sequence/README
index aabf3b804..aaac28248 100644
--- a/repos/os/src/app/sequence/README
+++ b/repos/os/src/app/sequence/README
@@ -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 '' 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:
!
!
!
+
+There are a few optional '' attributes that control the way the
+component operates:
+
+* 'repeat' will instruct the component to repeat the sequence again
+ starting from the first '' 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'.
diff --git a/repos/os/src/app/sequence/main.cc b/repos/os/src/app/sequence/main.cc
index 6c9e111fe..1069a53b1 100644
--- a/repos/os/src/app/sequence/main.cc
+++ b/repos/os/src/app/sequence/main.cc
@@ -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) {