Refactor the plugin registration and loading machinery
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Sat, 21 Jan 2017 06:16:20 +0000 (01:16 -0500)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Sun, 28 May 2017 16:57:37 +0000 (12:57 -0400)
commit6ba0b073d3cc5040234aad3ab820b7ca4022e3e9
treed88093f34153864de9006c67657eb0665db498ed
parentcbb9e0b1ec169269733bcd689294b1fd8be59a2c
Refactor the plugin registration and loading machinery

This patch refactors the plugin registration and loading machinery: the
different, specific symbol names found in the shared object are dropped
in favor of two sections.

The goals of this refactoring are:

1. To allow optional plugin attributes now and in the future.
2. To allow optional component class attributes now and in the future.
3. To make backward and forward compatibility easier.
4. To simplify the plugin development API from a user's perspective.
5. To use the same mechanism to load plugins from a shared object and
   statically from the `babeltrace` binary.

You can still find the macros used to define plugins, plugin attributes,
and component classes in `babeltrace/plugin/plugin-dev`.

We introduce four (IV) new structures to the plugin subsystem:

* A *plugin descriptor* describes a single plugin. Note that one shared
  object can contain one or more plugin descriptors, thus it can contain
  one or more plugins.

  A plugin descriptor contains the interface version of the plugin it
  describes as well as its name (a C string).

  The BT_PLUGIN_WITH_ID() macro creates a plugin descriptor structure
  with a specific identifier in its variable name. It also creates a
  pointer to this structure which is added to the plugin descriptor
  section (`__bt_plugin_descriptors`).

  The BT_PLUGIN() macro is an easy-to-use version of
  BT_PLUGIN_WITH_ID(): it accepts a C identifier which is the name of
  the plugin. Its plugin descriptor ID is `auto`.

* A *plugin descriptor attribute* is an optional attribute attached to a
  specific plugin descriptor.

  A plugin descriptor attribute structure has a type (its key) as well
  as a value (the value's type depends on the attribute type). For debug
  purposes, we also put a string in this structure which is the name of
  the attribute type. This can be used by the plugin subsystem to give
  more information when it warns that an attribute with an unknown type
  was found (use case: current Babeltrace loading a future plugin).

  A plugin descriptor attribute also has a member pointing to its
  "parent" plugin descriptor.

  The following macros each create a plugin descriptor attribute
  structure and a pointer to this structure which is added to the plugin
  attribute section. Each macro accepts a plugin descriptor ID (to
  attach the attribute to the appropriate descriptor) and a value:

  * BT_PLUGIN_INIT_WITH_ID():        Initialization function.
  * BT_PLUGIN_EXIT_WITH_ID():        Exit function.
  * BT_PLUGIN_AUTHOR_WITH_ID():      Author.
  * BT_PLUGIN_LICENSE_WITH_ID():     License.
  * BT_PLUGIN_DESCRIPTION_WITH_ID(): Description.

  You can use the macros above in any order, but you need to use them
  after BT_PLUGIN_INIT*().

  There's an equivalent, easy-to-use macro for each of the macros above
  without the `_WITH_ID` suffix which uses the `auto` plugin descriptor.

* A *component class descriptor* describes a single component class
  attached to a specific plugin descriptor.

  The structure contains the mandatory attributes needed to build a
  component class (name, component type, component initialization
  function).

  The BT_PLUGIN_COMPONENT_CLASS_WITH_ID() macro creates a component
  class descriptor structure with a specific component class descriptor
  identifier in its variable name. The component source type is also
  part of the variable name, as well as the specified plugin descriptor
  ID. The macro also creates a pointer to this structure which is added
  to the component class descriptor section
  (`__bt_plugin_component_descriptors`).

  The easy-to-use BT_PLUGIN_COMPONENT_CLASS() macro uses the `auto`
  plugin descriptor and the name of the component class as the component
  class descriptor ID (a C identifier in this version, to allow this).

  With this new mechanism, the BT_PLUGIN_COMPONENT_CLASSES_BEGIN and
  BT_PLUGIN_COMPONENT_CLASSES_END macros do not exist anymore: you can
  use BT_PLUGIN_COMPONENT_CLASS*() macros anywhere, in any order, as
  long as they appear after BT_PLUGIN_INIT*().

* A *component class descriptor attribute* is an optional attribute
  attached to a specific component class descriptor.

  A component class descriptor attribute structure has a type (its key)
  as well as a value (the value's type depends on the attribute type).
  For debug purposes, we also put a string in this structure which is
  the name of the attribute type.

  A component class descriptor attribute also has a member pointing to
  its "parent" component class descriptor (which itself, as stated
  above, as a member pointing to its "parent" plugin descriptor).

  As of this patch, the only available component class descriptor
  attribute is its optional description. The
  BT_PLUGIN_COMPONENT_CLASS_DESCRIPTION_WITH_ID() macro creates such an
  attribute. BT_PLUGIN_COMPONENT_CLASS_DESCRIPTION() is the easy-to-use
  version which uses the `auto` plugin descriptor.

  You need to place BT_PLUGIN_COMPONENT_CLASS_DESCRIPTION*() after
  the associated BT_PLUGIN_COMPONENT_CLASS*().

We also add the macro BT_PLUGIN_DECLARE() to declare an `extern` plugin
descriptor structure to add plugin attributes to the same plugin
descriptor from different compilation units. Thanks to this, the simple
fact of linking a given object file or not to a shared object is enough
to conditionally add or not one or more component classes.

This approach also has the somewhat interesting side effect of refusing
to build if you define a plugin descriptor attribute without using
BT_PLUGIN_INIT*() (missing name) or if you define the same attribute
twice, since the macros create actual variables which must have unique
names.

When the plugin subsystem loads a shared object, it looks for the
beginning and end symbols for the four sections:

* Plugin descriptors.
* Plugin descriptor attributes.
* Component class descriptors.
* Component class descriptor attributes.

Those are enough to provide everything that is needed to create a plugin
object. A plugin's initialization function is called first, and then its
component classes are created and added sequentially according to the
discovered component class descriptors.

Since a single shared object file can now contain more than one plugin
(descriptor), the following function:

    struct bt_plugin *bt_plugin_create_from_file(const char *path);

is changed to this:

    struct bt_plugin **bt_plugin_create_all_from_file(const char *path);

In other words, the function returns a NULL-terminated array of plugin
objects, just like bt_plugin_create_append_all_from_dir() does.

All the existing plugins and tests are updated to follow the changes.

Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
17 files changed:
include/babeltrace/plugin/plugin-dev.h
include/babeltrace/plugin/plugin-internal.h
include/babeltrace/plugin/plugin.h
lib/component/component-class.c
lib/plugin/plugin.c
plugins/ctf/fs/fs.h
plugins/ctf/lttng-live/lttng-live-internal.h
plugins/ctf/plugin.c
plugins/muxer/muxer.c
plugins/text/text.c
plugins/trimmer/trimmer.c
plugins/writer/writer.c
tests/lib/test-plugin-plugins/Makefile.am
tests/lib/test-plugin-plugins/invalid.c [deleted file]
tests/lib/test-plugin-plugins/minimal.c
tests/lib/test-plugin-plugins/sfs.c
tests/lib/test_plugin.c
This page took 0.027179 seconds and 4 git commands to generate.