6 * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
7 * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
9 * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
11 * Permission is hereby granted, free of charge, to any person obtaining a copy
12 * of this software and associated documentation files (the "Software"), to deal
13 * in the Software without restriction, including without limitation the rights
14 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 * copies of the Software, and to permit persons to whom the Software is
16 * furnished to do so, subject to the following conditions:
18 * The above copyright notice and this permission notice shall be included in
19 * all copies or substantial portions of the Software.
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 #include <babeltrace/compiler.h>
31 #include <babeltrace/ref.h>
32 #include <babeltrace/plugin/plugin-dev.h>
33 #include <babeltrace/plugin/plugin-internal.h>
34 #include <babeltrace/component/component-class-internal.h>
44 #define NATIVE_PLUGIN_SUFFIX ".so"
45 #define NATIVE_PLUGIN_SUFFIX_LEN sizeof(NATIVE_PLUGIN_SUFFIX)
46 #define LIBTOOL_PLUGIN_SUFFIX ".la"
47 #define LIBTOOL_PLUGIN_SUFFIX_LEN sizeof(LIBTOOL_PLUGIN_SUFFIX)
49 #define PLUGIN_SUFFIX_LEN max_t(size_t, sizeof(NATIVE_PLUGIN_SUFFIX), \
50 sizeof(LIBTOOL_PLUGIN_SUFFIX))
52 #define SECTION_BEGIN(_name) (&(__start_##_name))
53 #define SECTION_END(_name) (&(__stop_##_name))
54 #define SECTION_ELEMENT_COUNT(_name) (SECTION_END(_name) - SECTION_BEGIN(_name))
56 #define DECLARE_SECTION(_type, _name) \
57 extern _type __start_##_name __attribute((weak)); \
58 extern _type __stop_##_name __attribute((weak))
60 DECLARE_SECTION(struct __bt_plugin_descriptor
const *, __bt_plugin_descriptors
);
61 DECLARE_SECTION(struct __bt_plugin_descriptor_attribute
const *, __bt_plugin_descriptor_attributes
);
62 DECLARE_SECTION(struct __bt_plugin_component_class_descriptor
const *, __bt_plugin_component_class_descriptors
);
63 DECLARE_SECTION(struct __bt_plugin_component_class_descriptor_attribute
const *, __bt_plugin_component_class_descriptor_attributes
);
66 * This hash table, global to the library, maps component class pointers
67 * to shared library handles.
69 * The keys (component classes) are NOT owned by this hash table, whereas
70 * the values (shared library handles) are owned by this hash table.
72 * The keys are the component classes created with
73 * bt_plugin_add_component_class(). They keep the shared library handle
74 * object created by their plugin alive so that the plugin's code is
75 * not discarded when it could still be in use by living components
76 * created from those component classes:
78 * [component] --ref-> [component class] --through this HT-> [shlib handle]
80 * This hash table exists for two reasons:
82 * 1. To allow this application:
84 * my_plugins = bt_plugin_create_all_from_file("/path/to/my-plugin.so");
85 * // instantiate components from a plugin's component classes
86 * // put plugins and free my_plugins here
87 * // user code of instantiated components still exists
89 * 2. To decouple the plugin subsystem from the component subsystem:
90 * while plugins objects need to know component class objects, the
91 * opposite is not necessary, thus it makes no sense for a component
92 * class to keep a reference to the plugin object from which it was
95 * An entry is removed from this HT when a component class is destroyed
96 * thanks to a custom destroy listener. When the entry is removed, the
97 * GLib function calls the value destroy notifier of the HT, which is
98 * bt_put(). This decreases the reference count of the mapped shared
99 * library handle. Assuming the original plugin object which contained
100 * some component classes is put first, when the last component class is
101 * removed from this HT, the shared library handle object's reference
102 * count falls to zero and the shared library is finally closed.
105 GHashTable
*comp_classes_to_shlib_handles
;
107 __attribute__((constructor
)) static
108 void init_comp_classes_to_shlib_handles(void) {
109 comp_classes_to_shlib_handles
= g_hash_table_new_full(g_direct_hash
,
110 g_direct_equal
, NULL
, bt_put
);
111 assert(comp_classes_to_shlib_handles
);
114 __attribute__((destructor
)) static
115 void fini_comp_classes_to_shlib_handles(void) {
116 if (comp_classes_to_shlib_handles
) {
117 g_hash_table_destroy(comp_classes_to_shlib_handles
);
122 void bt_plugin_shared_lib_handle_destroy(struct bt_object
*obj
)
124 struct bt_plugin_shared_lib_handle
*shared_lib_handle
;
127 shared_lib_handle
= container_of(obj
,
128 struct bt_plugin_shared_lib_handle
, base
);
130 if (shared_lib_handle
->init_called
&& shared_lib_handle
->exit
) {
131 enum bt_plugin_status status
= shared_lib_handle
->exit();
134 const char *path
= shared_lib_handle
->path
?
135 shared_lib_handle
->path
->str
: "[built-in]";
137 printf_verbose("Plugin in module `%s` exited with error %d\n",
142 if (shared_lib_handle
->module
) {
143 if (!g_module_close(shared_lib_handle
->module
)) {
144 printf_error("Module close error: %s\n",
149 if (shared_lib_handle
->path
) {
150 g_string_free(shared_lib_handle
->path
, TRUE
);
153 g_free(shared_lib_handle
);
157 struct bt_plugin_shared_lib_handle
*bt_plugin_shared_lib_handle_create(
160 struct bt_plugin_shared_lib_handle
*shared_lib_handle
= NULL
;
162 shared_lib_handle
= g_new0(struct bt_plugin_shared_lib_handle
, 1);
163 if (!shared_lib_handle
) {
167 bt_object_init(shared_lib_handle
, bt_plugin_shared_lib_handle_destroy
);
173 shared_lib_handle
->path
= g_string_new(path
);
174 if (!shared_lib_handle
->path
) {
178 shared_lib_handle
->module
= g_module_open(path
, 0);
179 if (!shared_lib_handle
->module
) {
180 printf_verbose("Module open error: %s\n", g_module_error());
187 BT_PUT(shared_lib_handle
);
190 return shared_lib_handle
;
194 void bt_plugin_destroy(struct bt_object
*obj
)
196 struct bt_plugin
*plugin
;
199 plugin
= container_of(obj
, struct bt_plugin
, base
);
201 BT_PUT(plugin
->shared_lib_handle
);
203 if (plugin
->comp_classes
) {
204 g_ptr_array_free(plugin
->comp_classes
, TRUE
);
211 struct bt_plugin
*bt_plugin_create_empty(
212 struct bt_plugin_shared_lib_handle
*shared_lib_handle
)
214 struct bt_plugin
*plugin
= NULL
;
216 plugin
= g_new0(struct bt_plugin
, 1);
221 bt_object_init(plugin
, bt_plugin_destroy
);
222 plugin
->shared_lib_handle
= bt_get(shared_lib_handle
);
224 /* Create empty array of component classes */
225 plugin
->comp_classes
=
226 g_ptr_array_new_with_free_func((GDestroyNotify
) bt_put
);
227 if (!plugin
->comp_classes
) {
241 * This function does the following:
243 * 1. Iterate on the plugin descriptor attributes section and set the
244 * plugin's attributes depending on the attribute types. This
245 * includes the name of the plugin, its description, and its
246 * initialization function, for example.
248 * 2. Iterate on the component class descriptors section and create one
249 * "full descriptor" (temporary structure) for each one that is found
250 * and attached to our plugin descriptor.
252 * 3. Iterate on the component class descriptor attributes section and
253 * set the corresponding full descriptor's attributes depending on
254 * the attribute types. This includes the description of the
255 * component class, as well as its initialization and destroy
258 * 4. Call the user's plugin initialization function, if any is
261 * 5. For each full component class descriptor, create a component class
262 * object, set its optional attributes, and add it to the plugin
265 * 6. Freeze the plugin object.
268 enum bt_plugin_status
bt_plugin_init(
269 struct bt_plugin
*plugin
,
270 const struct __bt_plugin_descriptor
*descriptor
,
271 struct __bt_plugin_descriptor_attribute
const * const *attrs_begin
,
272 struct __bt_plugin_descriptor_attribute
const * const *attrs_end
,
273 struct __bt_plugin_component_class_descriptor
const * const *cc_descriptors_begin
,
274 struct __bt_plugin_component_class_descriptor
const * const *cc_descriptors_end
,
275 struct __bt_plugin_component_class_descriptor_attribute
const * const *cc_descr_attrs_begin
,
276 struct __bt_plugin_component_class_descriptor_attribute
const * const *cc_descr_attrs_end
)
279 * This structure's members point to the plugin's memory
282 struct comp_class_full_descriptor
{
283 const struct __bt_plugin_component_class_descriptor
*descriptor
;
284 const char *description
;
285 bt_component_class_init_method init_method
;
286 bt_component_class_destroy_method destroy_method
;
287 bt_component_class_filter_add_iterator_method filter_add_iterator_method
;
288 bt_component_class_sink_add_iterator_method sink_add_iterator_method
;
289 struct bt_component_class_iterator_methods iterator_methods
;
292 enum bt_plugin_status status
= BT_PLUGIN_STATUS_OK
;
293 struct __bt_plugin_descriptor_attribute
const * const *cur_attr_ptr
;
294 struct __bt_plugin_component_class_descriptor
const * const *cur_cc_descr_ptr
;
295 struct __bt_plugin_component_class_descriptor_attribute
const * const *cur_cc_descr_attr_ptr
;
296 GArray
*comp_class_full_descriptors
;
300 comp_class_full_descriptors
= g_array_new(FALSE
, TRUE
,
301 sizeof(struct comp_class_full_descriptor
));
302 if (!comp_class_full_descriptors
) {
303 status
= BT_PLUGIN_STATUS_ERROR
;
307 /* Set mandatory attributes */
308 plugin
->descriptor
= descriptor
;
309 plugin
->name
= descriptor
->name
;
312 * Find and set optional attributes attached to this plugin
315 for (cur_attr_ptr
= attrs_begin
; cur_attr_ptr
!= attrs_end
; cur_attr_ptr
++) {
316 const struct __bt_plugin_descriptor_attribute
*cur_attr
=
319 if (cur_attr
->plugin_descriptor
!= descriptor
) {
323 switch (cur_attr
->type
) {
324 case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_INIT
:
325 plugin
->init
= cur_attr
->value
.init
;
327 case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_EXIT
:
328 plugin
->shared_lib_handle
->exit
= cur_attr
->value
.exit
;
330 case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_AUTHOR
:
331 plugin
->author
= cur_attr
->value
.author
;
333 case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_LICENSE
:
334 plugin
->license
= cur_attr
->value
.license
;
336 case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_DESCRIPTION
:
337 plugin
->description
= cur_attr
->value
.description
;
339 case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_VERSION
:
340 plugin
->version
= &cur_attr
->value
.version
;
343 printf_verbose("WARNING: Unknown attribute \"%s\" (type %d) for plugin %s\n",
344 cur_attr
->type_name
, cur_attr
->type
,
351 * Find component class descriptors attached to this plugin
352 * descriptor and initialize corresponding full component class
353 * descriptors in the array.
355 for (cur_cc_descr_ptr
= cc_descriptors_begin
; cur_cc_descr_ptr
!= cc_descriptors_end
; cur_cc_descr_ptr
++) {
356 const struct __bt_plugin_component_class_descriptor
*cur_cc_descr
=
358 struct comp_class_full_descriptor full_descriptor
= {0};
360 if (cur_cc_descr
->plugin_descriptor
!= descriptor
) {
364 full_descriptor
.descriptor
= cur_cc_descr
;
365 g_array_append_val(comp_class_full_descriptors
,
370 * Find component class descriptor attributes attached to this
371 * plugin descriptor and update corresponding full component
372 * class descriptors in the array.
374 for (cur_cc_descr_attr_ptr
= cc_descr_attrs_begin
; cur_cc_descr_attr_ptr
!= cc_descr_attrs_end
; cur_cc_descr_attr_ptr
++) {
375 const struct __bt_plugin_component_class_descriptor_attribute
*cur_cc_descr_attr
=
376 *cur_cc_descr_attr_ptr
;
378 if (cur_cc_descr_attr
->comp_class_descriptor
->plugin_descriptor
!=
383 /* Find the corresponding component class descriptor entry */
384 for (i
= 0; i
< comp_class_full_descriptors
->len
; i
++) {
385 struct comp_class_full_descriptor
*cc_full_descr
=
386 &g_array_index(comp_class_full_descriptors
,
387 struct comp_class_full_descriptor
, i
);
389 if (cur_cc_descr_attr
->comp_class_descriptor
==
390 cc_full_descr
->descriptor
) {
391 switch (cur_cc_descr_attr
->type
) {
392 case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_DESCRIPTION
:
393 cc_full_descr
->description
=
394 cur_cc_descr_attr
->value
.description
;
396 case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_INIT_METHOD
:
397 cc_full_descr
->init_method
=
398 cur_cc_descr_attr
->value
.init_method
;
400 case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_DESTROY_METHOD
:
401 cc_full_descr
->destroy_method
=
402 cur_cc_descr_attr
->value
.destroy_method
;
404 case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_FILTER_ADD_ITERATOR_METHOD
:
405 cc_full_descr
->filter_add_iterator_method
=
406 cur_cc_descr_attr
->value
.filter_add_iterator_method
;
408 case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_SINK_ADD_ITERATOR_METHOD
:
409 cc_full_descr
->sink_add_iterator_method
=
410 cur_cc_descr_attr
->value
.sink_add_iterator_method
;
412 case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_NOTIF_ITER_INIT_METHOD
:
413 cc_full_descr
->iterator_methods
.init
=
414 cur_cc_descr_attr
->value
.notif_iter_init_method
;
416 case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_NOTIF_ITER_DESTROY_METHOD
:
417 cc_full_descr
->iterator_methods
.destroy
=
418 cur_cc_descr_attr
->value
.notif_iter_destroy_method
;
420 case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_NOTIF_ITER_SEEK_TIME_METHOD
:
421 cc_full_descr
->iterator_methods
.seek_time
=
422 cur_cc_descr_attr
->value
.notif_iter_seek_time_method
;
425 printf_verbose("WARNING: Unknown attribute \"%s\" (type %d) for component class %s (type %d) in plugin %s\n",
426 cur_cc_descr_attr
->type_name
,
427 cur_cc_descr_attr
->type
,
428 cur_cc_descr_attr
->comp_class_descriptor
->name
,
429 cur_cc_descr_attr
->comp_class_descriptor
->type
,
437 /* Initialize plugin */
439 status
= plugin
->init(plugin
);
441 printf_verbose("Plugin `%s` initialization error: %d\n",
442 plugin
->name
, status
);
447 plugin
->shared_lib_handle
->init_called
= true;
449 /* Add described component classes to plugin */
450 for (i
= 0; i
< comp_class_full_descriptors
->len
; i
++) {
451 struct comp_class_full_descriptor
*cc_full_descr
=
452 &g_array_index(comp_class_full_descriptors
,
453 struct comp_class_full_descriptor
, i
);
454 struct bt_component_class
*comp_class
;
456 switch (cc_full_descr
->descriptor
->type
) {
457 case BT_COMPONENT_CLASS_TYPE_SOURCE
:
458 comp_class
= bt_component_class_source_create(
459 cc_full_descr
->descriptor
->name
,
460 cc_full_descr
->descriptor
->methods
.source
.notif_iter_get
,
461 cc_full_descr
->descriptor
->methods
.source
.notif_iter_next
);
463 case BT_COMPONENT_CLASS_TYPE_FILTER
:
464 comp_class
= bt_component_class_filter_create(
465 cc_full_descr
->descriptor
->name
,
466 cc_full_descr
->descriptor
->methods
.source
.notif_iter_get
,
467 cc_full_descr
->descriptor
->methods
.source
.notif_iter_next
);
469 case BT_COMPONENT_CLASS_TYPE_SINK
:
470 comp_class
= bt_component_class_sink_create(
471 cc_full_descr
->descriptor
->name
,
472 cc_full_descr
->descriptor
->methods
.sink
.consume
);
475 printf_verbose("WARNING: Unknown component class type %d for component class %s in plugin %s\n",
476 cc_full_descr
->descriptor
->type
,
477 cc_full_descr
->descriptor
->name
,
483 status
= BT_PLUGIN_STATUS_ERROR
;
487 if (cc_full_descr
->description
) {
488 ret
= bt_component_class_set_description(comp_class
,
489 cc_full_descr
->description
);
491 status
= BT_PLUGIN_STATUS_ERROR
;
497 if (cc_full_descr
->init_method
) {
498 ret
= bt_component_class_set_init_method(comp_class
,
499 cc_full_descr
->init_method
);
501 status
= BT_PLUGIN_STATUS_ERROR
;
507 if (cc_full_descr
->destroy_method
) {
508 ret
= bt_component_class_set_destroy_method(comp_class
,
509 cc_full_descr
->destroy_method
);
511 status
= BT_PLUGIN_STATUS_ERROR
;
517 switch (cc_full_descr
->descriptor
->type
) {
518 case BT_COMPONENT_CLASS_TYPE_SOURCE
:
519 if (cc_full_descr
->iterator_methods
.init
) {
520 ret
= bt_component_class_source_set_notification_iterator_init_method(
522 cc_full_descr
->iterator_methods
.init
);
524 status
= BT_PLUGIN_STATUS_ERROR
;
530 if (cc_full_descr
->iterator_methods
.destroy
) {
531 ret
= bt_component_class_source_set_notification_iterator_destroy_method(
533 cc_full_descr
->iterator_methods
.destroy
);
535 status
= BT_PLUGIN_STATUS_ERROR
;
541 if (cc_full_descr
->iterator_methods
.seek_time
) {
542 ret
= bt_component_class_source_set_notification_iterator_seek_time_method(
544 cc_full_descr
->iterator_methods
.seek_time
);
546 status
= BT_PLUGIN_STATUS_ERROR
;
552 case BT_COMPONENT_CLASS_TYPE_FILTER
:
553 if (cc_full_descr
->filter_add_iterator_method
) {
554 ret
= bt_component_class_filter_set_add_iterator_method(
556 cc_full_descr
->filter_add_iterator_method
);
558 status
= BT_PLUGIN_STATUS_ERROR
;
564 if (cc_full_descr
->iterator_methods
.init
) {
565 ret
= bt_component_class_filter_set_notification_iterator_init_method(
567 cc_full_descr
->iterator_methods
.init
);
569 status
= BT_PLUGIN_STATUS_ERROR
;
575 if (cc_full_descr
->iterator_methods
.destroy
) {
576 ret
= bt_component_class_filter_set_notification_iterator_destroy_method(
578 cc_full_descr
->iterator_methods
.destroy
);
580 status
= BT_PLUGIN_STATUS_ERROR
;
586 if (cc_full_descr
->iterator_methods
.seek_time
) {
587 ret
= bt_component_class_filter_set_notification_iterator_seek_time_method(
589 cc_full_descr
->iterator_methods
.seek_time
);
591 status
= BT_PLUGIN_STATUS_ERROR
;
597 case BT_COMPONENT_CLASS_TYPE_SINK
:
598 if (cc_full_descr
->sink_add_iterator_method
) {
599 ret
= bt_component_class_sink_set_add_iterator_method(
601 cc_full_descr
->sink_add_iterator_method
);
603 status
= BT_PLUGIN_STATUS_ERROR
;
614 /* Add component class to the plugin object */
615 status
= bt_plugin_add_component_class(plugin
,
619 printf_verbose("Cannot add component class %s (type %d) to plugin `%s`: status = %d\n",
620 cc_full_descr
->descriptor
->name
,
621 cc_full_descr
->descriptor
->type
,
622 plugin
->name
, status
);
628 * All the plugin's component classes should be added at this
629 * point. We freeze the plugin so that it's not possible to add
630 * component classes to this plugin object after this stage
631 * (plugin object becomes immutable).
633 plugin
->frozen
= true;
636 g_array_free(comp_class_full_descriptors
, TRUE
);
641 struct bt_plugin
**bt_plugin_create_all_from_sections(
642 struct bt_plugin_shared_lib_handle
*shared_lib_handle
,
643 struct __bt_plugin_descriptor
const * const *descriptors_begin
,
644 struct __bt_plugin_descriptor
const * const *descriptors_end
,
645 struct __bt_plugin_descriptor_attribute
const * const *attrs_begin
,
646 struct __bt_plugin_descriptor_attribute
const * const *attrs_end
,
647 struct __bt_plugin_component_class_descriptor
const * const *cc_descriptors_begin
,
648 struct __bt_plugin_component_class_descriptor
const * const *cc_descriptors_end
,
649 struct __bt_plugin_component_class_descriptor_attribute
const * const *cc_descr_attrs_begin
,
650 struct __bt_plugin_component_class_descriptor_attribute
const * const *cc_descr_attrs_end
)
652 size_t descriptor_count
;
654 size_t cc_descriptors_count
;
655 size_t cc_descr_attrs_count
;
657 struct bt_plugin
**plugins
= NULL
;
659 descriptor_count
= descriptors_end
- descriptors_begin
;
660 attrs_count
= attrs_end
- attrs_begin
;
661 cc_descriptors_count
= cc_descriptors_end
- cc_descriptors_begin
;
662 cc_descr_attrs_count
= cc_descr_attrs_end
- cc_descr_attrs_begin
;
663 printf_verbose("Section: Plugin descriptors: [%p - %p], (%zu elements)\n",
664 descriptors_begin
, descriptors_end
, descriptor_count
);
665 printf_verbose("Section: Plugin descriptor attributes: [%p - %p], (%zu elements)\n",
666 attrs_begin
, attrs_end
, attrs_count
);
667 printf_verbose("Section: Plugin component class descriptors: [%p - %p], (%zu elements)\n",
668 cc_descriptors_begin
, cc_descriptors_end
, cc_descriptors_count
);
669 printf_verbose("Section: Plugin component class descriptor attributes: [%p - %p], (%zu elements)\n",
670 cc_descr_attrs_begin
, cc_descr_attrs_end
, cc_descr_attrs_count
);
671 plugins
= calloc(descriptor_count
+ 1, sizeof(*plugins
));
676 for (i
= 0; i
< descriptor_count
; i
++) {
677 enum bt_plugin_status status
;
678 const struct __bt_plugin_descriptor
*descriptor
=
679 descriptors_begin
[i
];
680 struct bt_plugin
*plugin
;
682 printf_verbose("Loading plugin %s (ABI %d.%d)\n", descriptor
->name
,
683 descriptor
->major
, descriptor
->minor
);
685 if (descriptor
->major
> __BT_PLUGIN_VERSION_MAJOR
) {
686 printf_error("Unknown plugin's major version: %d\n",
691 plugin
= bt_plugin_create_empty(shared_lib_handle
);
693 printf_error("Cannot allocate plugin object for plugin %s\n",
698 status
= bt_plugin_init(plugin
, descriptor
, attrs_begin
,
699 attrs_end
, cc_descriptors_begin
, cc_descriptors_end
,
700 cc_descr_attrs_begin
, cc_descr_attrs_end
);
702 printf_error("Cannot initialize plugin object %s\n",
708 /* Transfer ownership to the array */
722 struct bt_plugin
**bt_plugin_create_all_from_static(void)
724 struct bt_plugin
**plugins
= NULL
;
725 struct bt_plugin_shared_lib_handle
*shared_lib_handle
=
726 bt_plugin_shared_lib_handle_create(NULL
);
728 if (!shared_lib_handle
) {
732 plugins
= bt_plugin_create_all_from_sections(shared_lib_handle
,
733 SECTION_BEGIN(__bt_plugin_descriptors
),
734 SECTION_END(__bt_plugin_descriptors
),
735 SECTION_BEGIN(__bt_plugin_descriptor_attributes
),
736 SECTION_END(__bt_plugin_descriptor_attributes
),
737 SECTION_BEGIN(__bt_plugin_component_class_descriptors
),
738 SECTION_END(__bt_plugin_component_class_descriptors
),
739 SECTION_BEGIN(__bt_plugin_component_class_descriptor_attributes
),
740 SECTION_END(__bt_plugin_component_class_descriptor_attributes
));
743 BT_PUT(shared_lib_handle
);
748 struct bt_plugin
**bt_plugin_create_all_from_file(const char *path
)
751 struct bt_plugin
**plugins
= NULL
;
752 struct __bt_plugin_descriptor
const * const *descriptors_begin
= NULL
;
753 struct __bt_plugin_descriptor
const * const *descriptors_end
= NULL
;
754 struct __bt_plugin_descriptor_attribute
const * const *attrs_begin
= NULL
;
755 struct __bt_plugin_descriptor_attribute
const * const *attrs_end
= NULL
;
756 struct __bt_plugin_component_class_descriptor
const * const *cc_descriptors_begin
= NULL
;
757 struct __bt_plugin_component_class_descriptor
const * const *cc_descriptors_end
= NULL
;
758 struct __bt_plugin_component_class_descriptor_attribute
const * const *cc_descr_attrs_begin
= NULL
;
759 struct __bt_plugin_component_class_descriptor_attribute
const * const *cc_descr_attrs_end
= NULL
;
760 bool is_libtool_wrapper
= false, is_shared_object
= false;
761 struct bt_plugin_shared_lib_handle
*shared_lib_handle
= NULL
;
767 path_len
= strlen(path
);
768 if (path_len
<= PLUGIN_SUFFIX_LEN
) {
774 * Check if the file ends with a known plugin file type suffix (i.e. .so
777 is_libtool_wrapper
= !strncmp(LIBTOOL_PLUGIN_SUFFIX
,
778 path
+ path_len
- LIBTOOL_PLUGIN_SUFFIX_LEN
,
779 LIBTOOL_PLUGIN_SUFFIX_LEN
);
780 is_shared_object
= !strncmp(NATIVE_PLUGIN_SUFFIX
,
781 path
+ path_len
- NATIVE_PLUGIN_SUFFIX_LEN
,
782 NATIVE_PLUGIN_SUFFIX_LEN
);
783 if (!is_shared_object
&& !is_libtool_wrapper
) {
784 /* Name indicates that this is not a plugin file. */
788 shared_lib_handle
= bt_plugin_shared_lib_handle_create(path
);
789 if (!shared_lib_handle
) {
793 if (!g_module_symbol(shared_lib_handle
->module
, "__start___bt_plugin_descriptors",
794 (gpointer
*) &descriptors_begin
)) {
795 printf_verbose("Unable to resolve plugin symbol %s from %s\n",
796 "__start___bt_plugin_descriptors",
797 g_module_name(shared_lib_handle
->module
));
801 if (!g_module_symbol(shared_lib_handle
->module
, "__stop___bt_plugin_descriptors",
802 (gpointer
*) &descriptors_end
)) {
803 printf_verbose("Unable to resolve plugin symbol %s from %s\n",
804 "__stop___bt_plugin_descriptors",
805 g_module_name(shared_lib_handle
->module
));
809 if (!g_module_symbol(shared_lib_handle
->module
, "__start___bt_plugin_descriptor_attributes",
810 (gpointer
*) &attrs_begin
)) {
811 printf_verbose("Unable to resolve plugin symbol %s from %s\n",
812 "__start___bt_plugin_descriptor_attributes",
813 g_module_name(shared_lib_handle
->module
));
816 if (!g_module_symbol(shared_lib_handle
->module
, "__stop___bt_plugin_descriptor_attributes",
817 (gpointer
*) &attrs_end
)) {
818 printf_verbose("Unable to resolve plugin symbol %s from %s\n",
819 "__stop___bt_plugin_descriptor_attributes",
820 g_module_name(shared_lib_handle
->module
));
823 if ((!!attrs_begin
- !!attrs_end
) != 0) {
824 printf_verbose("Found __start___bt_plugin_descriptor_attributes or __stop___bt_plugin_descriptor_attributes symbol, but not both in %s\n",
825 g_module_name(shared_lib_handle
->module
));
829 if (!g_module_symbol(shared_lib_handle
->module
, "__start___bt_plugin_component_class_descriptors",
830 (gpointer
*) &cc_descriptors_begin
)) {
831 printf_verbose("Unable to resolve plugin symbol %s from %s\n",
832 "__start___bt_plugin_component_class_descriptors",
833 g_module_name(shared_lib_handle
->module
));
836 if (!g_module_symbol(shared_lib_handle
->module
, "__stop___bt_plugin_component_class_descriptors",
837 (gpointer
*) &cc_descriptors_end
)) {
838 printf_verbose("Unable to resolve plugin symbol %s from %s\n",
839 "__stop___bt_plugin_component_class_descriptors",
840 g_module_name(shared_lib_handle
->module
));
843 if ((!!cc_descriptors_begin
- !!cc_descriptors_end
) != 0) {
844 printf_verbose("Found __start___bt_plugin_component_class_descriptors or __stop___bt_plugin_component_class_descriptors symbol, but not both in %s\n",
845 g_module_name(shared_lib_handle
->module
));
849 if (!g_module_symbol(shared_lib_handle
->module
, "__start___bt_plugin_component_class_descriptor_attributes",
850 (gpointer
*) &cc_descr_attrs_begin
)) {
851 printf_verbose("Unable to resolve plugin symbol %s from %s\n",
852 "__start___bt_plugin_component_class_descriptor_attributes",
853 g_module_name(shared_lib_handle
->module
));
856 if (!g_module_symbol(shared_lib_handle
->module
, "__stop___bt_plugin_component_class_descriptor_attributes",
857 (gpointer
*) &cc_descr_attrs_end
)) {
858 printf_verbose("Unable to resolve plugin symbol %s from %s\n",
859 "__stop___bt_plugin_component_class_descriptor_attributes",
860 g_module_name(shared_lib_handle
->module
));
863 if ((!!cc_descr_attrs_begin
- !!cc_descr_attrs_end
) != 0) {
864 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",
865 g_module_name(shared_lib_handle
->module
));
869 /* Initialize plugin */
870 plugins
= bt_plugin_create_all_from_sections(shared_lib_handle
,
871 descriptors_begin
, descriptors_end
, attrs_begin
, attrs_end
,
872 cc_descriptors_begin
, cc_descriptors_end
,
873 cc_descr_attrs_begin
, cc_descr_attrs_end
);
876 BT_PUT(shared_lib_handle
);
880 /* Allocate dirent as recommended by READDIR(3), NOTES on readdir_r */
882 struct dirent
*alloc_dirent(const char *path
)
886 struct dirent
*entry
;
888 name_max
= pathconf(path
, _PC_NAME_MAX
);
889 if (name_max
== -1) {
892 len
= offsetof(struct dirent
, d_name
) + name_max
+ 1;
893 entry
= zmalloc(len
);
898 enum bt_plugin_status
bt_plugin_create_append_all_from_dir(
899 GPtrArray
*plugins
, const char *path
, bool recurse
)
901 DIR *directory
= NULL
;
902 struct dirent
*entry
= NULL
, *result
= NULL
;
903 char *file_path
= NULL
;
905 enum bt_plugin_status ret
= BT_PLUGIN_STATUS_OK
;
908 ret
= BT_PLUGIN_STATUS_ERROR
;
912 path_len
= strlen(path
);
914 if (path_len
>= PATH_MAX
) {
915 ret
= BT_PLUGIN_STATUS_ERROR
;
919 entry
= alloc_dirent(path
);
921 ret
= BT_PLUGIN_STATUS_ERROR
;
925 file_path
= zmalloc(PATH_MAX
);
927 ret
= BT_PLUGIN_STATUS_NOMEM
;
931 strncpy(file_path
, path
, path_len
);
932 /* Append a trailing '/' to the path */
933 if (file_path
[path_len
- 1] != '/') {
934 file_path
[path_len
++] = '/';
937 directory
= opendir(file_path
);
939 perror("Failed to open plug-in directory");
940 ret
= BT_PLUGIN_STATUS_ERROR
;
944 /* Recursively walk directory */
945 while (!readdir_r(directory
, entry
, &result
) && result
) {
948 size_t file_name_len
;
950 if (result
->d_name
[0] == '.') {
951 /* Skip hidden files, . and .. */
955 file_name_len
= strlen(result
->d_name
);
957 if (path_len
+ file_name_len
>= PATH_MAX
) {
961 strncpy(file_path
+ path_len
, result
->d_name
, file_name_len
);
962 file_path
[path_len
+ file_name_len
] = '\0';
964 stat_ret
= stat(file_path
, &st
);
966 /* Continue to next file / directory. */
967 printf_perror("Failed to stat() plugin file\n");
971 if (S_ISDIR(st
.st_mode
) && recurse
) {
972 ret
= bt_plugin_create_append_all_from_dir(plugins
,
977 } else if (S_ISREG(st
.st_mode
)) {
978 struct bt_plugin
**plugins_from_file
=
979 bt_plugin_create_all_from_file(file_path
);
981 if (plugins_from_file
) {
982 struct bt_plugin
**plugin
;
984 for (plugin
= plugins_from_file
; *plugin
; plugin
++) {
985 /* Transfer ownership to array */
986 g_ptr_array_add(plugins
, *plugin
);
989 free(plugins_from_file
);
995 if (closedir(directory
)) {
997 * We don't want to override the error since there is
1000 perror("Failed to close plug-in directory");
1008 struct bt_plugin
**bt_plugin_create_all_from_dir(const char *path
,
1011 GPtrArray
*plugins_array
= g_ptr_array_new();
1012 struct bt_plugin
**plugins
= NULL
;
1013 enum bt_plugin_status status
;
1015 /* Append found plugins to array */
1016 status
= bt_plugin_create_append_all_from_dir(plugins_array
, path
,
1022 /* Add sentinel to array */
1023 g_ptr_array_add(plugins_array
, NULL
);
1024 plugins
= (struct bt_plugin
**) plugins_array
->pdata
;
1028 if (plugins_array
) {
1029 g_ptr_array_free(plugins_array
, TRUE
);
1030 plugins_array
= NULL
;
1034 if (plugins_array
) {
1035 g_ptr_array_free(plugins_array
, FALSE
);
1041 const char *bt_plugin_get_name(struct bt_plugin
*plugin
)
1043 return plugin
? plugin
->name
: NULL
;
1046 const char *bt_plugin_get_author(struct bt_plugin
*plugin
)
1048 return plugin
? plugin
->author
: NULL
;
1051 const char *bt_plugin_get_license(struct bt_plugin
*plugin
)
1053 return plugin
? plugin
->license
: NULL
;
1056 const char *bt_plugin_get_path(struct bt_plugin
*plugin
)
1058 return (plugin
&& plugin
->shared_lib_handle
->path
) ?
1059 plugin
->shared_lib_handle
->path
->str
: NULL
;
1062 const char *bt_plugin_get_description(struct bt_plugin
*plugin
)
1064 return plugin
? plugin
->description
: NULL
;
1067 enum bt_plugin_status
bt_plugin_get_version(struct bt_plugin
*plugin
,
1068 unsigned int *major
, unsigned int *minor
, unsigned int *patch
,
1071 enum bt_plugin_status status
= BT_PLUGIN_STATUS_OK
;
1073 if (!plugin
|| !plugin
->version
) {
1074 status
= BT_PLUGIN_STATUS_ERROR
;
1079 *major
= (unsigned int) plugin
->version
->major
;
1083 *minor
= (unsigned int) plugin
->version
->minor
;
1087 *patch
= (unsigned int) plugin
->version
->patch
;
1091 *extra
= plugin
->version
->extra
;
1098 int bt_plugin_get_component_class_count(struct bt_plugin
*plugin
)
1100 return plugin
? plugin
->comp_classes
->len
: -1;
1103 struct bt_component_class
*bt_plugin_get_component_class(
1104 struct bt_plugin
*plugin
, size_t index
)
1106 struct bt_component_class
*comp_class
= NULL
;
1108 if (!plugin
|| index
>= plugin
->comp_classes
->len
) {
1112 comp_class
= g_ptr_array_index(plugin
->comp_classes
, index
);
1123 struct bt_component_class
*bt_plugin_get_component_class_by_name_and_type(
1124 struct bt_plugin
*plugin
, const char *name
,
1125 enum bt_component_class_type type
)
1127 struct bt_component_class
*comp_class
= NULL
;
1130 if (!plugin
|| !name
) {
1134 for (i
= 0; i
< plugin
->comp_classes
->len
; i
++) {
1135 struct bt_component_class
*comp_class_candidate
=
1136 g_ptr_array_index(plugin
->comp_classes
, i
);
1137 const char *comp_class_cand_name
=
1138 bt_component_class_get_name(comp_class_candidate
);
1139 enum bt_component_class_type comp_class_cand_type
=
1140 bt_component_class_get_type(comp_class_candidate
);
1142 assert(comp_class_cand_name
);
1143 assert(comp_class_cand_type
>= 0);
1145 if (strcmp(name
, comp_class_cand_name
) == 0 &&
1146 comp_class_cand_type
== type
) {
1147 comp_class
= bt_get(comp_class_candidate
);
1162 void plugin_comp_class_destroy_listener(struct bt_component_class
*comp_class
,
1165 gboolean exists
= g_hash_table_remove(comp_classes_to_shlib_handles
,
1170 enum bt_plugin_status
bt_plugin_add_component_class(
1171 struct bt_plugin
*plugin
, struct bt_component_class
*comp_class
)
1173 enum bt_plugin_status status
= BT_PLUGIN_STATUS_OK
;
1174 struct bt_component_class
*comp_class_dup
= NULL
;
1176 int comp_class_index
= -1;
1178 if (!plugin
|| !comp_class
|| plugin
->frozen
) {
1182 /* Check for duplicate */
1183 comp_class_dup
= bt_plugin_get_component_class_by_name_and_type(plugin
,
1184 bt_component_class_get_name(comp_class
),
1185 bt_component_class_get_type(comp_class
));
1186 if (comp_class_dup
) {
1187 printf_verbose("Plugin `%s`: adding component class with existing name `%s` and type %d\n",
1189 bt_component_class_get_name(comp_class
),
1190 bt_component_class_get_type(comp_class
));
1194 /* Add new component class */
1195 comp_class_index
= plugin
->comp_classes
->len
;
1196 g_ptr_array_add(plugin
->comp_classes
, bt_get(comp_class
));
1198 /* Map component class pointer to shared lib handle in global HT */
1199 g_hash_table_insert(comp_classes_to_shlib_handles
, comp_class
,
1200 bt_get(plugin
->shared_lib_handle
));
1202 /* Add our custom destroy listener */
1203 ret
= bt_component_class_add_destroy_listener(comp_class
,
1204 plugin_comp_class_destroy_listener
, NULL
);
1212 /* Remove entry from global hash table (if exists) */
1213 g_hash_table_remove(comp_classes_to_shlib_handles
,
1216 /* Remove entry from plugin's component classes (if added) */
1217 if (comp_class_index
>= 0) {
1218 g_ptr_array_remove_index(plugin
->comp_classes
,
1222 status
= BT_PLUGIN_STATUS_ERROR
;
1225 bt_put(comp_class_dup
);