lib: add bt_{graph,query_executor}_add_interrupter()
This patch makes it possible to add interrupter objects to a graph or to
a query executor.
To do this, you need to create an interrupter object
(bt_interrupter_create()), add it to a graph or to a query executor with
the new bt_graph_add_interrupter() and
bt_query_executor_add_interrupter() functions. Then you can interrupt
the object with bt_interrupter_set().
Within the whole project, the "cancel" terminology is renamed to
"interrupt", as many times it is possible to resume an interrupted
operation. For example, if you interrupt a running graph and
bt_graph_run() returns `BT_GRAPH_RUN_STATUS_AGAIN`, then you can resume
the graph's operation by calling bt_graph_run() again.
A graph or a query executor is deemed interrupted when any of its
interrupters is set. This makes it possible, for example, to add both a
global interrupter and a thread-specific interrupter to a graph object
so that either the thread-specific action or a global signal handler can
interrupt the graph.
As a convenience, bt_graph_interrupt() (which was bt_graph_cancel()) and
bt_query_executor_interrupt() (which was bt_query_executor_cancel()) are
kept: they set a default interrupter which is always part of the
object's interrupter set.
Conceptually, when a graph runs, each execution context is considered
independently interruptible:
* The execution of a message iterator.
* The execution of a sink component.
* The execution of the bt_graph_run() loop itself.
bt_graph_add_interrupter() conceptually adds the given interrupter to:
* All the graph's message iterators, current and future.
* All the graph's sink components.
* Itself, for bt_graph_run().
This is needed because message iterators typically won't check if they
are interrupted without performing "long" tasks. Because we cannot
guarantee that, bt_graph_run() checks if it's interrupted for each
sink consuming iteration.
This is why bt_graph_is_canceled() and bt_component_graph_is_canceled()
do not exist anymore, while the new
bt_self_message_iterator_is_interrupted() and
bt_self_component_sink_is_interrupted() functions are introduced.
However, because we don't need per-message iterator or per-sink
component interruption yet, bt_self_message_iterator_is_interrupted()
and bt_self_component_sink_is_interrupted() simply check their graph's
interrupters directly. The two functions exist so that, in the future,
we can add interrupters to a single message iterator (and its upstream
message iterators) or to a single sink component if needed.
As of this patch, you cannot remove an interrupter from a graph or from
a query executor as the project does not need this currently.
A message iterator, a sink component, a graph, or a query executor never
returns an "interrupted" status. It is the job of the actor which checks
the interruption status to return an appropriate status:
* Whenever possible, returning an "again" status is the cleanest
approach: this indicates that the operation can resume later, even if
it was interrupted.
* Otherwise, return an error status.
The distinction between a "real" "again" status and an "again" status
caused by an interruption is easy to make from the side controlling the
interrupter: check the interrupter's state to discover it. For example
(Python):
while True:
try:
my_graph.run()
except bt2.TryAgain:
if my_interrupter:
print('interrupted by user')
sys.exit(1)
else:
time.sleep(.1)
The same should be checked when getting an error, as an error can be the
consequence of an interruption (this is what `src.ctf.lttng-live` does
currently as it cannot safely interrupt some network interchanges and
resume them later).
The CLI is changed to have a single, global interrupter object. This
interrupter is added to any query executor or graph. The `SIGINT` signal
handler sets this interrupter. When getting an "again" or an error
status, the CLI checks the interrupter's state to discover if this is
the result of a user action, for example:
case BT_GRAPH_RUN_STATUS_AGAIN:
if (bt_interrupter_is_set(the_interrupter)) {
BT_CLI_LOGW_APPEND_CAUSE("Graph was interrupted by user.");
goto error;
}
/* ... */
In the `bt2` Python package:
* The `bt2.Canceled` exception is removed as it's not needed anymore.
The tests are adapted to demonstrate that.
* Graph.cancel() is changed to Graph.interrupt().
* Graph.is_canceled() is removed.
* There's a new Graph.add_interrupter() method.
* QueryExecutor.cancel() is changed to QueryExecutor.interrupt().
* There's a new QueryExecutor.add_interrupter() method.
* There's a new protected _UserMessageIterator._is_interrupted() method.
* There's a new protected _UserSinkComponent._is_interrupted() method.
Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
Change-Id: I4d6631d39b585bd440457e7fea53a939ec9aaf3a
Reviewed-on: https://review.lttng.org/c/babeltrace/+/1735
Tested-by: jenkins <jenkins@lttng.org>
40 files changed:
This page took 0.029544 seconds and 4 git commands to generate.