lib: add bt_{graph,query_executor}_add_interrupter()
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Sun, 21 Jul 2019 01:30:30 +0000 (21:30 -0400)
committerPhilippe Proulx <eeppeliteloop@gmail.com>
Wed, 24 Jul 2019 14:17:16 +0000 (10:17 -0400)
commit9b4f9b425f2efce9a6ccc25f7ae062ebc1116a7d
tree8b8e5746edb2411ae1ee3c13714164d5132fe0e7
parent1e92035335352f8a67cbc3de28a0ad44b7ee02a1
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:
CONTRIBUTING.adoc
include/babeltrace2/babeltrace.h
include/babeltrace2/func-status.h
include/babeltrace2/graph/component-const.h
include/babeltrace2/graph/graph-const.h
include/babeltrace2/graph/graph.h
include/babeltrace2/graph/query-executor-const.h
include/babeltrace2/graph/query-executor.h
include/babeltrace2/graph/self-component-sink.h
include/babeltrace2/graph/self-message-iterator.h
include/babeltrace2/value-const.h
include/babeltrace2/value.h
src/bindings/python/bt2/bt2/__init__.py.in
src/bindings/python/bt2/bt2/component.py
src/bindings/python/bt2/bt2/graph.py
src/bindings/python/bt2/bt2/message_iterator.py
src/bindings/python/bt2/bt2/native_bt_component_class.i
src/bindings/python/bt2/bt2/query_executor.py
src/bindings/python/bt2/bt2/utils.py
src/cli/babeltrace2.c
src/common/common.h
src/lib/func-status.h
src/lib/graph/component-sink.c
src/lib/graph/component.c
src/lib/graph/connection.c
src/lib/graph/graph.c
src/lib/graph/graph.h
src/lib/graph/interrupter.h
src/lib/graph/iterator.c
src/lib/graph/query-executor.c
src/lib/graph/query-executor.h
src/lib/lib-logging.c
src/lib/value.c
src/plugins/ctf/lttng-live/lttng-live.c
src/plugins/ctf/lttng-live/lttng-live.h
src/plugins/ctf/lttng-live/metadata.c
src/plugins/ctf/lttng-live/viewer-connection.c
tests/bindings/python/bt2/test_graph.py
tests/bindings/python/bt2/test_query_executor.py
tests/lib/test_bt_values.c
This page took 0.029744 seconds and 4 git commands to generate.