Add support for plugins written in Python
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Fri, 3 Feb 2017 20:30:38 +0000 (15:30 -0500)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Sun, 28 May 2017 16:57:37 +0000 (12:57 -0400)
Now that the bt2 package exists and allows a user to create its own
component classes, we're not so far from a Python plugin support, a
Babeltrace plugin being only a set of basic attributes and a list of
component classes.

The chosen approach here is to add a module to the bt2 package,
py_plugin, which contains the following:

* plugin_component_class(): Function to be used as a decorator to tag a
  given user component class as being part of a Babeltrace plugin.

* register_plugin(): Function to be called anywhere from a Python module
  to register this module as a Babeltrace plugin. This call receives
  the name of the plugin and other optional attributes (description,
  author, license, etc.).

* _try_load_plugin_module(): Function reserved for the Babeltrace
  library to try to get a plugin information object from a given
  path (Python file).

  The same logic could be implemented with the Python C API, but since
  a Babeltrace Python plugin needs to import the bt2 package anyway,
  we're sure that the package exists and that we can use it. Arguably
  this function could be located in another module, outside the bt2
  package, for example in /usr/lib/babeltrace/plugin_utils.py.

Here's a very simple Python plugin which contains a single sink
component class named MySink:

    import bt2

    @bt2.plugin_component_class
    class MySink(bt2.UserSinkComponent):
        def __init__(self, params, name):
            self._stuff = params['stuff']

        def _consume(self):
            got_one = False

            for notif_iter in self._input_notification_iterators:
                try:
                    notif = next(notif_iter)
                except StopIteration:
                    continue

                got_one = True

                if isinstance(notif, bt2.TraceEventNotification):
                    event = notif.event
                    print('>>>', self._stuff, event.name)

            if not got_one:
                raise bt2.Stop

    bt2.register_plugin(__name__, name='my_plugin',
                        author='Philippe Proulx', license='MIT',
                        version=(2, 35, 3, '-dev'))

Here's what happens when the C API user does this:

    plugins = bt_plugin_create_all_from_file(
        "python-plugins/bt_plugin_hello.py");

1. bt_plugin_create_all_from_file() calls
   bt_plugin_so_create_all_from_file() without success, because the
   extension does not match.

   Then it tries bt_plugin_python_create_all_from_file().

2. bt_plugin_python_create_all_from_file() makes sure that the base name
   of the file to load starts with `bt_plugin_` and ends with `.py`. The
   prefix is up for debate, but my argument is that we don't want to
   import all the Python files when loading all the plugins of a
   directory: some Python files could be modules imported by plugins,
   not actual plugins. Having the prefix at least reduces the
   possibility of importing a non-plugin Python module.

3. init_python() is called. This function initializes the Python
   interpreter if it's not already done. It also refuses to do so if
   BABELTRACE_DISABLE_PYTHON_PLUGINS=1 (environment variable). It also
   imports the bt2.py_plugin module and finds the
   _try_load_plugin_module() function (global object, put in the
   library's destructor).

   If the needed global objects are still not set after this call,
   bt_plugin_python_create_all_from_file() returns an error. If
   init_python() fails, all the future calls to
   bt_plugin_python_create_all_from_file() will also fail (we don't
   attempt to initialize Python again if it failed once).

4. bt_plugin_python_create_all_from_file() calls
   _try_load_plugin_module() (Python) with the path, let's say
   `python-plugins/bt_plugin_hello.py`.

  a) A module name is created for this plugin. Since the plugin system
     can load plugins from files having the same base name, but in
     different directories, we cannot use the base name here. For
     example, we cannot name the module `bt_plugin_hello`: module names
     are unique in Python (for the whole interpreter) and are registered
     in the sys.modules dictionary.

     What's done here is to hash the path and prefix this with
     `bt_plugin_`. For example, this module would have the name
     bt_plugin_9dc80c7b58e49667cb5898697a5197d22f3a09386d017e08e2....

  b) The function tries to import the module using importlib. The module
     is executed from top to bottom:

    i) The @bt2.plugin_component_class decorator is called on the MySink
       class (which, thanks to its metaclass, has an associated native
       BT component class created): as a reminder, this is the
       equivalent of:

           MySink = bt2.plugin_component_class(MySink)

       This function adds an attribute to MySink: it sets
       MySink._bt_plugin_component_class to None. The mere existence
       of this attribute, whatever its value, means that this user
       component class is part of the plugin.

    ii) The module calls bt2.register_plugin(), passing __name__ as the
        first argument. This is used for bt2.register_plugin() to find
        the module from which it is called. In this case, __name__
        is bt_plugin_9dc80c7b58e49667cb5898697a5197d22f3a09386d017e...
        bt2.register_plugin() gets the actual module object from
        sys.modules and adds the _bt_plugin_info attribute to it after
        checking that all the arguments are correct. This is an object
        which contains, so far, the name and other optional properties
        of the plugin.

  c) If the import is successful, the function looks for the
     _bt_plugin_info attribute in the module object. If it's not found,
     an error is raised.

  d) The function then uses the inspect module to find all the classes
     in the module which contain the _bt_plugin_component_class
     attribute. All the native BT component class addresses are appended
     to a list which is set as the comp_class_addrs attribute of the
     plugin info object.

     _try_load_plugin_module() returns this plugin info object.

5. bt_plugin_python_create_all_from_file() calls
   bt_plugin_from_python_plugin_info() to convert the returned Python
   object to a bt_plugin object, which is returned to the user.

If anything goes wrong on the Python side during this call, and if
BABELTRACE_VERBOSE=1, the Python traceback is printed.

With the plugin above, we can run the converter like this to use its
sink component class:

    babeltrace --plugin-path python-plugins \
               -i ctf.fs -P /path/to/trace \
               -o my_plugin.MySink -p 'stuff="hello there!"'

We get something like this:

    >>> hello there! sched_switch
    >>> hello there! sys_open
    >>> hello there! sched_wakeup
    ...

It seems like Py_InitializeEx() and PyImport_ImportModule() can override
the current SIGINT handler, which is why we save the old handler before
calling those and then restore it afterwards. This seems to work.

Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
13 files changed:
bindings/python/bt2/Makefile.am
bindings/python/bt2/__init__.py.in
bindings/python/bt2/py_plugin.py [new file with mode: 0644]
configure.ac
include/Makefile.am
include/babeltrace/plugin/plugin-internal.h
include/babeltrace/plugin/plugin-python-disabled-internal.h [new file with mode: 0644]
include/babeltrace/plugin/plugin-python-enabled-internal.h [new file with mode: 0644]
include/babeltrace/plugin/plugin-so-internal.h [new file with mode: 0644]
lib/plugin/Makefile.am
lib/plugin/plugin-python.c [new file with mode: 0644]
lib/plugin/plugin-so.c [new file with mode: 0644]
lib/plugin/plugin.c

index 4989a72cd3ed30af44eed0094631314dfeaccd21..e2f01e603c3f5e350fb52f9220ecd360435c184f 100644 (file)
@@ -39,7 +39,8 @@ EXTRA_MODULES =               \
        component               \
        notification            \
        notification_iterator   \
-       plugin
+       plugin                  \
+       py_plugin
 
 # automatically generated file lists
 EXTRA_MODULES_PY = $(addprefix $(srcdir)/,$(addsuffix .py,$(EXTRA_MODULES)))
index 9a8c93c4a7343e863ac2ba7ee43483b3e86a24f8..452cb3267c3c5518b915ef281db0d68c97bfea1d 100644 (file)
@@ -32,6 +32,7 @@ from bt2.fields import *
 from bt2.notification import *
 from bt2.notification_iterator import *
 from bt2.plugin import *
+from bt2.py_plugin import *
 from bt2.stream_class import *
 from bt2.trace import *
 from bt2.values import *
diff --git a/bindings/python/bt2/py_plugin.py b/bindings/python/bt2/py_plugin.py
new file mode 100644 (file)
index 0000000..b845030
--- /dev/null
@@ -0,0 +1,135 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+from bt2 import utils
+import bt2.component
+
+
+def plugin_component_class(component_class):
+    if not issubclass(component_class, bt2.component._UserComponent):
+        raise TypeError('component class is not a subclass of a user component class')
+
+    component_class._bt_plugin_component_class = None
+    return component_class
+
+
+def register_plugin(module_name, name, description=None, author=None,
+                    license=None, version=None):
+    import sys
+
+    if module_name not in sys.modules:
+        raise RuntimeError("cannot find module '{}' in loaded modules".format(module_name))
+
+    utils._check_str(name)
+
+    if description is not None:
+        utils._check_str(description)
+
+    if author is not None:
+        utils._check_str(author)
+
+    if license is not None:
+        utils._check_str(license)
+
+    if version is not None:
+        if not _validate_version(version):
+            raise ValueError('wrong version: expecting a tuple: (major, minor, patch) or (major, minor, patch, extra)')
+
+    sys.modules[module_name]._bt_plugin_info = _PluginInfo(name, description,
+                                                           author, license,
+                                                           version)
+
+
+def _validate_version(version):
+    if version is None:
+        return True
+
+    if not isinstance(version, tuple):
+        return False
+
+    if len(version) < 3 or len(version) > 4:
+        return False
+
+    if not isinstance(version[0], int):
+        return False
+
+    if not isinstance(version[1], int):
+        return False
+
+    if not isinstance(version[2], int):
+        return False
+
+    if len(version) == 4:
+        if not isinstance(version[3], str):
+            return False
+
+    return True
+
+
+class _PluginInfo:
+    def __init__(self, name, description, author, license, version):
+        self.name = name
+        self.description = description
+        self.author = author
+        self.license = license
+        self.version = version
+        self.comp_class_addrs = None
+
+
+# called by the BT plugin system
+def _try_load_plugin_module(path):
+    import importlib.machinery
+    import inspect
+    import hashlib
+
+    if path is None:
+        raise TypeError('missing path')
+
+    # In order to load the module uniquely from its path, even from
+    # different files which have the same basename, we hash the path
+    # and prefix with `bt_plugin_`. This is its key in sys.modules.
+    h = hashlib.sha256()
+    h.update(path.encode())
+    module_name = 'bt_plugin_{}'.format(h.hexdigest())
+
+    # try loading the module: any raised exception is catched by the caller
+    mod = importlib.machinery.SourceFileLoader(module_name, path).load_module()
+
+    # we have the module: look for its plugin info first
+    if not hasattr(mod, '_bt_plugin_info'):
+        raise RuntimeError("missing '_bt_plugin_info' module attribute")
+
+    plugin_info = mod._bt_plugin_info
+
+    # search for user component classes
+    def is_user_comp_class(obj):
+        if not inspect.isclass(obj):
+            return False
+
+        if not hasattr(obj, '_bt_plugin_component_class'):
+            return False
+
+        return True
+
+    comp_class_entries = inspect.getmembers(mod, is_user_comp_class)
+    plugin_info.comp_class_addrs = [entry[1].addr for entry in comp_class_entries]
+    return plugin_info
index 554a5b05ef2d273fe68a41344792faee63149188..f4902254f872b3b67ab8ef0c1ddf89b7b7151f6b 100644 (file)
@@ -242,36 +242,28 @@ swig_version=2.0.0
 AC_ARG_ENABLE([python-bindings],
               [AC_HELP_STRING([--enable-python-bindings],
                               [generate Python bindings])],
-              [enable_python=yes], [enable_python=no])
+              [enable_python_bindings=yes], [enable_python_bindings=no])
 
-AM_CONDITIONAL([USE_PYTHON], [test "x${enable_python:-yes}" = xyes])
+AM_CONDITIONAL([USE_PYTHON], [test "x${enable_python_bindings:-yes}" = xyes])
 
-AC_ARG_ENABLE([python-bindings-doc],
-              [AC_HELP_STRING([--enable-python-bindings-doc],
-                              [generate Python bindings documentation])],
-              [enable_python_bindings_doc=yes], [enable_python_bindings_doc=no])
-
-AC_ARG_ENABLE([python-bindings-tests],
-              [AC_HELP_STRING([--enable-python-bindings-tests],
-                              [test Python bindings])],
-              [enable_python_bindings_tests=yes], [enable_python_bindings_tests=no])
-
-AM_CONDITIONAL([ENABLE_PYTHON_BINDINGS_TESTS], [test "x${enable_python_bindings_tests:-yes}" = xyes])
-
-if test "x${enable_python:-no}" = xno; then
-  if test "x${enable_python_bindings_doc:-yes}" = xyes; then
-    AC_MSG_ERROR([--enable-python-bindings-doc was specified without --enable-python-bindings])
-  fi
+AC_ARG_ENABLE(
+       [python-plugins],
+       [AC_HELP_STRING(
+               [--enable-python-plugins],
+               [add support for the Babeltrace library and converter to load Python plugins])
+       ],
+       [enable_python_plugins=yes],
+       [enable_python_plugins=no]
+)
 
-  if test "x${enable_python_bindings_tests:-yes}" = xyes; then
-    AC_MSG_ERROR([--enable-python-bindings-tests was specified without --enable-python-bindings])
-  fi
+if test "x${enable_python_bindings:-yes}" = xyes; then
+  AX_PKG_SWIG($swig_version, [], [ AC_MSG_ERROR([SWIG $swig_version or newer is needed]) ])
+else
+    AC_MSG_NOTICE([You may configure with --enable-python-bindings ]dnl
+[if you want Python bindings.])
 fi
 
-AM_CONDITIONAL([BUILD_PYTHON_BINDINGS_DOC], [test "x${enable_python_bindings_doc:-yes}" = xyes])
-
-if test "x${enable_python:-yes}" = xyes; then
-  AX_PKG_SWIG($swig_version, [], [ AC_MSG_ERROR([SWIG $swig_version or newer is needed]) ])
+if test "x$enable_python_bindings" != xno || test "x$enable_python_plugins" != xno; then
   AM_PATH_PYTHON([3.0], , [AC_MSG_ERROR(Python3 is not available or is not the default Python interpreter on your system. See the README file to learn how to override your distribution's default Python interpreter.)])
 
   AM_PATH_PYTHON_MODULES([PYTHON])
@@ -279,7 +271,8 @@ if test "x${enable_python:-yes}" = xyes; then
   pythondir=$PYTHON_PREFIX/$PYTHON_MODULES_PATH
   # pyexecdir is the path that contains shared objects used by the extra modules
   pyexecdir=$PYTHON_EXEC_PREFIX/$PYTHON_MODULES_PATH
-  AC_ARG_VAR([PYTHON_INCLUDE], [Include flags for python, bypassing python-config])
+  AC_ARG_VAR([PYTHON_INCLUDE], [Include flags for Python, bypassing python-config])
+  AC_ARG_VAR([PYTHON_LIBS], [Library flags for Python, bypassing python-config])
   AC_ARG_VAR([PYTHON_CONFIG], [Path to python-config])
   AS_IF([test -z "$PYTHON_INCLUDE"], [
     AS_IF([test -z "$PYTHON_CONFIG"], [
@@ -289,14 +282,52 @@ if test "x${enable_python:-yes}" = xyes; then
                     [`dirname $PYTHON`])
       AS_IF([test "$PYTHON_CONFIG" = no], [AC_MSG_ERROR([cannot find python-config for $PYTHON. Do you have python-dev installed?])])
     ])
-    AC_MSG_CHECKING([python include flags])
+    AC_MSG_CHECKING([Python include flags])
     PYTHON_INCLUDE=`$PYTHON_CONFIG --includes`
     AC_MSG_RESULT([$PYTHON_INCLUDE])
   ])
-else
-    AC_MSG_NOTICE([You may configure with --enable-python-bindings ]dnl
-[if you want Python bindings.])
+  AS_IF([test -z "$PYTHON_LIBS"], [
+    AS_IF([test -z "$PYTHON_CONFIG"], [
+      AC_PATH_PROGS([PYTHON_CONFIG],
+                    [python$PYTHON_VERSION-config python-config],
+                    [no],
+                    [`dirname $PYTHON`])
+      AS_IF([test "$PYTHON_CONFIG" = no], [AC_MSG_ERROR([cannot find python-config for $PYTHON. Do you have python-dev installed?])])
+    ])
+    AC_MSG_CHECKING([Python library flags])
+    PYTHON_LIBS=`$PYTHON_CONFIG --libs`
+    AC_MSG_RESULT([$PYTHON_LIBS])
+  ])
+fi
+
+AM_CONDITIONAL([WITH_PYTHON_PLUGINS], [test "x$enable_python_plugins" != xno])
+AS_IF(
+  [test "x$enable_python_plugins" != xno],
+  AC_DEFINE_UNQUOTED([WITH_PYTHON_PLUGINS], [1], [Python plugin support.])
+)
+
+AC_ARG_ENABLE([python-bindings-doc],
+              [AC_HELP_STRING([--enable-python-bindings-doc],
+                              [generate Python bindings documentation])],
+              [enable_python_bindings_doc=yes], [enable_python_bindings_doc=no])
+
+AM_CONDITIONAL([BUILD_PYTHON_BINDINGS_DOC], [test "x${enable_python_bindings_doc:-yes}" = xyes])
 
+AC_ARG_ENABLE([python-bindings-tests],
+              [AC_HELP_STRING([--enable-python-bindings-tests],
+                              [test Python bindings])],
+              [enable_python_bindings_tests=yes], [enable_python_bindings_tests=no])
+
+AM_CONDITIONAL([ENABLE_PYTHON_BINDINGS_TESTS], [test "x${enable_python_bindings_tests:-yes}" = xyes])
+
+if test "x${enable_python_bindings:-no}" = xno; then
+  if test "x${enable_python_bindings_doc:-yes}" = xyes; then
+    AC_MSG_ERROR([--enable-python-bindings-doc was specified without --enable-python-bindings])
+  fi
+
+  if test "x${enable_python_bindings_tests:-yes}" = xyes; then
+    AC_MSG_ERROR([--enable-python-bindings-tests was specified without --enable-python-bindings])
+  fi
 fi
 
 if test "x${enable_python_bindings_doc:-yes}" = xyes; then
@@ -522,7 +553,7 @@ test "x$enable_api_doc" = "xyes" && value=1 || value=0
 PPRINT_PROP_BOOL([HTML API documentation], $value)
 
 # python bindings enabled/disabled
-test "x$enable_python" = "xyes" && value=1 || value=0
+test "x$enable_python_bindings" = "xyes" && value=1 || value=0
 PPRINT_PROP_BOOL([Python bindings], $value)
 
 # python bindings doc enabled/disabled
@@ -533,6 +564,10 @@ PPRINT_PROP_BOOL([Python bindings doc], $value)
 test "x$enable_python_bindings_tests" = "xyes" && value=1 || value=0
 PPRINT_PROP_BOOL([Python bindings tests], $value)
 
+# python plugins enabled/disabled
+test "x$enable_python_plugins" = "xyes" && value=1 || value=0
+PPRINT_PROP_BOOL([Python plugin support], $value)
+
 # debug info enabled/disabled
 test "x$_enable_debug_info" = "xyes" && value=1 || value=0
 PPRINT_PROP_BOOL([Debug information output], $value)
index bfd2a16688ba3ba3623a3f00a45fda250bc0a089..b05e6469ddd2e46334ded95d7af63e805ffe2082 100644 (file)
@@ -123,6 +123,9 @@ noinst_HEADERS = \
        babeltrace/endian.h \
        babeltrace/mmap-align.h \
        babeltrace/plugin/plugin-internal.h \
+       babeltrace/plugin/plugin-so-internal.h \
+       babeltrace/plugin/plugin-python-enabled-internal.h \
+       babeltrace/plugin/plugin-python-disabled-internal.h \
        babeltrace/component/component-class-internal.h \
        babeltrace/component/component-connection-internal.h \
        babeltrace/component/component-internal.h \
index 4f361d6d6d2931285565f81fe64cb637581f43e0..eb72e9445b9101d097a3738120971fd8006bc8d0 100644 (file)
 #include <babeltrace/plugin/plugin-dev.h>
 #include <babeltrace/object-internal.h>
 #include <stdbool.h>
-#include <gmodule.h>
+#include <glib.h>
 
-struct bt_plugin_shared_lib_handle {
-       struct bt_object base;
-       GString *path;
-       GModule *module;
-
-       /* True if initialization function was called */
-       bool init_called;
-       bt_plugin_exit_func exit;
+enum bt_plugin_type {
+       BT_PLUGIN_TYPE_SO = 0,
+       BT_PLUGIN_TYPE_PYTHON = 1,
 };
 
 struct bt_plugin {
        struct bt_object base;
+       enum bt_plugin_type type;
        bool frozen;
 
-       /* Owned by this */
-       struct bt_plugin_shared_lib_handle *shared_lib_handle;
-
        /* Array of pointers to bt_component_class (owned by this) */
        GPtrArray *comp_classes;
 
-       /* Pointers to plugin's memory: do NOT free */
-       const struct __bt_plugin_descriptor *descriptor;
-       const char *name;
-       const char *author;
-       const char *license;
-       const char *description;
-       bt_plugin_init_func init;
-       const struct __bt_plugin_descriptor_version *version;
+       /* Info (owned by this) */
+       struct {
+               GString *path;
+               GString *name;
+               GString *author;
+               GString *license;
+               GString *description;
+               struct {
+                       unsigned int major;
+                       unsigned int minor;
+                       unsigned int patch;
+                       GString *extra;
+               } version;
+               bool path_set;
+               bool name_set;
+               bool author_set;
+               bool license_set;
+               bool description_set;
+               bool version_set;
+       } info;
+
+       /* Value depends on the specific plugin type */
+       void *spec_data;
 };
 
+BT_HIDDEN
+struct bt_plugin *bt_plugin_create_empty(enum bt_plugin_type type);
+
+static inline
+void bt_plugin_set_path(struct bt_plugin *plugin, const char *path)
+{
+       assert(plugin);
+       assert(path);
+       g_string_assign(plugin->info.path, path);
+       plugin->info.path_set = true;
+}
+
+static inline
+void bt_plugin_set_name(struct bt_plugin *plugin, const char *name)
+{
+       assert(plugin);
+       assert(name);
+       g_string_assign(plugin->info.name, name);
+       plugin->info.name_set = true;
+}
+
+static inline
+void bt_plugin_set_description(struct bt_plugin *plugin,
+               const char *description)
+{
+       assert(plugin);
+       assert(description);
+       g_string_assign(plugin->info.description, description);
+       plugin->info.description_set = true;
+}
+
+static inline
+void bt_plugin_set_author(struct bt_plugin *plugin, const char *author)
+{
+       assert(plugin);
+       assert(author);
+       g_string_assign(plugin->info.author, author);
+       plugin->info.author_set = true;
+}
+
+static inline
+void bt_plugin_set_license(struct bt_plugin *plugin, const char *license)
+{
+       assert(plugin);
+       assert(license);
+       g_string_assign(plugin->info.license, license);
+       plugin->info.license_set = true;
+}
+
+static inline
+void bt_plugin_set_version(struct bt_plugin *plugin, unsigned int major,
+               unsigned int minor, unsigned int patch, const char *extra)
+{
+       assert(plugin);
+       plugin->info.version.major = major;
+       plugin->info.version.minor = minor;
+       plugin->info.version.patch = patch;
+
+       if (extra) {
+               g_string_assign(plugin->info.version.extra, extra);
+       }
+
+       plugin->info.version_set = true;
+}
+
+static inline
+void bt_plugin_freeze(struct bt_plugin *plugin)
+{
+       assert(plugin);
+       plugin->frozen = true;
+}
+
 #endif /* BABELTRACE_PLUGIN_PLUGIN_INTERNAL_H */
diff --git a/include/babeltrace/plugin/plugin-python-disabled-internal.h b/include/babeltrace/plugin/plugin-python-disabled-internal.h
new file mode 100644 (file)
index 0000000..dec6fc1
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef BABELTRACE_PLUGIN_PLUGIN_PYTHON_DISABLED_INTERNAL_H
+#define BABELTRACE_PLUGIN_PLUGIN_PYTHON_DISABLED_INTERNAL_H
+
+/*
+ * BabelTrace - Babeltrace Plug-in Interface
+ *
+ * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+struct bt_plugin;
+
+static inline
+struct bt_plugin **bt_plugin_python_create_all_from_file(const char *path)
+{
+       return NULL;
+}
+
+static inline
+void bt_plugin_python_destroy_spec_data(struct bt_plugin *plugin)
+{
+}
+
+#endif /* BABELTRACE_PLUGIN_PLUGIN_PYTHON_DISABLED_INTERNAL_H */
diff --git a/include/babeltrace/plugin/plugin-python-enabled-internal.h b/include/babeltrace/plugin/plugin-python-enabled-internal.h
new file mode 100644 (file)
index 0000000..b1d0345
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef BABELTRACE_PLUGIN_PLUGIN_PYTHON_ENABLED_INTERNAL_H
+#define BABELTRACE_PLUGIN_PLUGIN_PYTHON_ENABLED_INTERNAL_H
+
+/*
+ * BabelTrace - Babeltrace Plug-in Interface
+ *
+ * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+struct bt_plugin;
+
+BT_HIDDEN
+struct bt_plugin **bt_plugin_python_create_all_from_file(const char *path);
+
+static inline
+void bt_plugin_python_destroy_spec_data(struct bt_plugin *plugin)
+{
+}
+
+#endif /* BABELTRACE_PLUGIN_PLUGIN_PYTHON_ENABLED_INTERNAL_H */
diff --git a/include/babeltrace/plugin/plugin-so-internal.h b/include/babeltrace/plugin/plugin-so-internal.h
new file mode 100644 (file)
index 0000000..4e3bc86
--- /dev/null
@@ -0,0 +1,70 @@
+#ifndef BABELTRACE_PLUGIN_PLUGIN_SO_INTERNAL_H
+#define BABELTRACE_PLUGIN_PLUGIN_SO_INTERNAL_H
+
+/*
+ * BabelTrace - Babeltrace Plug-in Interface
+ *
+ * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <glib.h>
+#include <gmodule.h>
+
+struct bt_plugin;
+struct bt_component_class;
+
+struct bt_plugin_so_shared_lib_handle {
+       struct bt_object base;
+       GString *path;
+       GModule *module;
+
+       /* True if initialization function was called */
+       bool init_called;
+       bt_plugin_exit_func exit;
+};
+
+struct bt_plugin_so_spec_data {
+       /* Shared lib. handle: owned by this */
+       struct bt_plugin_so_shared_lib_handle *shared_lib_handle;
+
+       /* Pointers to plugin's memory: do NOT free */
+       const struct __bt_plugin_descriptor *descriptor;
+       bt_plugin_init_func init;
+       const struct __bt_plugin_descriptor_version *version;
+};
+
+BT_HIDDEN
+struct bt_plugin **bt_plugin_so_create_all_from_file(const char *path);
+
+BT_HIDDEN
+struct bt_plugin **bt_plugin_so_create_all_from_static(void);
+
+BT_HIDDEN
+int bt_plugin_so_on_add_component_class(struct bt_plugin *plugin,
+               struct bt_component_class *comp_class);
+
+BT_HIDDEN
+void bt_plugin_so_destroy_spec_data(struct bt_plugin *plugin);
+
+#endif /* BABELTRACE_PLUGIN_PLUGIN_SO_INTERNAL_H */
index 6a5e4a1112403004430c7530f95e1f3319e09233..355a31f89d72da52ef433bf7c0bf529d371ba28f 100644 (file)
@@ -1,7 +1,13 @@
-AM_CFLAGS = $(PACKAGE_CFLAGS) -I$(top_srcdir)/include
+AM_CFLAGS = $(PYTHON_INCLUDE) $(PACKAGE_CFLAGS) -I$(top_srcdir)/include
 
 noinst_LTLIBRARIES = libplugin.la
 
 # Plug-in system library
 libplugin_la_SOURCES = \
-       plugin.c
+       plugin.c \
+       plugin-so.c
+
+if WITH_PYTHON_PLUGINS
+libplugin_la_SOURCES += plugin-python.c
+libplugin_la_LDFLAGS = $(PYTHON_LIBS)
+endif
diff --git a/lib/plugin/plugin-python.c b/lib/plugin/plugin-python.c
new file mode 100644 (file)
index 0000000..fc897ee
--- /dev/null
@@ -0,0 +1,454 @@
+/*
+ * plugin-python.c
+ *
+ * Babeltrace Plugin (Python)
+ *
+ * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <babeltrace/babeltrace-internal.h>
+#include <babeltrace/compiler.h>
+#include <babeltrace/ref.h>
+#include <babeltrace/plugin/plugin-internal.h>
+#include <babeltrace/plugin/plugin-internal.h>
+#include <babeltrace/component/component-class-internal.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <Python.h>
+
+#define PYTHON_PLUGIN_FILE_PREFIX      "bt_plugin_"
+#define PYTHON_PLUGIN_FILE_PREFIX_LEN  (sizeof(PYTHON_PLUGIN_FILE_PREFIX) - 1)
+#define PYTHON_PLUGIN_FILE_EXT         ".py"
+#define PYTHON_PLUGIN_FILE_EXT_LEN     (sizeof(PYTHON_PLUGIN_FILE_EXT) - 1)
+
+enum python_state {
+       /* init_python() not called yet */
+       PYTHON_STATE_NOT_INITED,
+
+       /* init_python() called once with success */
+       PYTHON_STATE_FULLY_INITIALIZED,
+
+       /* init_python() called once without success */
+       PYTHON_STATE_CANNOT_INITIALIZE,
+} python_state = PYTHON_STATE_NOT_INITED;
+
+static PyObject *py_try_load_plugin_module_func = NULL;
+
+static
+void print_python_traceback_verbose(void)
+{
+       if (Py_IsInitialized() && PyErr_Occurred() && babeltrace_verbose) {
+               PyErr_Print();
+       }
+}
+
+static
+void pyerr_clear(void)
+{
+       if (Py_IsInitialized()) {
+               PyErr_Clear();
+       }
+}
+
+static
+void init_python(void)
+{
+       PyObject *py_bt2_py_plugin_mod = NULL;
+       const char *dis_python_env;
+       sighandler_t old_sigint = signal(SIGINT, SIG_DFL);
+
+       if (python_state != PYTHON_STATE_NOT_INITED) {
+               goto end;
+       }
+
+       /*
+        * User can disable Python plugin support with the
+        * BABELTRACE_DISABLE_PYTHON_PLUGINS environment variable set to
+        * 1.
+        */
+       dis_python_env = getenv("BABELTRACE_DISABLE_PYTHON_PLUGINS");
+       if (dis_python_env && dis_python_env[0] == '1' &&
+                       dis_python_env[1] == '\0') {
+               printf_verbose("Python plugin support is disabled by BABELTRACE_DISABLE_PYTHON_PLUGINS environment variable\n");
+               python_state = PYTHON_STATE_CANNOT_INITIALIZE;
+               goto end;
+       }
+
+       if (!Py_IsInitialized()) {
+               Py_InitializeEx(0);
+               printf_verbose("Initialized Python:\n%s\n", Py_GetVersion());
+       }
+
+       py_bt2_py_plugin_mod = PyImport_ImportModule("bt2.py_plugin");
+       if (!py_bt2_py_plugin_mod) {
+               printf_verbose("Cannot import bt2.py_plugin Python module\n");
+               python_state = PYTHON_STATE_CANNOT_INITIALIZE;
+               goto end;
+       }
+
+       py_try_load_plugin_module_func =
+               PyObject_GetAttrString(py_bt2_py_plugin_mod, "_try_load_plugin_module");
+       if (!py_try_load_plugin_module_func) {
+               printf_verbose("Cannot get _try_load_plugin_module attribute from bt2.py_plugin Python module\n");
+               python_state = PYTHON_STATE_CANNOT_INITIALIZE;
+               goto end;
+       }
+
+       python_state = PYTHON_STATE_FULLY_INITIALIZED;
+
+end:
+       if (old_sigint != SIG_ERR) {
+               (void) signal(SIGINT, old_sigint);
+       }
+
+       print_python_traceback_verbose();
+       pyerr_clear();
+       Py_XDECREF(py_bt2_py_plugin_mod);
+       return;
+}
+
+__attribute__((destructor)) static
+void fini_python(void) {
+       if (Py_IsInitialized()) {
+               if (py_try_load_plugin_module_func) {
+                       Py_DECREF(py_try_load_plugin_module_func);
+                       py_try_load_plugin_module_func = NULL;
+               }
+
+               Py_Finalize();
+       }
+
+       python_state = PYTHON_STATE_NOT_INITED;
+}
+
+static
+struct bt_plugin *bt_plugin_from_python_plugin_info(PyObject *plugin_info)
+{
+       struct bt_plugin *plugin = NULL;
+       PyObject *py_name = NULL;
+       PyObject *py_author = NULL;
+       PyObject *py_description = NULL;
+       PyObject *py_license = NULL;
+       PyObject *py_version = NULL;
+       PyObject *py_comp_class_addrs = NULL;
+       const char *name = NULL;
+       const char *author = NULL;
+       const char *description = NULL;
+       const char *license = NULL;
+       unsigned int major = 0, minor = 0, patch = 0;
+       const char *version_extra = NULL;
+       int ret;
+
+       assert(plugin_info);
+       assert(python_state == PYTHON_STATE_FULLY_INITIALIZED);
+       py_name = PyObject_GetAttrString(plugin_info, "name");
+       if (!py_name) {
+               printf_verbose("Cannot find `name` attribute in plugin info\n");
+               goto error;
+       }
+
+       py_author = PyObject_GetAttrString(plugin_info, "author");
+       if (!py_author) {
+               printf_verbose("Cannot find `author` attribute in plugin info\n");
+               goto error;
+       }
+
+       py_description = PyObject_GetAttrString(plugin_info, "description");
+       if (!py_description) {
+               printf_verbose("Cannot find `description` attribute in plugin info\n");
+               goto error;
+       }
+
+       py_license = PyObject_GetAttrString(plugin_info, "license");
+       if (!py_license) {
+               printf_verbose("Cannot find `license` attribute in plugin info\n");
+               goto error;
+       }
+
+       py_version = PyObject_GetAttrString(plugin_info, "version");
+       if (!py_version) {
+               printf_verbose("Cannot find `version` attribute in plugin info\n");
+               goto error;
+       }
+
+       py_comp_class_addrs = PyObject_GetAttrString(plugin_info,
+               "comp_class_addrs");
+       if (!py_comp_class_addrs) {
+               printf_verbose("Cannot find `comp_class_addrs` attribute in plugin info\n");
+               goto error;
+       }
+
+       if (PyUnicode_Check(py_name)) {
+               name = PyUnicode_AsUTF8(py_name);
+               if (!name) {
+                       printf_verbose("Cannot decode plugin name string\n");
+                       goto error;
+               }
+       } else {
+               /* Plugin name is mandatory */
+               printf_verbose("Plugin name is not a string\n");
+               goto error;
+       }
+
+       if (PyUnicode_Check(py_author)) {
+               author = PyUnicode_AsUTF8(py_author);
+               if (!author) {
+                       printf_verbose("Cannot decode plugin author string\n");
+                       goto error;
+               }
+       }
+
+       if (PyUnicode_Check(py_description)) {
+               description = PyUnicode_AsUTF8(py_description);
+               if (!description) {
+                       printf_verbose("Cannot decode plugin description string\n");
+                       goto error;
+               }
+       }
+
+       if (PyUnicode_Check(py_license)) {
+               license = PyUnicode_AsUTF8(py_license);
+               if (!license) {
+                       printf_verbose("Cannot decode plugin license string\n");
+                       goto error;
+               }
+       }
+
+       if (PyTuple_Check(py_version)) {
+               if (PyTuple_Size(py_version) >= 3) {
+                       PyObject *py_major = PyTuple_GetItem(py_version, 0);
+                       PyObject *py_minor = PyTuple_GetItem(py_version, 1);
+                       PyObject *py_patch = PyTuple_GetItem(py_version, 2);
+
+                       assert(py_major);
+                       assert(py_minor);
+                       assert(py_patch);
+
+                       if (PyLong_Check(py_major)) {
+                               major = PyLong_AsUnsignedLong(py_major);
+                       }
+
+                       if (PyLong_Check(py_minor)) {
+                               minor = PyLong_AsUnsignedLong(py_minor);
+                       }
+
+                       if (PyLong_Check(py_patch)) {
+                               patch = PyLong_AsUnsignedLong(py_patch);
+                       }
+
+                       if (PyErr_Occurred()) {
+                               /* Overflow error, most probably */
+                               printf_verbose("Invalid plugin version format\n");
+                               goto error;
+                       }
+               }
+
+               if (PyTuple_Size(py_version) >= 4) {
+                       PyObject *py_extra = PyTuple_GetItem(py_version, 3);
+
+                       assert(py_extra);
+
+                       if (PyUnicode_Check(py_extra)) {
+                               version_extra = PyUnicode_AsUTF8(py_extra);
+                               if (!version_extra) {
+                                       printf_verbose("Cannot decode plugin version's extra string\n");
+                                       goto error;
+                               }
+                       }
+               }
+       }
+
+       plugin = bt_plugin_create_empty(BT_PLUGIN_TYPE_PYTHON);
+       if (!plugin) {
+               goto error;
+       }
+
+       bt_plugin_set_name(plugin, name);
+
+       if (description) {
+               bt_plugin_set_description(plugin, description);
+       }
+
+       if (author) {
+               bt_plugin_set_author(plugin, author);
+       }
+
+       if (license) {
+               bt_plugin_set_license(plugin, license);
+       }
+
+       bt_plugin_set_version(plugin, major, minor, patch, version_extra);
+
+       if (PyList_Check(py_comp_class_addrs)) {
+               size_t i;
+
+               for (i = 0; i < PyList_Size(py_comp_class_addrs); i++) {
+                       struct bt_component_class *comp_class;
+                       PyObject *py_comp_class_addr;
+
+                       py_comp_class_addr =
+                               PyList_GetItem(py_comp_class_addrs, i);
+                       assert(py_comp_class_addr);
+                       if (PyLong_Check(py_comp_class_addr)) {
+                               comp_class = (struct bt_component_class *)
+                                       PyLong_AsUnsignedLongLong(py_comp_class_addr);
+                       } else {
+                               printf_verbose("Component class address #%zu: not an integer\n",
+                                       i);
+                               continue;
+                       }
+
+                       ret = bt_plugin_add_component_class(plugin, comp_class);
+                       if (ret < 0) {
+                               printf_verbose("Cannot add component class #%zu\n",
+                                       i);
+                               continue;
+                       }
+               }
+       }
+
+       bt_plugin_freeze(plugin);
+
+       goto end;
+
+error:
+       print_python_traceback_verbose();
+       pyerr_clear();
+       BT_PUT(plugin);
+
+end:
+       Py_XDECREF(py_name);
+       Py_XDECREF(py_author);
+       Py_XDECREF(py_description);
+       Py_XDECREF(py_license);
+       Py_XDECREF(py_version);
+       Py_XDECREF(py_comp_class_addrs);
+       return plugin;
+}
+
+BT_HIDDEN
+struct bt_plugin **bt_plugin_python_create_all_from_file(const char *path)
+{
+       struct bt_plugin **plugins = NULL;
+       PyObject *py_plugin_info = NULL;
+       gchar *basename = NULL;
+       size_t path_len;
+
+       assert(path);
+
+       if (python_state == PYTHON_STATE_CANNOT_INITIALIZE) {
+               /*
+                * We do not even care about the rest of the function
+                * here because we already know Python cannot be fully
+                * initialized.
+                */
+               goto error;
+       }
+
+       path_len = strlen(path);
+
+       /* File name ends with `.py` */
+       if (strncmp(path + path_len - PYTHON_PLUGIN_FILE_EXT_LEN,
+                       PYTHON_PLUGIN_FILE_EXT,
+                       PYTHON_PLUGIN_FILE_EXT_LEN) != 0) {
+               printf_verbose("Skipping non-Python file: `%s`\n",
+                       path);
+               goto error;
+       }
+
+       /* File name starts with `bt_plugin_` */
+       basename = g_path_get_basename(path);
+       if (!basename) {
+               goto error;
+       }
+
+       if (strncmp(basename, PYTHON_PLUGIN_FILE_PREFIX,
+                       PYTHON_PLUGIN_FILE_PREFIX_LEN) != 0) {
+               printf_verbose("Skipping Python file not starting with `%s`: `%s`\n",
+                       PYTHON_PLUGIN_FILE_PREFIX, path);
+               goto error;
+       }
+
+       /*
+        * Initialize Python now.
+        *
+        * This is not done in the library contructor because the
+        * interpreter is somewhat slow to initialize. If you don't
+        * have any potential Python plugins, you don't need to endure
+        * this waiting time everytime you load the library.
+        */
+       init_python();
+       if (python_state != PYTHON_STATE_FULLY_INITIALIZED) {
+               /*
+                * For some reason we cannot initialize Python,
+                * import the required modules, and get the required
+                * attributes from them.
+                */
+               goto error;
+       }
+
+       /*
+        * Call bt2.py_plugin._try_load_plugin_module() with this path
+        * to get plugin info if the plugin is loadable and complete.
+        * This function returns None when there's an error, but just in
+        * case we also manually clear the last Python error state.
+        */
+       py_plugin_info = PyObject_CallFunction(py_try_load_plugin_module_func,
+               "(s)", path);
+       if (!py_plugin_info || py_plugin_info == Py_None) {
+               printf_verbose("Cannot load Python plugin `%s`:\n", path);
+               print_python_traceback_verbose();
+               PyErr_Clear();
+               goto error;
+       }
+
+       /*
+        * Get bt_plugin from plugin info object.
+        *
+        * calloc(2, ...) because a single Python plugin file always
+        * provides a single Babeltrace plugin (second item is the
+        * sentinel).
+        */
+       plugins = calloc(2, sizeof(*plugins));
+       if (!plugins) {
+               goto error;
+       }
+
+       plugins[0] = bt_plugin_from_python_plugin_info(py_plugin_info);
+       if (!plugins[0]) {
+               goto error;
+       }
+
+       bt_plugin_set_path(plugins[0], path);
+       goto end;
+
+error:
+       if (plugins) {
+               BT_PUT(plugins[0]);
+               free(plugins);
+               plugins = NULL;
+       }
+
+end:
+       Py_XDECREF(py_plugin_info);
+       g_free(basename);
+       return plugins;
+}
diff --git a/lib/plugin/plugin-so.c b/lib/plugin/plugin-so.c
new file mode 100644 (file)
index 0000000..6760aa7
--- /dev/null
@@ -0,0 +1,931 @@
+/*
+ * plugin-so.c
+ *
+ * Babeltrace Plugin (shared object)
+ *
+ * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <babeltrace/compiler.h>
+#include <babeltrace/ref.h>
+#include <babeltrace/plugin/plugin-internal.h>
+#include <babeltrace/plugin/plugin-so-internal.h>
+#include <babeltrace/plugin/plugin-dev.h>
+#include <babeltrace/plugin/plugin-internal.h>
+#include <babeltrace/component/component-class-internal.h>
+#include <string.h>
+#include <stdbool.h>
+#include <glib.h>
+#include <gmodule.h>
+
+#define NATIVE_PLUGIN_SUFFIX           ".so"
+#define NATIVE_PLUGIN_SUFFIX_LEN       sizeof(NATIVE_PLUGIN_SUFFIX)
+#define LIBTOOL_PLUGIN_SUFFIX          ".la"
+#define LIBTOOL_PLUGIN_SUFFIX_LEN      sizeof(LIBTOOL_PLUGIN_SUFFIX)
+
+#define PLUGIN_SUFFIX_LEN      max_t(size_t, sizeof(NATIVE_PLUGIN_SUFFIX), \
+                                       sizeof(LIBTOOL_PLUGIN_SUFFIX))
+
+#define SECTION_BEGIN(_name)           (&(__start_##_name))
+#define SECTION_END(_name)             (&(__stop_##_name))
+#define SECTION_ELEMENT_COUNT(_name) (SECTION_END(_name) - SECTION_BEGIN(_name))
+
+#define DECLARE_SECTION(_type, _name)                          \
+       extern _type __start_##_name __attribute((weak));       \
+       extern _type __stop_##_name __attribute((weak))
+
+DECLARE_SECTION(struct __bt_plugin_descriptor const *, __bt_plugin_descriptors);
+DECLARE_SECTION(struct __bt_plugin_descriptor_attribute const *, __bt_plugin_descriptor_attributes);
+DECLARE_SECTION(struct __bt_plugin_component_class_descriptor const *, __bt_plugin_component_class_descriptors);
+DECLARE_SECTION(struct __bt_plugin_component_class_descriptor_attribute const *, __bt_plugin_component_class_descriptor_attributes);
+
+/*
+ * This hash table, global to the library, maps component class pointers
+ * to shared library handles.
+ *
+ * The keys (component classes) are NOT owned by this hash table, whereas
+ * the values (shared library handles) are owned by this hash table.
+ *
+ * The keys are the component classes created with
+ * bt_plugin_add_component_class(). They keep the shared library handle
+ * object created by their plugin alive so that the plugin's code is
+ * not discarded when it could still be in use by living components
+ * created from those component classes:
+ *
+ *     [component] --ref-> [component class] --through this HT-> [shlib handle]
+ *
+ * This hash table exists for two reasons:
+ *
+ * 1. To allow this application:
+ *
+ *        my_plugins = bt_plugin_create_all_from_file("/path/to/my-plugin.so");
+ *        // instantiate components from a plugin's component classes
+ *        // put plugins and free my_plugins here
+ *        // user code of instantiated components still exists
+ *
+ * 2. To decouple the plugin subsystem from the component subsystem:
+ *    while plugins objects need to know component class objects, the
+ *    opposite is not necessary, thus it makes no sense for a component
+ *    class to keep a reference to the plugin object from which it was
+ *    created.
+ *
+ * An entry is removed from this HT when a component class is destroyed
+ * thanks to a custom destroy listener. When the entry is removed, the
+ * GLib function calls the value destroy notifier of the HT, which is
+ * bt_put(). This decreases the reference count of the mapped shared
+ * library handle. Assuming the original plugin object which contained
+ * some component classes is put first, when the last component class is
+ * removed from this HT, the shared library handle object's reference
+ * count falls to zero and the shared library is finally closed.
+ */
+static
+GHashTable *comp_classes_to_shlib_handles;
+
+__attribute__((constructor)) static
+void init_comp_classes_to_shlib_handles(void) {
+       comp_classes_to_shlib_handles = g_hash_table_new_full(g_direct_hash,
+               g_direct_equal, NULL, bt_put);
+       assert(comp_classes_to_shlib_handles);
+}
+
+__attribute__((destructor)) static
+void fini_comp_classes_to_shlib_handles(void) {
+       if (comp_classes_to_shlib_handles) {
+               g_hash_table_destroy(comp_classes_to_shlib_handles);
+       }
+}
+
+static
+void bt_plugin_so_shared_lib_handle_destroy(struct bt_object *obj)
+{
+       struct bt_plugin_so_shared_lib_handle *shared_lib_handle;
+
+       assert(obj);
+       shared_lib_handle = container_of(obj,
+               struct bt_plugin_so_shared_lib_handle, base);
+
+       if (shared_lib_handle->init_called && shared_lib_handle->exit) {
+               enum bt_plugin_status status = shared_lib_handle->exit();
+
+               if (status < 0) {
+                       const char *path = shared_lib_handle->path ?
+                               shared_lib_handle->path->str : "[built-in]";
+
+                       printf_verbose("Plugin in module `%s` exited with error %d\n",
+                               path, status);
+               }
+       }
+
+       if (shared_lib_handle->module) {
+               if (!g_module_close(shared_lib_handle->module)) {
+                       printf_error("Module close error: %s\n",
+                                       g_module_error());
+               }
+       }
+
+       if (shared_lib_handle->path) {
+               g_string_free(shared_lib_handle->path, TRUE);
+       }
+
+       g_free(shared_lib_handle);
+}
+
+static
+struct bt_plugin_so_shared_lib_handle *bt_plugin_so_shared_lib_handle_create(
+               const char *path)
+{
+       struct bt_plugin_so_shared_lib_handle *shared_lib_handle = NULL;
+
+       shared_lib_handle = g_new0(struct bt_plugin_so_shared_lib_handle, 1);
+       if (!shared_lib_handle) {
+               goto error;
+       }
+
+       bt_object_init(shared_lib_handle, bt_plugin_so_shared_lib_handle_destroy);
+
+       if (!path) {
+               goto end;
+       }
+
+       shared_lib_handle->path = g_string_new(path);
+       if (!shared_lib_handle->path) {
+               goto error;
+       }
+
+       shared_lib_handle->module = g_module_open(path, 0);
+       if (!shared_lib_handle->module) {
+               printf_verbose("Module open error: %s\n", g_module_error());
+               goto error;
+       }
+
+       goto end;
+
+error:
+       BT_PUT(shared_lib_handle);
+
+end:
+       return shared_lib_handle;
+}
+
+BT_HIDDEN
+void bt_plugin_so_destroy_spec_data(struct bt_plugin *plugin)
+{
+       struct bt_plugin_so_spec_data *spec = plugin->spec_data;
+
+       if (!plugin->spec_data) {
+               return;
+       }
+
+       assert(plugin->type == BT_PLUGIN_TYPE_SO);
+       assert(spec);
+       BT_PUT(spec->shared_lib_handle);
+       g_free(plugin->spec_data);
+       plugin->spec_data = NULL;
+}
+
+/*
+ * This function does the following:
+ *
+ * 1. Iterate on the plugin descriptor attributes section and set the
+ *    plugin's attributes depending on the attribute types. This
+ *    includes the name of the plugin, its description, and its
+ *    initialization function, for example.
+ *
+ * 2. Iterate on the component class descriptors section and create one
+ *    "full descriptor" (temporary structure) for each one that is found
+ *    and attached to our plugin descriptor.
+ *
+ * 3. Iterate on the component class descriptor attributes section and
+ *    set the corresponding full descriptor's attributes depending on
+ *    the attribute types. This includes the description of the
+ *    component class, as well as its initialization and destroy
+ *    methods.
+ *
+ * 4. Call the user's plugin initialization function, if any is
+ *    defined.
+ *
+ * 5. For each full component class descriptor, create a component class
+ *    object, set its optional attributes, and add it to the plugin
+ *    object.
+ *
+ * 6. Freeze the plugin object.
+ */
+static
+enum bt_plugin_status bt_plugin_so_init(
+               struct bt_plugin *plugin,
+               const struct __bt_plugin_descriptor *descriptor,
+               struct __bt_plugin_descriptor_attribute const * const *attrs_begin,
+               struct __bt_plugin_descriptor_attribute const * const *attrs_end,
+               struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_begin,
+               struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_end,
+               struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_begin,
+               struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_end)
+{
+       /*
+        * This structure's members point to the plugin's memory
+        * (do NOT free).
+        */
+       struct comp_class_full_descriptor {
+               const struct __bt_plugin_component_class_descriptor *descriptor;
+               const char *description;
+               bt_component_class_init_method init_method;
+               bt_component_class_destroy_method destroy_method;
+               bt_component_class_filter_add_iterator_method filter_add_iterator_method;
+               bt_component_class_sink_add_iterator_method sink_add_iterator_method;
+               struct bt_component_class_iterator_methods iterator_methods;
+       };
+
+       enum bt_plugin_status status = BT_PLUGIN_STATUS_OK;
+       struct __bt_plugin_descriptor_attribute const * const *cur_attr_ptr;
+       struct __bt_plugin_component_class_descriptor const * const *cur_cc_descr_ptr;
+       struct __bt_plugin_component_class_descriptor_attribute const * const *cur_cc_descr_attr_ptr;
+       struct bt_plugin_so_spec_data *spec = plugin->spec_data;
+       GArray *comp_class_full_descriptors;
+       size_t i;
+       int ret;
+
+       comp_class_full_descriptors = g_array_new(FALSE, TRUE,
+               sizeof(struct comp_class_full_descriptor));
+       if (!comp_class_full_descriptors) {
+               status = BT_PLUGIN_STATUS_ERROR;
+               goto end;
+       }
+
+       /* Set mandatory attributes */
+       spec->descriptor = descriptor;
+       bt_plugin_set_name(plugin, descriptor->name);
+
+       /*
+        * Find and set optional attributes attached to this plugin
+        * descriptor.
+        */
+       for (cur_attr_ptr = attrs_begin; cur_attr_ptr != attrs_end; cur_attr_ptr++) {
+               const struct __bt_plugin_descriptor_attribute *cur_attr =
+                       *cur_attr_ptr;
+
+               if (cur_attr->plugin_descriptor != descriptor) {
+                       continue;
+               }
+
+               switch (cur_attr->type) {
+               case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_INIT:
+                       spec->init = cur_attr->value.init;
+                       break;
+               case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_EXIT:
+                       spec->shared_lib_handle->exit = cur_attr->value.exit;
+                       break;
+               case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_AUTHOR:
+                       bt_plugin_set_author(plugin, cur_attr->value.author);
+                       break;
+               case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_LICENSE:
+                       bt_plugin_set_license(plugin, cur_attr->value.license);
+                       break;
+               case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_DESCRIPTION:
+                       bt_plugin_set_description(plugin, cur_attr->value.description);
+                       break;
+               case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_VERSION:
+                       bt_plugin_set_version(plugin,
+                               (unsigned int) cur_attr->value.version.major,
+                               (unsigned int) cur_attr->value.version.minor,
+                               (unsigned int) cur_attr->value.version.patch,
+                               cur_attr->value.version.extra);
+                       break;
+               default:
+                       printf_verbose("WARNING: Unknown attribute \"%s\" (type %d) for plugin %s\n",
+                               cur_attr->type_name, cur_attr->type,
+                               descriptor->name);
+                       break;
+               }
+       }
+
+       /*
+        * Find component class descriptors attached to this plugin
+        * descriptor and initialize corresponding full component class
+        * descriptors in the array.
+        */
+       for (cur_cc_descr_ptr = cc_descriptors_begin; cur_cc_descr_ptr != cc_descriptors_end; cur_cc_descr_ptr++) {
+               const struct __bt_plugin_component_class_descriptor *cur_cc_descr =
+                       *cur_cc_descr_ptr;
+               struct comp_class_full_descriptor full_descriptor = {0};
+
+               if (cur_cc_descr->plugin_descriptor != descriptor) {
+                       continue;
+               }
+
+               full_descriptor.descriptor = cur_cc_descr;
+               g_array_append_val(comp_class_full_descriptors,
+                       full_descriptor);
+       }
+
+       /*
+        * Find component class descriptor attributes attached to this
+        * plugin descriptor and update corresponding full component
+        * class descriptors in the array.
+        */
+       for (cur_cc_descr_attr_ptr = cc_descr_attrs_begin; cur_cc_descr_attr_ptr != cc_descr_attrs_end; cur_cc_descr_attr_ptr++) {
+               const struct __bt_plugin_component_class_descriptor_attribute *cur_cc_descr_attr =
+                       *cur_cc_descr_attr_ptr;
+
+               if (cur_cc_descr_attr->comp_class_descriptor->plugin_descriptor !=
+                               descriptor) {
+                       continue;
+               }
+
+               /* Find the corresponding component class descriptor entry */
+               for (i = 0; i < comp_class_full_descriptors->len; i++) {
+                       struct comp_class_full_descriptor *cc_full_descr =
+                               &g_array_index(comp_class_full_descriptors,
+                                       struct comp_class_full_descriptor, i);
+
+                       if (cur_cc_descr_attr->comp_class_descriptor ==
+                                       cc_full_descr->descriptor) {
+                               switch (cur_cc_descr_attr->type) {
+                               case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_DESCRIPTION:
+                                       cc_full_descr->description =
+                                               cur_cc_descr_attr->value.description;
+                                       break;
+                               case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_INIT_METHOD:
+                                       cc_full_descr->init_method =
+                                               cur_cc_descr_attr->value.init_method;
+                                       break;
+                               case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_DESTROY_METHOD:
+                                       cc_full_descr->destroy_method =
+                                               cur_cc_descr_attr->value.destroy_method;
+                                       break;
+                               case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_FILTER_ADD_ITERATOR_METHOD:
+                                       cc_full_descr->filter_add_iterator_method =
+                                               cur_cc_descr_attr->value.filter_add_iterator_method;
+                                       break;
+                               case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_SINK_ADD_ITERATOR_METHOD:
+                                       cc_full_descr->sink_add_iterator_method =
+                                               cur_cc_descr_attr->value.sink_add_iterator_method;
+                                       break;
+                               case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_NOTIF_ITER_INIT_METHOD:
+                                       cc_full_descr->iterator_methods.init =
+                                               cur_cc_descr_attr->value.notif_iter_init_method;
+                                       break;
+                               case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_NOTIF_ITER_DESTROY_METHOD:
+                                       cc_full_descr->iterator_methods.destroy =
+                                               cur_cc_descr_attr->value.notif_iter_destroy_method;
+                                       break;
+                               case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_NOTIF_ITER_SEEK_TIME_METHOD:
+                                       cc_full_descr->iterator_methods.seek_time =
+                                               cur_cc_descr_attr->value.notif_iter_seek_time_method;
+                                       break;
+                               default:
+                                       printf_verbose("WARNING: Unknown attribute \"%s\" (type %d) for component class %s (type %d) in plugin %s\n",
+                                               cur_cc_descr_attr->type_name,
+                                               cur_cc_descr_attr->type,
+                                               cur_cc_descr_attr->comp_class_descriptor->name,
+                                               cur_cc_descr_attr->comp_class_descriptor->type,
+                                               descriptor->name);
+                                       break;
+                               }
+                       }
+               }
+       }
+
+       /* Initialize plugin */
+       if (spec->init) {
+               status = spec->init(plugin);
+               if (status < 0) {
+                       printf_verbose("Plugin `%s` initialization error: %d\n",
+                               bt_plugin_get_name(plugin), status);
+                       goto end;
+               }
+       }
+
+       spec->shared_lib_handle->init_called = true;
+
+       /* Add described component classes to plugin */
+       for (i = 0; i < comp_class_full_descriptors->len; i++) {
+               struct comp_class_full_descriptor *cc_full_descr =
+                       &g_array_index(comp_class_full_descriptors,
+                               struct comp_class_full_descriptor, i);
+               struct bt_component_class *comp_class;
+
+               switch (cc_full_descr->descriptor->type) {
+               case BT_COMPONENT_CLASS_TYPE_SOURCE:
+                       comp_class = bt_component_class_source_create(
+                               cc_full_descr->descriptor->name,
+                               cc_full_descr->descriptor->methods.source.notif_iter_get,
+                               cc_full_descr->descriptor->methods.source.notif_iter_next);
+                       break;
+               case BT_COMPONENT_CLASS_TYPE_FILTER:
+                       comp_class = bt_component_class_filter_create(
+                               cc_full_descr->descriptor->name,
+                               cc_full_descr->descriptor->methods.source.notif_iter_get,
+                               cc_full_descr->descriptor->methods.source.notif_iter_next);
+                       break;
+               case BT_COMPONENT_CLASS_TYPE_SINK:
+                       comp_class = bt_component_class_sink_create(
+                               cc_full_descr->descriptor->name,
+                               cc_full_descr->descriptor->methods.sink.consume);
+                       break;
+               default:
+                       printf_verbose("WARNING: Unknown component class type %d for component class %s in plugin %s\n",
+                               cc_full_descr->descriptor->type,
+                               cc_full_descr->descriptor->name,
+                               descriptor->name);
+                       continue;
+               }
+
+               if (!comp_class) {
+                       status = BT_PLUGIN_STATUS_ERROR;
+                       goto end;
+               }
+
+               if (cc_full_descr->description) {
+                       ret = bt_component_class_set_description(comp_class,
+                               cc_full_descr->description);
+                       if (ret) {
+                               status = BT_PLUGIN_STATUS_ERROR;
+                               BT_PUT(comp_class);
+                               goto end;
+                       }
+               }
+
+               if (cc_full_descr->init_method) {
+                       ret = bt_component_class_set_init_method(comp_class,
+                               cc_full_descr->init_method);
+                       if (ret) {
+                               status = BT_PLUGIN_STATUS_ERROR;
+                               BT_PUT(comp_class);
+                               goto end;
+                       }
+               }
+
+               if (cc_full_descr->destroy_method) {
+                       ret = bt_component_class_set_destroy_method(comp_class,
+                               cc_full_descr->destroy_method);
+                       if (ret) {
+                               status = BT_PLUGIN_STATUS_ERROR;
+                               BT_PUT(comp_class);
+                               goto end;
+                       }
+               }
+
+               switch (cc_full_descr->descriptor->type) {
+               case BT_COMPONENT_CLASS_TYPE_SOURCE:
+                       if (cc_full_descr->iterator_methods.init) {
+                               ret = bt_component_class_source_set_notification_iterator_init_method(
+                                       comp_class,
+                                       cc_full_descr->iterator_methods.init);
+                               if (ret) {
+                                       status = BT_PLUGIN_STATUS_ERROR;
+                                       BT_PUT(comp_class);
+                                       goto end;
+                               }
+                       }
+
+                       if (cc_full_descr->iterator_methods.destroy) {
+                               ret = bt_component_class_source_set_notification_iterator_destroy_method(
+                                       comp_class,
+                                       cc_full_descr->iterator_methods.destroy);
+                               if (ret) {
+                                       status = BT_PLUGIN_STATUS_ERROR;
+                                       BT_PUT(comp_class);
+                                       goto end;
+                               }
+                       }
+
+                       if (cc_full_descr->iterator_methods.seek_time) {
+                               ret = bt_component_class_source_set_notification_iterator_seek_time_method(
+                                       comp_class,
+                                       cc_full_descr->iterator_methods.seek_time);
+                               if (ret) {
+                                       status = BT_PLUGIN_STATUS_ERROR;
+                                       BT_PUT(comp_class);
+                                       goto end;
+                               }
+                       }
+                       break;
+               case BT_COMPONENT_CLASS_TYPE_FILTER:
+                       if (cc_full_descr->filter_add_iterator_method) {
+                               ret = bt_component_class_filter_set_add_iterator_method(
+                                       comp_class,
+                                       cc_full_descr->filter_add_iterator_method);
+                               if (ret) {
+                                       status = BT_PLUGIN_STATUS_ERROR;
+                                       BT_PUT(comp_class);
+                                       goto end;
+                               }
+                       }
+
+                       if (cc_full_descr->iterator_methods.init) {
+                               ret = bt_component_class_filter_set_notification_iterator_init_method(
+                                       comp_class,
+                                       cc_full_descr->iterator_methods.init);
+                               if (ret) {
+                                       status = BT_PLUGIN_STATUS_ERROR;
+                                       BT_PUT(comp_class);
+                                       goto end;
+                               }
+                       }
+
+                       if (cc_full_descr->iterator_methods.destroy) {
+                               ret = bt_component_class_filter_set_notification_iterator_destroy_method(
+                                       comp_class,
+                                       cc_full_descr->iterator_methods.destroy);
+                               if (ret) {
+                                       status = BT_PLUGIN_STATUS_ERROR;
+                                       BT_PUT(comp_class);
+                                       goto end;
+                               }
+                       }
+
+                       if (cc_full_descr->iterator_methods.seek_time) {
+                               ret = bt_component_class_filter_set_notification_iterator_seek_time_method(
+                                       comp_class,
+                                       cc_full_descr->iterator_methods.seek_time);
+                               if (ret) {
+                                       status = BT_PLUGIN_STATUS_ERROR;
+                                       BT_PUT(comp_class);
+                                       goto end;
+                               }
+                       }
+                       break;
+               case BT_COMPONENT_CLASS_TYPE_SINK:
+                       if (cc_full_descr->sink_add_iterator_method) {
+                               ret = bt_component_class_sink_set_add_iterator_method(
+                                       comp_class,
+                                       cc_full_descr->sink_add_iterator_method);
+                               if (ret) {
+                                       status = BT_PLUGIN_STATUS_ERROR;
+                                       BT_PUT(comp_class);
+                                       goto end;
+                               }
+                       }
+                       break;
+               default:
+                       assert(false);
+                       break;
+               }
+
+               /*
+                * Add component class to the plugin object.
+                *
+                * This will call back
+                * bt_plugin_so_on_add_component_class() so that we can
+                * add a mapping in comp_classes_to_shlib_handles when
+                * we know the component class is successfully added.
+                */
+               status = bt_plugin_add_component_class(plugin,
+                       comp_class);
+               BT_PUT(comp_class);
+               if (status < 0) {
+                       printf_verbose("Cannot add component class %s (type %d) to plugin `%s`: status = %d\n",
+                               cc_full_descr->descriptor->name,
+                               cc_full_descr->descriptor->type,
+                               bt_plugin_get_name(plugin), status);
+                       goto end;
+               }
+       }
+
+       /*
+        * All the plugin's component classes should be added at this
+        * point. We freeze the plugin so that it's not possible to add
+        * component classes to this plugin object after this stage
+        * (plugin object becomes immutable).
+        */
+       bt_plugin_freeze(plugin);
+
+end:
+       g_array_free(comp_class_full_descriptors, TRUE);
+       return status;
+}
+
+static
+struct bt_plugin *bt_plugin_so_create_empty(
+               struct bt_plugin_so_shared_lib_handle *shared_lib_handle)
+{
+       struct bt_plugin *plugin;
+       struct bt_plugin_so_spec_data *spec;
+
+       plugin = bt_plugin_create_empty(BT_PLUGIN_TYPE_SO);
+       if (!plugin) {
+               goto error;
+       }
+
+       plugin->spec_data = g_new0(struct bt_plugin_so_spec_data, 1);
+       if (!plugin->spec_data) {
+               goto error;
+       }
+
+       spec = plugin->spec_data;
+       spec->shared_lib_handle = bt_get(shared_lib_handle);
+       goto end;
+
+error:
+       BT_PUT(plugin);
+
+end:
+       return plugin;
+}
+
+static
+struct bt_plugin **bt_plugin_so_create_all_from_sections(
+               struct bt_plugin_so_shared_lib_handle *shared_lib_handle,
+               struct __bt_plugin_descriptor const * const *descriptors_begin,
+               struct __bt_plugin_descriptor const * const *descriptors_end,
+               struct __bt_plugin_descriptor_attribute const * const *attrs_begin,
+               struct __bt_plugin_descriptor_attribute const * const *attrs_end,
+               struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_begin,
+               struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_end,
+               struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_begin,
+               struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_end)
+{
+       size_t descriptor_count;
+       size_t attrs_count;
+       size_t cc_descriptors_count;
+       size_t cc_descr_attrs_count;
+       size_t i;
+       struct bt_plugin **plugins = NULL;
+
+       descriptor_count = descriptors_end - descriptors_begin;
+       attrs_count = attrs_end - attrs_begin;
+       cc_descriptors_count = cc_descriptors_end - cc_descriptors_begin;
+       cc_descr_attrs_count = cc_descr_attrs_end - cc_descr_attrs_begin;
+       printf_verbose("Section: Plugin descriptors: [%p - %p], (%zu elements)\n",
+               descriptors_begin, descriptors_end, descriptor_count);
+       printf_verbose("Section: Plugin descriptor attributes: [%p - %p], (%zu elements)\n",
+               attrs_begin, attrs_end, attrs_count);
+       printf_verbose("Section: Plugin component class descriptors: [%p - %p], (%zu elements)\n",
+               cc_descriptors_begin, cc_descriptors_end, cc_descriptors_count);
+       printf_verbose("Section: Plugin component class descriptor attributes: [%p - %p], (%zu elements)\n",
+               cc_descr_attrs_begin, cc_descr_attrs_end, cc_descr_attrs_count);
+       plugins = calloc(descriptor_count + 1, sizeof(*plugins));
+       if (!plugins) {
+               goto error;
+       }
+
+       for (i = 0; i < descriptor_count; i++) {
+               enum bt_plugin_status status;
+               const struct __bt_plugin_descriptor *descriptor =
+                       descriptors_begin[i];
+               struct bt_plugin *plugin;
+
+               printf_verbose("Loading plugin %s (ABI %d.%d)\n", descriptor->name,
+                       descriptor->major, descriptor->minor);
+
+               if (descriptor->major > __BT_PLUGIN_VERSION_MAJOR) {
+                       printf_error("Unknown plugin's major version: %d\n",
+                               descriptor->major);
+                       goto error;
+               }
+
+               plugin = bt_plugin_so_create_empty(shared_lib_handle);
+               if (!plugin) {
+                       printf_error("Cannot allocate plugin object for plugin %s\n",
+                               descriptor->name);
+                       goto error;
+               }
+
+               if (shared_lib_handle && shared_lib_handle->path) {
+                       bt_plugin_set_path(plugin, shared_lib_handle->path->str);
+               }
+
+               status = bt_plugin_so_init(plugin, descriptor, attrs_begin,
+                       attrs_end, cc_descriptors_begin, cc_descriptors_end,
+                       cc_descr_attrs_begin, cc_descr_attrs_end);
+               if (status < 0) {
+                       printf_error("Cannot initialize plugin object %s\n",
+                               descriptor->name);
+                       BT_PUT(plugin);
+                       goto error;
+               }
+
+               /* Transfer ownership to the array */
+               plugins[i] = plugin;
+       }
+
+       goto end;
+
+error:
+       g_free(plugins);
+       plugins = NULL;
+
+end:
+       return plugins;
+}
+
+BT_HIDDEN
+struct bt_plugin **bt_plugin_so_create_all_from_static(void)
+{
+       struct bt_plugin **plugins = NULL;
+       struct bt_plugin_so_shared_lib_handle *shared_lib_handle =
+               bt_plugin_so_shared_lib_handle_create(NULL);
+
+       if (!shared_lib_handle) {
+               goto end;
+       }
+
+       plugins = bt_plugin_so_create_all_from_sections(shared_lib_handle,
+               SECTION_BEGIN(__bt_plugin_descriptors),
+               SECTION_END(__bt_plugin_descriptors),
+               SECTION_BEGIN(__bt_plugin_descriptor_attributes),
+               SECTION_END(__bt_plugin_descriptor_attributes),
+               SECTION_BEGIN(__bt_plugin_component_class_descriptors),
+               SECTION_END(__bt_plugin_component_class_descriptors),
+               SECTION_BEGIN(__bt_plugin_component_class_descriptor_attributes),
+               SECTION_END(__bt_plugin_component_class_descriptor_attributes));
+
+end:
+       BT_PUT(shared_lib_handle);
+
+       return plugins;
+}
+
+BT_HIDDEN
+struct bt_plugin **bt_plugin_so_create_all_from_file(const char *path)
+{
+       size_t path_len;
+       struct bt_plugin **plugins = NULL;
+       struct __bt_plugin_descriptor const * const *descriptors_begin = NULL;
+       struct __bt_plugin_descriptor const * const *descriptors_end = NULL;
+       struct __bt_plugin_descriptor_attribute const * const *attrs_begin = NULL;
+       struct __bt_plugin_descriptor_attribute const * const *attrs_end = NULL;
+       struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_begin = NULL;
+       struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_end = NULL;
+       struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_begin = NULL;
+       struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_end = NULL;
+       bool is_libtool_wrapper = false, is_shared_object = false;
+       struct bt_plugin_so_shared_lib_handle *shared_lib_handle = NULL;
+
+       if (!path) {
+               goto end;
+       }
+
+       path_len = strlen(path);
+       if (path_len <= PLUGIN_SUFFIX_LEN) {
+               goto end;
+       }
+
+       path_len++;
+       /*
+        * Check if the file ends with a known plugin file type suffix (i.e. .so
+        * or .la on Linux).
+        */
+       is_libtool_wrapper = !strncmp(LIBTOOL_PLUGIN_SUFFIX,
+               path + path_len - LIBTOOL_PLUGIN_SUFFIX_LEN,
+               LIBTOOL_PLUGIN_SUFFIX_LEN);
+       is_shared_object = !strncmp(NATIVE_PLUGIN_SUFFIX,
+               path + path_len - NATIVE_PLUGIN_SUFFIX_LEN,
+               NATIVE_PLUGIN_SUFFIX_LEN);
+       if (!is_shared_object && !is_libtool_wrapper) {
+               /* Name indicates that this is not a plugin file. */
+               goto end;
+       }
+
+       shared_lib_handle = bt_plugin_so_shared_lib_handle_create(path);
+       if (!shared_lib_handle) {
+               goto end;
+       }
+
+       if (!g_module_symbol(shared_lib_handle->module, "__start___bt_plugin_descriptors",
+                       (gpointer *) &descriptors_begin)) {
+               printf_verbose("Unable to resolve plugin symbol %s from %s\n",
+                       "__start___bt_plugin_descriptors",
+                       g_module_name(shared_lib_handle->module));
+               goto end;
+       }
+
+       if (!g_module_symbol(shared_lib_handle->module, "__stop___bt_plugin_descriptors",
+                       (gpointer *) &descriptors_end)) {
+               printf_verbose("Unable to resolve plugin symbol %s from %s\n",
+                       "__stop___bt_plugin_descriptors",
+                       g_module_name(shared_lib_handle->module));
+               goto end;
+       }
+
+       if (!g_module_symbol(shared_lib_handle->module, "__start___bt_plugin_descriptor_attributes",
+                       (gpointer *) &attrs_begin)) {
+               printf_verbose("Unable to resolve plugin symbol %s from %s\n",
+                       "__start___bt_plugin_descriptor_attributes",
+                       g_module_name(shared_lib_handle->module));
+       }
+
+       if (!g_module_symbol(shared_lib_handle->module, "__stop___bt_plugin_descriptor_attributes",
+                       (gpointer *) &attrs_end)) {
+               printf_verbose("Unable to resolve plugin symbol %s from %s\n",
+                       "__stop___bt_plugin_descriptor_attributes",
+                       g_module_name(shared_lib_handle->module));
+       }
+
+       if ((!!attrs_begin - !!attrs_end) != 0) {
+               printf_verbose("Found __start___bt_plugin_descriptor_attributes or __stop___bt_plugin_descriptor_attributes symbol, but not both in %s\n",
+                       g_module_name(shared_lib_handle->module));
+               goto end;
+       }
+
+       if (!g_module_symbol(shared_lib_handle->module, "__start___bt_plugin_component_class_descriptors",
+                       (gpointer *) &cc_descriptors_begin)) {
+               printf_verbose("Unable to resolve plugin symbol %s from %s\n",
+                       "__start___bt_plugin_component_class_descriptors",
+                       g_module_name(shared_lib_handle->module));
+       }
+
+       if (!g_module_symbol(shared_lib_handle->module, "__stop___bt_plugin_component_class_descriptors",
+                       (gpointer *) &cc_descriptors_end)) {
+               printf_verbose("Unable to resolve plugin symbol %s from %s\n",
+                       "__stop___bt_plugin_component_class_descriptors",
+                       g_module_name(shared_lib_handle->module));
+       }
+
+       if ((!!cc_descriptors_begin - !!cc_descriptors_end) != 0) {
+               printf_verbose("Found __start___bt_plugin_component_class_descriptors or __stop___bt_plugin_component_class_descriptors symbol, but not both in %s\n",
+                       g_module_name(shared_lib_handle->module));
+               goto end;
+       }
+
+       if (!g_module_symbol(shared_lib_handle->module, "__start___bt_plugin_component_class_descriptor_attributes",
+                       (gpointer *) &cc_descr_attrs_begin)) {
+               printf_verbose("Unable to resolve plugin symbol %s from %s\n",
+                       "__start___bt_plugin_component_class_descriptor_attributes",
+                       g_module_name(shared_lib_handle->module));
+       }
+
+       if (!g_module_symbol(shared_lib_handle->module, "__stop___bt_plugin_component_class_descriptor_attributes",
+                       (gpointer *) &cc_descr_attrs_end)) {
+               printf_verbose("Unable to resolve plugin symbol %s from %s\n",
+                       "__stop___bt_plugin_component_class_descriptor_attributes",
+                       g_module_name(shared_lib_handle->module));
+       }
+
+       if ((!!cc_descr_attrs_begin - !!cc_descr_attrs_end) != 0) {
+               printf_verbose("Found __start___bt_plugin_component_class_descriptor_attributes or __stop___bt_plugin_component_class_descriptor_attributes symbol, but not both in %s\n",
+                       g_module_name(shared_lib_handle->module));
+               goto end;
+       }
+
+       /* Initialize plugin */
+       plugins = bt_plugin_so_create_all_from_sections(shared_lib_handle,
+               descriptors_begin, descriptors_end, attrs_begin, attrs_end,
+               cc_descriptors_begin, cc_descriptors_end,
+               cc_descr_attrs_begin, cc_descr_attrs_end);
+
+end:
+       BT_PUT(shared_lib_handle);
+       return plugins;
+}
+
+static
+void plugin_comp_class_destroy_listener(struct bt_component_class *comp_class,
+               void *data)
+{
+       gboolean exists = g_hash_table_remove(comp_classes_to_shlib_handles,
+               comp_class);
+       assert(exists);
+}
+
+BT_HIDDEN
+int bt_plugin_so_on_add_component_class(struct bt_plugin *plugin,
+               struct bt_component_class *comp_class)
+{
+       int ret;
+       struct bt_plugin_so_spec_data *spec = plugin->spec_data;
+
+       assert(plugin->spec_data);
+       assert(plugin->type == BT_PLUGIN_TYPE_SO);
+
+       /* Map component class pointer to shared lib handle in global HT */
+       g_hash_table_insert(comp_classes_to_shlib_handles, comp_class,
+               bt_get(spec->shared_lib_handle));
+
+       /* Add our custom destroy listener */
+       ret = bt_component_class_add_destroy_listener(comp_class,
+               plugin_comp_class_destroy_listener, NULL);
+       if (ret) {
+               goto error;
+       }
+       goto end;
+
+error:
+       /* Remove entry from global hash table (if exists) */
+       g_hash_table_remove(comp_classes_to_shlib_handles,
+               comp_class);
+
+end:
+       return ret;
+}
index 3395da8d599f596e33e6cc79dfdc1616bf18aaf2..ce3a866f18935d0e4f803980a06dbdc249adf020 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * plugin.c
  *
- * Babeltrace Plugin
+ * Babeltrace Plugin (generic)
  *
  * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
  * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
 
 #include <babeltrace/compiler.h>
 #include <babeltrace/ref.h>
-#include <babeltrace/plugin/plugin-dev.h>
 #include <babeltrace/plugin/plugin-internal.h>
-#include <babeltrace/component/component-class-internal.h>
-#include <string.h>
-#include <stdbool.h>
+#include <babeltrace/plugin/plugin-so-internal.h>
 #include <glib.h>
-#include <gmodule.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <sys/stat.h>
 #include <dirent.h>
 
-#define NATIVE_PLUGIN_SUFFIX           ".so"
-#define NATIVE_PLUGIN_SUFFIX_LEN       sizeof(NATIVE_PLUGIN_SUFFIX)
-#define LIBTOOL_PLUGIN_SUFFIX          ".la"
-#define LIBTOOL_PLUGIN_SUFFIX_LEN      sizeof(LIBTOOL_PLUGIN_SUFFIX)
+#ifdef WITH_PYTHON_PLUGINS
+# include <babeltrace/plugin/plugin-python-enabled-internal.h>
+#else
+# include <babeltrace/plugin/plugin-python-disabled-internal.h>
+#endif
 
-#define PLUGIN_SUFFIX_LEN      max_t(size_t, sizeof(NATIVE_PLUGIN_SUFFIX), \
-                                       sizeof(LIBTOOL_PLUGIN_SUFFIX))
-
-#define SECTION_BEGIN(_name)           (&(__start_##_name))
-#define SECTION_END(_name)             (&(__stop_##_name))
-#define SECTION_ELEMENT_COUNT(_name) (SECTION_END(_name) - SECTION_BEGIN(_name))
-
-#define DECLARE_SECTION(_type, _name)                          \
-       extern _type __start_##_name __attribute((weak));       \
-       extern _type __stop_##_name __attribute((weak))
-
-DECLARE_SECTION(struct __bt_plugin_descriptor const *, __bt_plugin_descriptors);
-DECLARE_SECTION(struct __bt_plugin_descriptor_attribute const *, __bt_plugin_descriptor_attributes);
-DECLARE_SECTION(struct __bt_plugin_component_class_descriptor const *, __bt_plugin_component_class_descriptors);
-DECLARE_SECTION(struct __bt_plugin_component_class_descriptor_attribute const *, __bt_plugin_component_class_descriptor_attributes);
-
-/*
- * This hash table, global to the library, maps component class pointers
- * to shared library handles.
- *
- * The keys (component classes) are NOT owned by this hash table, whereas
- * the values (shared library handles) are owned by this hash table.
- *
- * The keys are the component classes created with
- * bt_plugin_add_component_class(). They keep the shared library handle
- * object created by their plugin alive so that the plugin's code is
- * not discarded when it could still be in use by living components
- * created from those component classes:
- *
- *     [component] --ref-> [component class] --through this HT-> [shlib handle]
- *
- * This hash table exists for two reasons:
- *
- * 1. To allow this application:
- *
- *        my_plugins = bt_plugin_create_all_from_file("/path/to/my-plugin.so");
- *        // instantiate components from a plugin's component classes
- *        // put plugins and free my_plugins here
- *        // user code of instantiated components still exists
- *
- * 2. To decouple the plugin subsystem from the component subsystem:
- *    while plugins objects need to know component class objects, the
- *    opposite is not necessary, thus it makes no sense for a component
- *    class to keep a reference to the plugin object from which it was
- *    created.
- *
- * An entry is removed from this HT when a component class is destroyed
- * thanks to a custom destroy listener. When the entry is removed, the
- * GLib function calls the value destroy notifier of the HT, which is
- * bt_put(). This decreases the reference count of the mapped shared
- * library handle. Assuming the original plugin object which contained
- * some component classes is put first, when the last component class is
- * removed from this HT, the shared library handle object's reference
- * count falls to zero and the shared library is finally closed.
- */
 static
-GHashTable *comp_classes_to_shlib_handles;
-
-__attribute__((constructor)) static
-void init_comp_classes_to_shlib_handles(void) {
-       comp_classes_to_shlib_handles = g_hash_table_new_full(g_direct_hash,
-               g_direct_equal, NULL, bt_put);
-       assert(comp_classes_to_shlib_handles);
-}
-
-__attribute__((destructor)) static
-void fini_comp_classes_to_shlib_handles(void) {
-       if (comp_classes_to_shlib_handles) {
-               g_hash_table_destroy(comp_classes_to_shlib_handles);
-       }
-}
-
-static
-void bt_plugin_shared_lib_handle_destroy(struct bt_object *obj)
+void bt_plugin_destroy(struct bt_object *obj)
 {
-       struct bt_plugin_shared_lib_handle *shared_lib_handle;
+       struct bt_plugin *plugin;
 
        assert(obj);
-       shared_lib_handle = container_of(obj,
-               struct bt_plugin_shared_lib_handle, base);
-
-       if (shared_lib_handle->init_called && shared_lib_handle->exit) {
-               enum bt_plugin_status status = shared_lib_handle->exit();
-
-               if (status < 0) {
-                       const char *path = shared_lib_handle->path ?
-                               shared_lib_handle->path->str : "[built-in]";
+       plugin = container_of(obj, struct bt_plugin, base);
 
-                       printf_verbose("Plugin in module `%s` exited with error %d\n",
-                               path, status);
-               }
+       if (plugin->type == BT_PLUGIN_TYPE_SO) {
+               bt_plugin_so_destroy_spec_data(plugin);
+       } else if (plugin->type == BT_PLUGIN_TYPE_PYTHON) {
+               bt_plugin_python_destroy_spec_data(plugin);
+       } else {
+               assert(false);
        }
 
-       if (shared_lib_handle->module) {
-               if (!g_module_close(shared_lib_handle->module)) {
-                       printf_error("Module close error: %s\n",
-                                       g_module_error());
-               }
+       if (plugin->comp_classes) {
+               g_ptr_array_free(plugin->comp_classes, TRUE);
        }
 
-       if (shared_lib_handle->path) {
-               g_string_free(shared_lib_handle->path, TRUE);
+       if (plugin->info.name) {
+               g_string_free(plugin->info.name, TRUE);
        }
 
-       g_free(shared_lib_handle);
-}
-
-static
-struct bt_plugin_shared_lib_handle *bt_plugin_shared_lib_handle_create(
-               const char *path)
-{
-       struct bt_plugin_shared_lib_handle *shared_lib_handle = NULL;
-
-       shared_lib_handle = g_new0(struct bt_plugin_shared_lib_handle, 1);
-       if (!shared_lib_handle) {
-               goto error;
+       if (plugin->info.path) {
+               g_string_free(plugin->info.path, TRUE);
        }
 
-       bt_object_init(shared_lib_handle, bt_plugin_shared_lib_handle_destroy);
-
-       if (!path) {
-               goto end;
+       if (plugin->info.description) {
+               g_string_free(plugin->info.description, TRUE);
        }
 
-       shared_lib_handle->path = g_string_new(path);
-       if (!shared_lib_handle->path) {
-               goto error;
+       if (plugin->info.author) {
+               g_string_free(plugin->info.author, TRUE);
        }
 
-       shared_lib_handle->module = g_module_open(path, 0);
-       if (!shared_lib_handle->module) {
-               printf_verbose("Module open error: %s\n", g_module_error());
-               goto error;
+       if (plugin->info.license) {
+               g_string_free(plugin->info.license, TRUE);
        }
 
-       goto end;
-
-error:
-       BT_PUT(shared_lib_handle);
-
-end:
-       return shared_lib_handle;
-}
-
-static
-void bt_plugin_destroy(struct bt_object *obj)
-{
-       struct bt_plugin *plugin;
-
-       assert(obj);
-       plugin = container_of(obj, struct bt_plugin, base);
-
-       BT_PUT(plugin->shared_lib_handle);
-
-       if (plugin->comp_classes) {
-               g_ptr_array_free(plugin->comp_classes, TRUE);
+       if (plugin->info.version.extra) {
+               g_string_free(plugin->info.version.extra, TRUE);
        }
 
        g_free(plugin);
 }
 
-static
-struct bt_plugin *bt_plugin_create_empty(
-               struct bt_plugin_shared_lib_handle *shared_lib_handle)
+BT_HIDDEN
+struct bt_plugin *bt_plugin_create_empty(enum bt_plugin_type type)
 {
        struct bt_plugin *plugin = NULL;
 
@@ -219,7 +101,7 @@ struct bt_plugin *bt_plugin_create_empty(
        }
 
        bt_object_init(plugin, bt_plugin_destroy);
-       plugin->shared_lib_handle = bt_get(shared_lib_handle);
+       plugin->type = type;
 
        /* Create empty array of component classes */
        plugin->comp_classes =
@@ -228,652 +110,73 @@ struct bt_plugin *bt_plugin_create_empty(
                goto error;
        }
 
-       goto end;
-
-error:
-       BT_PUT(plugin);
-
-end:
-       return plugin;
-}
-
-/*
- * This function does the following:
- *
- * 1. Iterate on the plugin descriptor attributes section and set the
- *    plugin's attributes depending on the attribute types. This
- *    includes the name of the plugin, its description, and its
- *    initialization function, for example.
- *
- * 2. Iterate on the component class descriptors section and create one
- *    "full descriptor" (temporary structure) for each one that is found
- *    and attached to our plugin descriptor.
- *
- * 3. Iterate on the component class descriptor attributes section and
- *    set the corresponding full descriptor's attributes depending on
- *    the attribute types. This includes the description of the
- *    component class, as well as its initialization and destroy
- *    methods.
- *
- * 4. Call the user's plugin initialization function, if any is
- *    defined.
- *
- * 5. For each full component class descriptor, create a component class
- *    object, set its optional attributes, and add it to the plugin
- *    object.
- *
- * 6. Freeze the plugin object.
- */
-static
-enum bt_plugin_status bt_plugin_init(
-               struct bt_plugin *plugin,
-               const struct __bt_plugin_descriptor *descriptor,
-               struct __bt_plugin_descriptor_attribute const * const *attrs_begin,
-               struct __bt_plugin_descriptor_attribute const * const *attrs_end,
-               struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_begin,
-               struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_end,
-               struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_begin,
-               struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_end)
-{
-       /*
-        * This structure's members point to the plugin's memory
-        * (do NOT free).
-        */
-       struct comp_class_full_descriptor {
-               const struct __bt_plugin_component_class_descriptor *descriptor;
-               const char *description;
-               bt_component_class_init_method init_method;
-               bt_component_class_destroy_method destroy_method;
-               bt_component_class_filter_add_iterator_method filter_add_iterator_method;
-               bt_component_class_sink_add_iterator_method sink_add_iterator_method;
-               struct bt_component_class_iterator_methods iterator_methods;
-       };
-
-       enum bt_plugin_status status = BT_PLUGIN_STATUS_OK;
-       struct __bt_plugin_descriptor_attribute const * const *cur_attr_ptr;
-       struct __bt_plugin_component_class_descriptor const * const *cur_cc_descr_ptr;
-       struct __bt_plugin_component_class_descriptor_attribute const * const *cur_cc_descr_attr_ptr;
-       GArray *comp_class_full_descriptors;
-       size_t i;
-       int ret;
-
-       comp_class_full_descriptors = g_array_new(FALSE, TRUE,
-               sizeof(struct comp_class_full_descriptor));
-       if (!comp_class_full_descriptors) {
-               status = BT_PLUGIN_STATUS_ERROR;
-               goto end;
-       }
-
-       /* Set mandatory attributes */
-       plugin->descriptor = descriptor;
-       plugin->name = descriptor->name;
-
-       /*
-        * Find and set optional attributes attached to this plugin
-        * descriptor.
-        */
-       for (cur_attr_ptr = attrs_begin; cur_attr_ptr != attrs_end; cur_attr_ptr++) {
-               const struct __bt_plugin_descriptor_attribute *cur_attr =
-                       *cur_attr_ptr;
-
-               if (cur_attr->plugin_descriptor != descriptor) {
-                       continue;
-               }
-
-               switch (cur_attr->type) {
-               case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_INIT:
-                       plugin->init = cur_attr->value.init;
-                       break;
-               case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_EXIT:
-                       plugin->shared_lib_handle->exit = cur_attr->value.exit;
-                       break;
-               case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_AUTHOR:
-                       plugin->author = cur_attr->value.author;
-                       break;
-               case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_LICENSE:
-                       plugin->license = cur_attr->value.license;
-                       break;
-               case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_DESCRIPTION:
-                       plugin->description = cur_attr->value.description;
-                       break;
-               case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_VERSION:
-                       plugin->version = &cur_attr->value.version;
-                       break;
-               default:
-                       printf_verbose("WARNING: Unknown attribute \"%s\" (type %d) for plugin %s\n",
-                               cur_attr->type_name, cur_attr->type,
-                               descriptor->name);
-                       break;
-               }
-       }
-
-       /*
-        * Find component class descriptors attached to this plugin
-        * descriptor and initialize corresponding full component class
-        * descriptors in the array.
-        */
-       for (cur_cc_descr_ptr = cc_descriptors_begin; cur_cc_descr_ptr != cc_descriptors_end; cur_cc_descr_ptr++) {
-               const struct __bt_plugin_component_class_descriptor *cur_cc_descr =
-                       *cur_cc_descr_ptr;
-               struct comp_class_full_descriptor full_descriptor = {0};
-
-               if (cur_cc_descr->plugin_descriptor != descriptor) {
-                       continue;
-               }
-
-               full_descriptor.descriptor = cur_cc_descr;
-               g_array_append_val(comp_class_full_descriptors,
-                       full_descriptor);
+       /* Create empty info */
+       plugin->info.name = g_string_new(NULL);
+       if (!plugin->info.name) {
+               goto error;
        }
 
-       /*
-        * Find component class descriptor attributes attached to this
-        * plugin descriptor and update corresponding full component
-        * class descriptors in the array.
-        */
-       for (cur_cc_descr_attr_ptr = cc_descr_attrs_begin; cur_cc_descr_attr_ptr != cc_descr_attrs_end; cur_cc_descr_attr_ptr++) {
-               const struct __bt_plugin_component_class_descriptor_attribute *cur_cc_descr_attr =
-                       *cur_cc_descr_attr_ptr;
-
-               if (cur_cc_descr_attr->comp_class_descriptor->plugin_descriptor !=
-                               descriptor) {
-                       continue;
-               }
-
-               /* Find the corresponding component class descriptor entry */
-               for (i = 0; i < comp_class_full_descriptors->len; i++) {
-                       struct comp_class_full_descriptor *cc_full_descr =
-                               &g_array_index(comp_class_full_descriptors,
-                                       struct comp_class_full_descriptor, i);
-
-                       if (cur_cc_descr_attr->comp_class_descriptor ==
-                                       cc_full_descr->descriptor) {
-                               switch (cur_cc_descr_attr->type) {
-                               case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_DESCRIPTION:
-                                       cc_full_descr->description =
-                                               cur_cc_descr_attr->value.description;
-                                       break;
-                               case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_INIT_METHOD:
-                                       cc_full_descr->init_method =
-                                               cur_cc_descr_attr->value.init_method;
-                                       break;
-                               case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_DESTROY_METHOD:
-                                       cc_full_descr->destroy_method =
-                                               cur_cc_descr_attr->value.destroy_method;
-                                       break;
-                               case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_FILTER_ADD_ITERATOR_METHOD:
-                                       cc_full_descr->filter_add_iterator_method =
-                                               cur_cc_descr_attr->value.filter_add_iterator_method;
-                                       break;
-                               case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_SINK_ADD_ITERATOR_METHOD:
-                                       cc_full_descr->sink_add_iterator_method =
-                                               cur_cc_descr_attr->value.sink_add_iterator_method;
-                                       break;
-                               case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_NOTIF_ITER_INIT_METHOD:
-                                       cc_full_descr->iterator_methods.init =
-                                               cur_cc_descr_attr->value.notif_iter_init_method;
-                                       break;
-                               case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_NOTIF_ITER_DESTROY_METHOD:
-                                       cc_full_descr->iterator_methods.destroy =
-                                               cur_cc_descr_attr->value.notif_iter_destroy_method;
-                                       break;
-                               case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_NOTIF_ITER_SEEK_TIME_METHOD:
-                                       cc_full_descr->iterator_methods.seek_time =
-                                               cur_cc_descr_attr->value.notif_iter_seek_time_method;
-                                       break;
-                               default:
-                                       printf_verbose("WARNING: Unknown attribute \"%s\" (type %d) for component class %s (type %d) in plugin %s\n",
-                                               cur_cc_descr_attr->type_name,
-                                               cur_cc_descr_attr->type,
-                                               cur_cc_descr_attr->comp_class_descriptor->name,
-                                               cur_cc_descr_attr->comp_class_descriptor->type,
-                                               descriptor->name);
-                                       break;
-                               }
-                       }
-               }
+       plugin->info.path = g_string_new(NULL);
+       if (!plugin->info.path) {
+               goto error;
        }
 
-       /* Initialize plugin */
-       if (plugin->init) {
-               status = plugin->init(plugin);
-               if (status < 0) {
-                       printf_verbose("Plugin `%s` initialization error: %d\n",
-                               plugin->name, status);
-                       goto end;
-               }
+       plugin->info.description = g_string_new(NULL);
+       if (!plugin->info.description) {
+               goto error;
        }
 
-       plugin->shared_lib_handle->init_called = true;
-
-       /* Add described component classes to plugin */
-       for (i = 0; i < comp_class_full_descriptors->len; i++) {
-               struct comp_class_full_descriptor *cc_full_descr =
-                       &g_array_index(comp_class_full_descriptors,
-                               struct comp_class_full_descriptor, i);
-               struct bt_component_class *comp_class;
-
-               switch (cc_full_descr->descriptor->type) {
-               case BT_COMPONENT_CLASS_TYPE_SOURCE:
-                       comp_class = bt_component_class_source_create(
-                               cc_full_descr->descriptor->name,
-                               cc_full_descr->descriptor->methods.source.notif_iter_get,
-                               cc_full_descr->descriptor->methods.source.notif_iter_next);
-                       break;
-               case BT_COMPONENT_CLASS_TYPE_FILTER:
-                       comp_class = bt_component_class_filter_create(
-                               cc_full_descr->descriptor->name,
-                               cc_full_descr->descriptor->methods.source.notif_iter_get,
-                               cc_full_descr->descriptor->methods.source.notif_iter_next);
-                       break;
-               case BT_COMPONENT_CLASS_TYPE_SINK:
-                       comp_class = bt_component_class_sink_create(
-                               cc_full_descr->descriptor->name,
-                               cc_full_descr->descriptor->methods.sink.consume);
-                       break;
-               default:
-                       printf_verbose("WARNING: Unknown component class type %d for component class %s in plugin %s\n",
-                               cc_full_descr->descriptor->type,
-                               cc_full_descr->descriptor->name,
-                               descriptor->name);
-                       continue;
-               }
-
-               if (!comp_class) {
-                       status = BT_PLUGIN_STATUS_ERROR;
-                       goto end;
-               }
-
-               if (cc_full_descr->description) {
-                       ret = bt_component_class_set_description(comp_class,
-                               cc_full_descr->description);
-                       if (ret) {
-                               status = BT_PLUGIN_STATUS_ERROR;
-                               BT_PUT(comp_class);
-                               goto end;
-                       }
-               }
-
-               if (cc_full_descr->init_method) {
-                       ret = bt_component_class_set_init_method(comp_class,
-                               cc_full_descr->init_method);
-                       if (ret) {
-                               status = BT_PLUGIN_STATUS_ERROR;
-                               BT_PUT(comp_class);
-                               goto end;
-                       }
-               }
-
-               if (cc_full_descr->destroy_method) {
-                       ret = bt_component_class_set_destroy_method(comp_class,
-                               cc_full_descr->destroy_method);
-                       if (ret) {
-                               status = BT_PLUGIN_STATUS_ERROR;
-                               BT_PUT(comp_class);
-                               goto end;
-                       }
-               }
-
-               switch (cc_full_descr->descriptor->type) {
-               case BT_COMPONENT_CLASS_TYPE_SOURCE:
-                       if (cc_full_descr->iterator_methods.init) {
-                               ret = bt_component_class_source_set_notification_iterator_init_method(
-                                       comp_class,
-                                       cc_full_descr->iterator_methods.init);
-                               if (ret) {
-                                       status = BT_PLUGIN_STATUS_ERROR;
-                                       BT_PUT(comp_class);
-                                       goto end;
-                               }
-                       }
-
-                       if (cc_full_descr->iterator_methods.destroy) {
-                               ret = bt_component_class_source_set_notification_iterator_destroy_method(
-                                       comp_class,
-                                       cc_full_descr->iterator_methods.destroy);
-                               if (ret) {
-                                       status = BT_PLUGIN_STATUS_ERROR;
-                                       BT_PUT(comp_class);
-                                       goto end;
-                               }
-                       }
-
-                       if (cc_full_descr->iterator_methods.seek_time) {
-                               ret = bt_component_class_source_set_notification_iterator_seek_time_method(
-                                       comp_class,
-                                       cc_full_descr->iterator_methods.seek_time);
-                               if (ret) {
-                                       status = BT_PLUGIN_STATUS_ERROR;
-                                       BT_PUT(comp_class);
-                                       goto end;
-                               }
-                       }
-                       break;
-               case BT_COMPONENT_CLASS_TYPE_FILTER:
-                       if (cc_full_descr->filter_add_iterator_method) {
-                               ret = bt_component_class_filter_set_add_iterator_method(
-                                       comp_class,
-                                       cc_full_descr->filter_add_iterator_method);
-                               if (ret) {
-                                       status = BT_PLUGIN_STATUS_ERROR;
-                                       BT_PUT(comp_class);
-                                       goto end;
-                               }
-                       }
-
-                       if (cc_full_descr->iterator_methods.init) {
-                               ret = bt_component_class_filter_set_notification_iterator_init_method(
-                                       comp_class,
-                                       cc_full_descr->iterator_methods.init);
-                               if (ret) {
-                                       status = BT_PLUGIN_STATUS_ERROR;
-                                       BT_PUT(comp_class);
-                                       goto end;
-                               }
-                       }
-
-                       if (cc_full_descr->iterator_methods.destroy) {
-                               ret = bt_component_class_filter_set_notification_iterator_destroy_method(
-                                       comp_class,
-                                       cc_full_descr->iterator_methods.destroy);
-                               if (ret) {
-                                       status = BT_PLUGIN_STATUS_ERROR;
-                                       BT_PUT(comp_class);
-                                       goto end;
-                               }
-                       }
-
-                       if (cc_full_descr->iterator_methods.seek_time) {
-                               ret = bt_component_class_filter_set_notification_iterator_seek_time_method(
-                                       comp_class,
-                                       cc_full_descr->iterator_methods.seek_time);
-                               if (ret) {
-                                       status = BT_PLUGIN_STATUS_ERROR;
-                                       BT_PUT(comp_class);
-                                       goto end;
-                               }
-                       }
-                       break;
-               case BT_COMPONENT_CLASS_TYPE_SINK:
-                       if (cc_full_descr->sink_add_iterator_method) {
-                               ret = bt_component_class_sink_set_add_iterator_method(
-                                       comp_class,
-                                       cc_full_descr->sink_add_iterator_method);
-                               if (ret) {
-                                       status = BT_PLUGIN_STATUS_ERROR;
-                                       BT_PUT(comp_class);
-                                       goto end;
-                               }
-                       }
-                       break;
-               default:
-                       assert(false);
-                       break;
-               }
-
-               /* Add component class to the plugin object */
-               status = bt_plugin_add_component_class(plugin,
-                       comp_class);
-               BT_PUT(comp_class);
-               if (status < 0) {
-                       printf_verbose("Cannot add component class %s (type %d) to plugin `%s`: status = %d\n",
-                               cc_full_descr->descriptor->name,
-                               cc_full_descr->descriptor->type,
-                               plugin->name, status);
-                       goto end;
-               }
+       plugin->info.author = g_string_new(NULL);
+       if (!plugin->info.author) {
+               goto error;
        }
 
-       /*
-        * All the plugin's component classes should be added at this
-        * point. We freeze the plugin so that it's not possible to add
-        * component classes to this plugin object after this stage
-        * (plugin object becomes immutable).
-        */
-       plugin->frozen = true;
-
-end:
-       g_array_free(comp_class_full_descriptors, TRUE);
-       return status;
-}
-
-static
-struct bt_plugin **bt_plugin_create_all_from_sections(
-               struct bt_plugin_shared_lib_handle *shared_lib_handle,
-               struct __bt_plugin_descriptor const * const *descriptors_begin,
-               struct __bt_plugin_descriptor const * const *descriptors_end,
-               struct __bt_plugin_descriptor_attribute const * const *attrs_begin,
-               struct __bt_plugin_descriptor_attribute const * const *attrs_end,
-               struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_begin,
-               struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_end,
-               struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_begin,
-               struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_end)
-{
-       size_t descriptor_count;
-       size_t attrs_count;
-       size_t cc_descriptors_count;
-       size_t cc_descr_attrs_count;
-       size_t i;
-       struct bt_plugin **plugins = NULL;
-
-       descriptor_count = descriptors_end - descriptors_begin;
-       attrs_count = attrs_end - attrs_begin;
-       cc_descriptors_count = cc_descriptors_end - cc_descriptors_begin;
-       cc_descr_attrs_count = cc_descr_attrs_end - cc_descr_attrs_begin;
-       printf_verbose("Section: Plugin descriptors: [%p - %p], (%zu elements)\n",
-               descriptors_begin, descriptors_end, descriptor_count);
-       printf_verbose("Section: Plugin descriptor attributes: [%p - %p], (%zu elements)\n",
-               attrs_begin, attrs_end, attrs_count);
-       printf_verbose("Section: Plugin component class descriptors: [%p - %p], (%zu elements)\n",
-               cc_descriptors_begin, cc_descriptors_end, cc_descriptors_count);
-       printf_verbose("Section: Plugin component class descriptor attributes: [%p - %p], (%zu elements)\n",
-               cc_descr_attrs_begin, cc_descr_attrs_end, cc_descr_attrs_count);
-       plugins = calloc(descriptor_count + 1, sizeof(*plugins));
-       if (!plugins) {
+       plugin->info.license = g_string_new(NULL);
+       if (!plugin->info.license) {
                goto error;
        }
 
-       for (i = 0; i < descriptor_count; i++) {
-               enum bt_plugin_status status;
-               const struct __bt_plugin_descriptor *descriptor =
-                       descriptors_begin[i];
-               struct bt_plugin *plugin;
-
-               printf_verbose("Loading plugin %s (ABI %d.%d)\n", descriptor->name,
-                       descriptor->major, descriptor->minor);
-
-               if (descriptor->major > __BT_PLUGIN_VERSION_MAJOR) {
-                       printf_error("Unknown plugin's major version: %d\n",
-                               descriptor->major);
-                       goto error;
-               }
-
-               plugin = bt_plugin_create_empty(shared_lib_handle);
-               if (!plugin) {
-                       printf_error("Cannot allocate plugin object for plugin %s\n",
-                               descriptor->name);
-                       goto error;
-               }
-
-               status = bt_plugin_init(plugin, descriptor, attrs_begin,
-                       attrs_end, cc_descriptors_begin, cc_descriptors_end,
-                       cc_descr_attrs_begin, cc_descr_attrs_end);
-               if (status < 0) {
-                       printf_error("Cannot initialize plugin object %s\n",
-                               descriptor->name);
-                       BT_PUT(plugin);
-                       goto error;
-               }
-
-               /* Transfer ownership to the array */
-               plugins[i] = plugin;
+       plugin->info.version.extra = g_string_new(NULL);
+       if (!plugin->info.version.extra) {
+               goto error;
        }
 
        goto end;
 
 error:
-       g_free(plugins);
-       plugins = NULL;
+       BT_PUT(plugin);
 
 end:
-       return plugins;
+       return plugin;
 }
 
 struct bt_plugin **bt_plugin_create_all_from_static(void)
 {
-       struct bt_plugin **plugins = NULL;
-       struct bt_plugin_shared_lib_handle *shared_lib_handle =
-               bt_plugin_shared_lib_handle_create(NULL);
-
-       if (!shared_lib_handle) {
-               goto end;
-       }
-
-       plugins = bt_plugin_create_all_from_sections(shared_lib_handle,
-               SECTION_BEGIN(__bt_plugin_descriptors),
-               SECTION_END(__bt_plugin_descriptors),
-               SECTION_BEGIN(__bt_plugin_descriptor_attributes),
-               SECTION_END(__bt_plugin_descriptor_attributes),
-               SECTION_BEGIN(__bt_plugin_component_class_descriptors),
-               SECTION_END(__bt_plugin_component_class_descriptors),
-               SECTION_BEGIN(__bt_plugin_component_class_descriptor_attributes),
-               SECTION_END(__bt_plugin_component_class_descriptor_attributes));
-
-end:
-       BT_PUT(shared_lib_handle);
-
-       return plugins;
+       return bt_plugin_so_create_all_from_static();
 }
 
 struct bt_plugin **bt_plugin_create_all_from_file(const char *path)
 {
-       size_t path_len;
        struct bt_plugin **plugins = NULL;
-       struct __bt_plugin_descriptor const * const *descriptors_begin = NULL;
-       struct __bt_plugin_descriptor const * const *descriptors_end = NULL;
-       struct __bt_plugin_descriptor_attribute const * const *attrs_begin = NULL;
-       struct __bt_plugin_descriptor_attribute const * const *attrs_end = NULL;
-       struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_begin = NULL;
-       struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_end = NULL;
-       struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_begin = NULL;
-       struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_end = NULL;
-       bool is_libtool_wrapper = false, is_shared_object = false;
-       struct bt_plugin_shared_lib_handle *shared_lib_handle = NULL;
 
        if (!path) {
                goto end;
        }
 
-       path_len = strlen(path);
-       if (path_len <= PLUGIN_SUFFIX_LEN) {
-               goto end;
-       }
-
-       path_len++;
-       /*
-        * Check if the file ends with a known plugin file type suffix (i.e. .so
-        * or .la on Linux).
-        */
-       is_libtool_wrapper = !strncmp(LIBTOOL_PLUGIN_SUFFIX,
-               path + path_len - LIBTOOL_PLUGIN_SUFFIX_LEN,
-               LIBTOOL_PLUGIN_SUFFIX_LEN);
-       is_shared_object = !strncmp(NATIVE_PLUGIN_SUFFIX,
-               path + path_len - NATIVE_PLUGIN_SUFFIX_LEN,
-               NATIVE_PLUGIN_SUFFIX_LEN);
-       if (!is_shared_object && !is_libtool_wrapper) {
-               /* Name indicates that this is not a plugin file. */
-               goto end;
-       }
-
-       shared_lib_handle = bt_plugin_shared_lib_handle_create(path);
-       if (!shared_lib_handle) {
-               goto end;
-       }
-
-       if (!g_module_symbol(shared_lib_handle->module, "__start___bt_plugin_descriptors",
-                       (gpointer *) &descriptors_begin)) {
-               printf_verbose("Unable to resolve plugin symbol %s from %s\n",
-                       "__start___bt_plugin_descriptors",
-                       g_module_name(shared_lib_handle->module));
-               goto end;
-       }
-
-       if (!g_module_symbol(shared_lib_handle->module, "__stop___bt_plugin_descriptors",
-                       (gpointer *) &descriptors_end)) {
-               printf_verbose("Unable to resolve plugin symbol %s from %s\n",
-                       "__stop___bt_plugin_descriptors",
-                       g_module_name(shared_lib_handle->module));
-               goto end;
-       }
-
-       if (!g_module_symbol(shared_lib_handle->module, "__start___bt_plugin_descriptor_attributes",
-                       (gpointer *) &attrs_begin)) {
-               printf_verbose("Unable to resolve plugin symbol %s from %s\n",
-                       "__start___bt_plugin_descriptor_attributes",
-                       g_module_name(shared_lib_handle->module));
-       }
-
-       if (!g_module_symbol(shared_lib_handle->module, "__stop___bt_plugin_descriptor_attributes",
-                       (gpointer *) &attrs_end)) {
-               printf_verbose("Unable to resolve plugin symbol %s from %s\n",
-                       "__stop___bt_plugin_descriptor_attributes",
-                       g_module_name(shared_lib_handle->module));
-       }
-
-       if ((!!attrs_begin - !!attrs_end) != 0) {
-               printf_verbose("Found __start___bt_plugin_descriptor_attributes or __stop___bt_plugin_descriptor_attributes symbol, but not both in %s\n",
-                       g_module_name(shared_lib_handle->module));
-               goto end;
-       }
-
-       if (!g_module_symbol(shared_lib_handle->module, "__start___bt_plugin_component_class_descriptors",
-                       (gpointer *) &cc_descriptors_begin)) {
-               printf_verbose("Unable to resolve plugin symbol %s from %s\n",
-                       "__start___bt_plugin_component_class_descriptors",
-                       g_module_name(shared_lib_handle->module));
-       }
-
-       if (!g_module_symbol(shared_lib_handle->module, "__stop___bt_plugin_component_class_descriptors",
-                       (gpointer *) &cc_descriptors_end)) {
-               printf_verbose("Unable to resolve plugin symbol %s from %s\n",
-                       "__stop___bt_plugin_component_class_descriptors",
-                       g_module_name(shared_lib_handle->module));
-       }
+       printf_verbose("Trying to load plugins from `%s`\n", path);
 
-       if ((!!cc_descriptors_begin - !!cc_descriptors_end) != 0) {
-               printf_verbose("Found __start___bt_plugin_component_class_descriptors or __stop___bt_plugin_component_class_descriptors symbol, but not both in %s\n",
-                       g_module_name(shared_lib_handle->module));
+       /* Try shared object plugins */
+       plugins = bt_plugin_so_create_all_from_file(path);
+       if (plugins) {
                goto end;
        }
 
-       if (!g_module_symbol(shared_lib_handle->module, "__start___bt_plugin_component_class_descriptor_attributes",
-                       (gpointer *) &cc_descr_attrs_begin)) {
-               printf_verbose("Unable to resolve plugin symbol %s from %s\n",
-                       "__start___bt_plugin_component_class_descriptor_attributes",
-                       g_module_name(shared_lib_handle->module));
-       }
-
-       if (!g_module_symbol(shared_lib_handle->module, "__stop___bt_plugin_component_class_descriptor_attributes",
-                       (gpointer *) &cc_descr_attrs_end)) {
-               printf_verbose("Unable to resolve plugin symbol %s from %s\n",
-                       "__stop___bt_plugin_component_class_descriptor_attributes",
-                       g_module_name(shared_lib_handle->module));
-       }
-
-       if ((!!cc_descr_attrs_begin - !!cc_descr_attrs_end) != 0) {
-               printf_verbose("Found __start___bt_plugin_component_class_descriptor_attributes or __stop___bt_plugin_component_class_descriptor_attributes symbol, but not both in %s\n",
-                       g_module_name(shared_lib_handle->module));
+       plugins = bt_plugin_python_create_all_from_file(path);
+       if (plugins) {
                goto end;
        }
 
-       /* Initialize plugin */
-       plugins = bt_plugin_create_all_from_sections(shared_lib_handle,
-               descriptors_begin, descriptors_end, attrs_begin, attrs_end,
-               cc_descriptors_begin, cc_descriptors_end,
-               cc_descr_attrs_begin, cc_descr_attrs_end);
-
 end:
-       BT_PUT(shared_lib_handle);
        return plugins;
 }
 
@@ -960,7 +263,6 @@ enum bt_plugin_status bt_plugin_create_append_all_from_dir(
 
                strncpy(file_path + path_len, result->d_name, file_name_len);
                file_path[path_len + file_name_len] = '\0';
-
                stat_ret = stat(file_path, &st);
                if (stat_ret < 0) {
                        /* Continue to next file / directory. */
@@ -1040,28 +342,27 @@ end:
 
 const char *bt_plugin_get_name(struct bt_plugin *plugin)
 {
-       return plugin ? plugin->name : NULL;
+       return plugin && plugin->info.name_set ? plugin->info.name->str : NULL;
 }
 
 const char *bt_plugin_get_author(struct bt_plugin *plugin)
 {
-       return plugin ? plugin->author : NULL;
+       return plugin && plugin->info.author_set ? plugin->info.author->str : NULL;
 }
 
 const char *bt_plugin_get_license(struct bt_plugin *plugin)
 {
-       return plugin ? plugin->license : NULL;
+       return plugin && plugin->info.license_set ? plugin->info.license->str : NULL;
 }
 
 const char *bt_plugin_get_path(struct bt_plugin *plugin)
 {
-       return (plugin && plugin->shared_lib_handle->path) ?
-               plugin->shared_lib_handle->path->str : NULL;
+       return plugin && plugin->info.path_set ? plugin->info.path->str : NULL;
 }
 
 const char *bt_plugin_get_description(struct bt_plugin *plugin)
 {
-       return plugin ? plugin->description : NULL;
+       return plugin && plugin->info.description_set ? plugin->info.description->str : NULL;
 }
 
 enum bt_plugin_status bt_plugin_get_version(struct bt_plugin *plugin,
@@ -1070,25 +371,25 @@ enum bt_plugin_status bt_plugin_get_version(struct bt_plugin *plugin,
 {
        enum bt_plugin_status status = BT_PLUGIN_STATUS_OK;
 
-       if (!plugin || !plugin->version) {
+       if (!plugin || !plugin->info.version_set) {
                status = BT_PLUGIN_STATUS_ERROR;
                goto end;
        }
 
        if (major) {
-               *major = (unsigned int) plugin->version->major;
+               *major = plugin->info.version.major;
        }
 
        if (minor) {
-               *minor = (unsigned int) plugin->version->minor;
+               *minor = plugin->info.version.minor;
        }
 
        if (patch) {
-               *patch = (unsigned int) plugin->version->patch;
+               *patch = plugin->info.version.patch;
        }
 
        if (extra) {
-               *extra = plugin->version->extra;
+               *extra = plugin->info.version.extra->str;
        }
 
 end:
@@ -1158,15 +459,6 @@ end:
        return comp_class;
 }
 
-static
-void plugin_comp_class_destroy_listener(struct bt_component_class *comp_class,
-               void *data)
-{
-       gboolean exists = g_hash_table_remove(comp_classes_to_shlib_handles,
-               comp_class);
-       assert(exists);
-}
-
 enum bt_plugin_status bt_plugin_add_component_class(
        struct bt_plugin *plugin, struct bt_component_class *comp_class)
 {
@@ -1185,7 +477,7 @@ enum bt_plugin_status bt_plugin_add_component_class(
                bt_component_class_get_type(comp_class));
        if (comp_class_dup) {
                printf_verbose("Plugin `%s`: adding component class with existing name `%s` and type %d\n",
-                       plugin->name,
+                       bt_plugin_get_name(plugin),
                        bt_component_class_get_name(comp_class),
                        bt_component_class_get_type(comp_class));
                goto error;
@@ -1195,24 +487,17 @@ enum bt_plugin_status bt_plugin_add_component_class(
        comp_class_index = plugin->comp_classes->len;
        g_ptr_array_add(plugin->comp_classes, bt_get(comp_class));
 
-       /* Map component class pointer to shared lib handle in global HT */
-       g_hash_table_insert(comp_classes_to_shlib_handles, comp_class,
-               bt_get(plugin->shared_lib_handle));
-
-       /* Add our custom destroy listener */
-       ret = bt_component_class_add_destroy_listener(comp_class,
-               plugin_comp_class_destroy_listener, NULL);
-       if (ret) {
-               goto error;
+       /* Special case for a shared object plugin */
+       if (plugin->type == BT_PLUGIN_TYPE_SO) {
+               ret = bt_plugin_so_on_add_component_class(plugin, comp_class);
+               if (ret) {
+                       goto error;
+               }
        }
 
        goto end;
 
 error:
-       /* Remove entry from global hash table (if exists) */
-       g_hash_table_remove(comp_classes_to_shlib_handles,
-               comp_class);
-
        /* Remove entry from plugin's component classes (if added) */
        if (comp_class_index >= 0) {
                g_ptr_array_remove_index(plugin->comp_classes,
This page took 0.061818 seconds and 4 git commands to generate.