4 * Babeltrace Plugin (shared object)
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 #define BT_LOG_TAG "PLUGIN-SO"
31 #include <babeltrace/lib-logging-internal.h>
33 #include <babeltrace/compiler-internal.h>
34 #include <babeltrace/ref.h>
35 #include <babeltrace/plugin/plugin-internal.h>
36 #include <babeltrace/plugin/plugin-so-internal.h>
37 #include <babeltrace/plugin/plugin-dev.h>
38 #include <babeltrace/plugin/plugin-internal.h>
39 #include <babeltrace/graph/component-class-internal.h>
40 #include <babeltrace/types.h>
46 #define NATIVE_PLUGIN_SUFFIX "." G_MODULE_SUFFIX
47 #define NATIVE_PLUGIN_SUFFIX_LEN sizeof(NATIVE_PLUGIN_SUFFIX)
48 #define LIBTOOL_PLUGIN_SUFFIX ".la"
49 #define LIBTOOL_PLUGIN_SUFFIX_LEN sizeof(LIBTOOL_PLUGIN_SUFFIX)
51 #define PLUGIN_SUFFIX_LEN max_t(size_t, sizeof(NATIVE_PLUGIN_SUFFIX), \
52 sizeof(LIBTOOL_PLUGIN_SUFFIX))
54 #define SECTION_BEGIN(_name) (&(__start_##_name))
55 #define SECTION_END(_name) (&(__stop_##_name))
56 #define SECTION_ELEMENT_COUNT(_name) (SECTION_END(_name) - SECTION_BEGIN(_name))
58 #define DECLARE_SECTION(_type, _name) \
59 extern _type __start_##_name __attribute((weak)); \
60 extern _type __stop_##_name __attribute((weak))
62 DECLARE_SECTION(struct __bt_plugin_descriptor
const *, __bt_plugin_descriptors
);
63 DECLARE_SECTION(struct __bt_plugin_descriptor_attribute
const *, __bt_plugin_descriptor_attributes
);
64 DECLARE_SECTION(struct __bt_plugin_component_class_descriptor
const *, __bt_plugin_component_class_descriptors
);
65 DECLARE_SECTION(struct __bt_plugin_component_class_descriptor_attribute
const *, __bt_plugin_component_class_descriptor_attributes
);
68 * This hash table, global to the library, maps component class pointers
69 * to shared library handles.
71 * The keys (component classes) are NOT owned by this hash table, whereas
72 * the values (shared library handles) are owned by this hash table.
74 * The keys are the component classes created with
75 * bt_plugin_add_component_class(). They keep the shared library handle
76 * object created by their plugin alive so that the plugin's code is
77 * not discarded when it could still be in use by living components
78 * created from those component classes:
80 * [component] --ref-> [component class] --through this HT-> [shlib handle]
82 * This hash table exists for two reasons:
84 * 1. To allow this application:
86 * my_plugins = bt_plugin_create_all_from_file("/path/to/my-plugin.so");
87 * // instantiate components from a plugin's component classes
88 * // put plugins and free my_plugins here
89 * // user code of instantiated components still exists
91 * 2. To decouple the plugin subsystem from the component subsystem:
92 * while plugins objects need to know component class objects, the
93 * opposite is not necessary, thus it makes no sense for a component
94 * class to keep a reference to the plugin object from which it was
97 * An entry is removed from this HT when a component class is destroyed
98 * thanks to a custom destroy listener. When the entry is removed, the
99 * GLib function calls the value destroy notifier of the HT, which is
100 * bt_put(). This decreases the reference count of the mapped shared
101 * library handle. Assuming the original plugin object which contained
102 * some component classes is put first, when the last component class is
103 * removed from this HT, the shared library handle object's reference
104 * count falls to zero and the shared library is finally closed.
107 GHashTable
*comp_classes_to_shlib_handles
;
109 __attribute__((constructor
)) static
110 void init_comp_classes_to_shlib_handles(void) {
111 comp_classes_to_shlib_handles
= g_hash_table_new_full(g_direct_hash
,
112 g_direct_equal
, NULL
, bt_put
);
113 assert(comp_classes_to_shlib_handles
);
114 BT_LOGD_STR("Initialized component class to shared library handle hash table.");
117 __attribute__((destructor
)) static
118 void fini_comp_classes_to_shlib_handles(void) {
119 if (comp_classes_to_shlib_handles
) {
120 g_hash_table_destroy(comp_classes_to_shlib_handles
);
121 BT_LOGD_STR("Destroyed component class to shared library handle hash table.");
126 void bt_plugin_so_shared_lib_handle_destroy(struct bt_object
*obj
)
128 struct bt_plugin_so_shared_lib_handle
*shared_lib_handle
;
131 shared_lib_handle
= container_of(obj
,
132 struct bt_plugin_so_shared_lib_handle
, base
);
133 const char *path
= shared_lib_handle
->path
?
134 shared_lib_handle
->path
->str
: NULL
;
136 BT_LOGD("Destroying shared library handle: addr=%p, path=\"%s\"",
137 shared_lib_handle
, path
);
139 if (shared_lib_handle
->init_called
&& shared_lib_handle
->exit
) {
140 enum bt_plugin_status status
;
142 BT_LOGD_STR("Calling user's plugin exit function.");
143 status
= shared_lib_handle
->exit();
144 BT_LOGD("User function returned: %s",
145 bt_plugin_status_string(status
));
148 BT_LOGW("User's plugin exit function failed: "
149 "path=\"%s\"", path
);
153 if (shared_lib_handle
->module
) {
156 * Valgrind shows incomplete stack traces when
157 * dynamically loaded libraries are closed before it
158 * finishes. Use the BABELTRACE_NO_DLCLOSE in a debug
159 * build to avoid this.
161 const char *var
= getenv("BABELTRACE_NO_DLCLOSE");
163 if (!var
|| strcmp(var
, "1") != 0) {
165 BT_LOGD("Closing GModule: path=\"%s\"", path
);
167 if (!g_module_close(shared_lib_handle
->module
)) {
168 BT_LOGE("Cannot close GModule: %s: path=\"%s\"",
169 g_module_error(), path
);
173 BT_LOGD("Not closing GModule because `BABELTRACE_NO_DLCLOSE=1`: "
174 "path=\"%s\"", path
);
179 if (shared_lib_handle
->path
) {
180 g_string_free(shared_lib_handle
->path
, TRUE
);
183 g_free(shared_lib_handle
);
187 struct bt_plugin_so_shared_lib_handle
*bt_plugin_so_shared_lib_handle_create(
190 struct bt_plugin_so_shared_lib_handle
*shared_lib_handle
= NULL
;
192 BT_LOGD("Creating shared library handle: path=\"%s\"", path
);
193 shared_lib_handle
= g_new0(struct bt_plugin_so_shared_lib_handle
, 1);
194 if (!shared_lib_handle
) {
195 BT_LOGE_STR("Failed to allocate one shared library handle.");
199 bt_object_init(shared_lib_handle
, bt_plugin_so_shared_lib_handle_destroy
);
205 shared_lib_handle
->path
= g_string_new(path
);
206 if (!shared_lib_handle
->path
) {
207 BT_LOGE_STR("Failed to allocate a GString.");
211 shared_lib_handle
->module
= g_module_open(path
, 0);
212 if (!shared_lib_handle
->module
) {
214 * DEBUG-level logging because we're only _trying_ to
215 * open this file as a Babeltrace plugin: if it's not,
216 * it's not an error. And because this can be tried
217 * during bt_plugin_create_all_from_dir(), it's not even
220 BT_LOGD("Cannot open GModule: %s: path=\"%s\"",
221 g_module_error(), path
);
228 BT_PUT(shared_lib_handle
);
231 if (shared_lib_handle
) {
232 BT_LOGD("Created shared library handle: path=\"%s\", addr=%p",
233 path
, shared_lib_handle
);
236 return shared_lib_handle
;
240 void bt_plugin_so_destroy_spec_data(struct bt_plugin
*plugin
)
242 struct bt_plugin_so_spec_data
*spec
= plugin
->spec_data
;
244 if (!plugin
->spec_data
) {
248 assert(plugin
->type
== BT_PLUGIN_TYPE_SO
);
250 BT_PUT(spec
->shared_lib_handle
);
251 g_free(plugin
->spec_data
);
252 plugin
->spec_data
= NULL
;
256 * This function does the following:
258 * 1. Iterate on the plugin descriptor attributes section and set the
259 * plugin's attributes depending on the attribute types. This
260 * includes the name of the plugin, its description, and its
261 * initialization function, for example.
263 * 2. Iterate on the component class descriptors section and create one
264 * "full descriptor" (temporary structure) for each one that is found
265 * and attached to our plugin descriptor.
267 * 3. Iterate on the component class descriptor attributes section and
268 * set the corresponding full descriptor's attributes depending on
269 * the attribute types. This includes the description of the
270 * component class, as well as its initialization and destroy
273 * 4. Call the user's plugin initialization function, if any is
276 * 5. For each full component class descriptor, create a component class
277 * object, set its optional attributes, and add it to the plugin
280 * 6. Freeze the plugin object.
283 enum bt_plugin_status
bt_plugin_so_init(
284 struct bt_plugin
*plugin
,
285 const struct __bt_plugin_descriptor
*descriptor
,
286 struct __bt_plugin_descriptor_attribute
const * const *attrs_begin
,
287 struct __bt_plugin_descriptor_attribute
const * const *attrs_end
,
288 struct __bt_plugin_component_class_descriptor
const * const *cc_descriptors_begin
,
289 struct __bt_plugin_component_class_descriptor
const * const *cc_descriptors_end
,
290 struct __bt_plugin_component_class_descriptor_attribute
const * const *cc_descr_attrs_begin
,
291 struct __bt_plugin_component_class_descriptor_attribute
const * const *cc_descr_attrs_end
)
294 * This structure's members point to the plugin's memory
297 struct comp_class_full_descriptor
{
298 const struct __bt_plugin_component_class_descriptor
*descriptor
;
299 const char *description
;
301 bt_component_class_init_method init_method
;
302 bt_component_class_finalize_method finalize_method
;
303 bt_component_class_query_method query_method
;
304 bt_component_class_accept_port_connection_method accept_port_connection_method
;
305 bt_component_class_port_connected_method port_connected_method
;
306 bt_component_class_port_disconnected_method port_disconnected_method
;
307 struct bt_component_class_iterator_methods iterator_methods
;
310 enum bt_plugin_status status
= BT_PLUGIN_STATUS_OK
;
311 struct __bt_plugin_descriptor_attribute
const * const *cur_attr_ptr
;
312 struct __bt_plugin_component_class_descriptor
const * const *cur_cc_descr_ptr
;
313 struct __bt_plugin_component_class_descriptor_attribute
const * const *cur_cc_descr_attr_ptr
;
314 struct bt_plugin_so_spec_data
*spec
= plugin
->spec_data
;
315 GArray
*comp_class_full_descriptors
;
319 BT_LOGD("Initializing plugin object from descriptors found in sections: "
320 "plugin-addr=%p, plugin-path=\"%s\", "
321 "attrs-begin-addr=%p, attrs-end-addr=%p, "
322 "cc-descr-begin-addr=%p, cc-descr-end-addr=%p, "
323 "cc-descr-attrs-begin-addr=%p, cc-descr-attrs-end-addr=%p",
325 spec
->shared_lib_handle
->path
?
326 spec
->shared_lib_handle
->path
->str
: NULL
,
327 attrs_begin
, attrs_end
,
328 cc_descriptors_begin
, cc_descriptors_end
,
329 cc_descr_attrs_begin
, cc_descr_attrs_end
);
330 comp_class_full_descriptors
= g_array_new(FALSE
, TRUE
,
331 sizeof(struct comp_class_full_descriptor
));
332 if (!comp_class_full_descriptors
) {
333 BT_LOGE_STR("Failed to allocate a GArray.");
334 status
= BT_PLUGIN_STATUS_ERROR
;
338 /* Set mandatory attributes */
339 spec
->descriptor
= descriptor
;
340 bt_plugin_set_name(plugin
, descriptor
->name
);
343 * Find and set optional attributes attached to this plugin
346 for (cur_attr_ptr
= attrs_begin
; cur_attr_ptr
!= attrs_end
; cur_attr_ptr
++) {
347 const struct __bt_plugin_descriptor_attribute
*cur_attr
=
350 if (cur_attr
->plugin_descriptor
!= descriptor
) {
354 switch (cur_attr
->type
) {
355 case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_INIT
:
356 spec
->init
= cur_attr
->value
.init
;
358 case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_EXIT
:
359 spec
->shared_lib_handle
->exit
= cur_attr
->value
.exit
;
361 case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_AUTHOR
:
362 bt_plugin_set_author(plugin
, cur_attr
->value
.author
);
364 case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_LICENSE
:
365 bt_plugin_set_license(plugin
, cur_attr
->value
.license
);
367 case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_DESCRIPTION
:
368 bt_plugin_set_description(plugin
, cur_attr
->value
.description
);
370 case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_VERSION
:
371 bt_plugin_set_version(plugin
,
372 (unsigned int) cur_attr
->value
.version
.major
,
373 (unsigned int) cur_attr
->value
.version
.minor
,
374 (unsigned int) cur_attr
->value
.version
.patch
,
375 cur_attr
->value
.version
.extra
);
379 * WARN-level logging because this should not
380 * happen with the appropriate ABI version. If
381 * we're here, we know that for the reported
382 * version of the ABI, this attribute is
385 BT_LOGW("Ignoring unknown plugin descriptor attribute: "
386 "plugin-path=\"%s\", plugin-name=\"%s\", "
387 "attr-type-name=\"%s\", attr-type-id=%d",
388 spec
->shared_lib_handle
->path
?
389 spec
->shared_lib_handle
->path
->str
:
391 descriptor
->name
, cur_attr
->type_name
,
398 * Find component class descriptors attached to this plugin
399 * descriptor and initialize corresponding full component class
400 * descriptors in the array.
402 for (cur_cc_descr_ptr
= cc_descriptors_begin
; cur_cc_descr_ptr
!= cc_descriptors_end
; cur_cc_descr_ptr
++) {
403 const struct __bt_plugin_component_class_descriptor
*cur_cc_descr
=
405 struct comp_class_full_descriptor full_descriptor
= {0};
407 if (cur_cc_descr
->plugin_descriptor
!= descriptor
) {
411 full_descriptor
.descriptor
= cur_cc_descr
;
412 g_array_append_val(comp_class_full_descriptors
,
417 * Find component class descriptor attributes attached to this
418 * plugin descriptor and update corresponding full component
419 * class descriptors in the array.
421 for (cur_cc_descr_attr_ptr
= cc_descr_attrs_begin
; cur_cc_descr_attr_ptr
!= cc_descr_attrs_end
; cur_cc_descr_attr_ptr
++) {
422 const struct __bt_plugin_component_class_descriptor_attribute
*cur_cc_descr_attr
=
423 *cur_cc_descr_attr_ptr
;
425 if (cur_cc_descr_attr
->comp_class_descriptor
->plugin_descriptor
!=
430 /* Find the corresponding component class descriptor entry */
431 for (i
= 0; i
< comp_class_full_descriptors
->len
; i
++) {
432 struct comp_class_full_descriptor
*cc_full_descr
=
433 &g_array_index(comp_class_full_descriptors
,
434 struct comp_class_full_descriptor
, i
);
436 if (cur_cc_descr_attr
->comp_class_descriptor
==
437 cc_full_descr
->descriptor
) {
438 switch (cur_cc_descr_attr
->type
) {
439 case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_DESCRIPTION
:
440 cc_full_descr
->description
=
441 cur_cc_descr_attr
->value
.description
;
443 case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_HELP
:
444 cc_full_descr
->help
=
445 cur_cc_descr_attr
->value
.help
;
447 case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_INIT_METHOD
:
448 cc_full_descr
->init_method
=
449 cur_cc_descr_attr
->value
.init_method
;
451 case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_FINALIZE_METHOD
:
452 cc_full_descr
->finalize_method
=
453 cur_cc_descr_attr
->value
.finalize_method
;
455 case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_QUERY_METHOD
:
456 cc_full_descr
->query_method
=
457 cur_cc_descr_attr
->value
.query_method
;
459 case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_ACCEPT_PORT_CONNECTION_METHOD
:
460 cc_full_descr
->accept_port_connection_method
=
461 cur_cc_descr_attr
->value
.accept_port_connection_method
;
463 case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_PORT_CONNECTED_METHOD
:
464 cc_full_descr
->port_connected_method
=
465 cur_cc_descr_attr
->value
.port_connected_method
;
467 case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_PORT_DISCONNECTED_METHOD
:
468 cc_full_descr
->port_disconnected_method
=
469 cur_cc_descr_attr
->value
.port_disconnected_method
;
471 case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_NOTIF_ITER_INIT_METHOD
:
472 cc_full_descr
->iterator_methods
.init
=
473 cur_cc_descr_attr
->value
.notif_iter_init_method
;
475 case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_NOTIF_ITER_FINALIZE_METHOD
:
476 cc_full_descr
->iterator_methods
.finalize
=
477 cur_cc_descr_attr
->value
.notif_iter_finalize_method
;
479 case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_NOTIF_ITER_SEEK_TIME_METHOD
:
480 cc_full_descr
->iterator_methods
.seek_time
=
481 cur_cc_descr_attr
->value
.notif_iter_seek_time_method
;
485 * WARN-level logging because
486 * this should not happen with
487 * the appropriate ABI version.
488 * If we're here, we know that
489 * for the reported version of
490 * the ABI, this attribute is
493 BT_LOGW("Ignoring unknown component class descriptor attribute: "
494 "plugin-path=\"%s\", "
495 "plugin-name=\"%s\", "
496 "comp-class-name=\"%s\", "
497 "comp-class-type=%s, "
498 "attr-type-name=\"%s\", "
500 spec
->shared_lib_handle
->path
?
501 spec
->shared_lib_handle
->path
->str
:
504 cur_cc_descr_attr
->comp_class_descriptor
->name
,
505 bt_component_class_type_string(
506 cur_cc_descr_attr
->comp_class_descriptor
->type
),
507 cur_cc_descr_attr
->type_name
,
508 cur_cc_descr_attr
->type
);
515 /* Initialize plugin */
517 BT_LOGD_STR("Calling user's plugin initialization function.");
518 status
= spec
->init(plugin
);
519 BT_LOGD("User function returned: %s",
520 bt_plugin_status_string(status
));
523 BT_LOGW_STR("User's plugin initialization function failed.");
528 spec
->shared_lib_handle
->init_called
= BT_TRUE
;
530 /* Add described component classes to plugin */
531 for (i
= 0; i
< comp_class_full_descriptors
->len
; i
++) {
532 struct comp_class_full_descriptor
*cc_full_descr
=
533 &g_array_index(comp_class_full_descriptors
,
534 struct comp_class_full_descriptor
, i
);
535 struct bt_component_class
*comp_class
;
537 BT_LOGD("Creating and setting properties of plugin's component class: "
538 "plugin-path=\"%s\", plugin-name=\"%s\", "
539 "comp-class-name=\"%s\", comp-class-type=%s",
540 spec
->shared_lib_handle
->path
?
541 spec
->shared_lib_handle
->path
->str
:
544 cc_full_descr
->descriptor
->name
,
545 bt_component_class_type_string(
546 cc_full_descr
->descriptor
->type
));
548 switch (cc_full_descr
->descriptor
->type
) {
549 case BT_COMPONENT_CLASS_TYPE_SOURCE
:
550 comp_class
= bt_component_class_source_create(
551 cc_full_descr
->descriptor
->name
,
552 cc_full_descr
->descriptor
->methods
.source
.notif_iter_next
);
554 case BT_COMPONENT_CLASS_TYPE_FILTER
:
555 comp_class
= bt_component_class_filter_create(
556 cc_full_descr
->descriptor
->name
,
557 cc_full_descr
->descriptor
->methods
.source
.notif_iter_next
);
559 case BT_COMPONENT_CLASS_TYPE_SINK
:
560 comp_class
= bt_component_class_sink_create(
561 cc_full_descr
->descriptor
->name
,
562 cc_full_descr
->descriptor
->methods
.sink
.consume
);
566 * WARN-level logging because this should not
567 * happen with the appropriate ABI version. If
568 * we're here, we know that for the reported
569 * version of the ABI, this component class type
572 BT_LOGW("Ignoring unknown component class type: "
573 "plugin-path=\"%s\", plugin-name=\"%s\", "
574 "comp-class-name=\"%s\", comp-class-type=%d",
575 spec
->shared_lib_handle
->path
->str
?
576 spec
->shared_lib_handle
->path
->str
:
579 cc_full_descr
->descriptor
->name
,
580 cc_full_descr
->descriptor
->type
);
585 BT_LOGE_STR("Cannot create component class.");
586 status
= BT_PLUGIN_STATUS_ERROR
;
590 if (cc_full_descr
->description
) {
591 ret
= bt_component_class_set_description(comp_class
,
592 cc_full_descr
->description
);
594 BT_LOGE_STR("Cannot set component class's description.");
595 status
= BT_PLUGIN_STATUS_ERROR
;
601 if (cc_full_descr
->help
) {
602 ret
= bt_component_class_set_help(comp_class
,
603 cc_full_descr
->help
);
605 BT_LOGE_STR("Cannot set component class's help string.");
606 status
= BT_PLUGIN_STATUS_ERROR
;
612 if (cc_full_descr
->init_method
) {
613 ret
= bt_component_class_set_init_method(comp_class
,
614 cc_full_descr
->init_method
);
616 BT_LOGE_STR("Cannot set component class's initialization method.");
617 status
= BT_PLUGIN_STATUS_ERROR
;
623 if (cc_full_descr
->finalize_method
) {
624 ret
= bt_component_class_set_finalize_method(comp_class
,
625 cc_full_descr
->finalize_method
);
627 BT_LOGE_STR("Cannot set component class's finalization method.");
628 status
= BT_PLUGIN_STATUS_ERROR
;
634 if (cc_full_descr
->query_method
) {
635 ret
= bt_component_class_set_query_method(
636 comp_class
, cc_full_descr
->query_method
);
638 BT_LOGE_STR("Cannot set component class's query method.");
639 status
= BT_PLUGIN_STATUS_ERROR
;
645 if (cc_full_descr
->accept_port_connection_method
) {
646 ret
= bt_component_class_set_accept_port_connection_method(
647 comp_class
, cc_full_descr
->accept_port_connection_method
);
649 BT_LOGE_STR("Cannot set component class's \"accept port connection\" method.");
650 status
= BT_PLUGIN_STATUS_ERROR
;
656 if (cc_full_descr
->port_connected_method
) {
657 ret
= bt_component_class_set_port_connected_method(
658 comp_class
, cc_full_descr
->port_connected_method
);
660 BT_LOGE_STR("Cannot set component class's \"port connected\" method.");
661 status
= BT_PLUGIN_STATUS_ERROR
;
667 if (cc_full_descr
->port_disconnected_method
) {
668 ret
= bt_component_class_set_port_disconnected_method(
669 comp_class
, cc_full_descr
->port_disconnected_method
);
671 BT_LOGE_STR("Cannot set component class's \"port disconnected\" method.");
672 status
= BT_PLUGIN_STATUS_ERROR
;
678 switch (cc_full_descr
->descriptor
->type
) {
679 case BT_COMPONENT_CLASS_TYPE_SOURCE
:
680 if (cc_full_descr
->iterator_methods
.init
) {
681 ret
= bt_component_class_source_set_notification_iterator_init_method(
683 cc_full_descr
->iterator_methods
.init
);
685 BT_LOGE_STR("Cannot set component class's notification iterator initialization method.");
686 status
= BT_PLUGIN_STATUS_ERROR
;
692 if (cc_full_descr
->iterator_methods
.finalize
) {
693 ret
= bt_component_class_source_set_notification_iterator_finalize_method(
695 cc_full_descr
->iterator_methods
.finalize
);
697 BT_LOGE_STR("Cannot set source component class's notification iterator finalization method.");
698 status
= BT_PLUGIN_STATUS_ERROR
;
704 if (cc_full_descr
->iterator_methods
.seek_time
) {
705 ret
= bt_component_class_source_set_notification_iterator_seek_time_method(
707 cc_full_descr
->iterator_methods
.seek_time
);
709 BT_LOGE_STR("Cannot set source component class's notification iterator seek to time method.");
710 status
= BT_PLUGIN_STATUS_ERROR
;
716 case BT_COMPONENT_CLASS_TYPE_FILTER
:
717 if (cc_full_descr
->iterator_methods
.init
) {
718 ret
= bt_component_class_filter_set_notification_iterator_init_method(
720 cc_full_descr
->iterator_methods
.init
);
722 BT_LOGE_STR("Cannot set filter component class's notification iterator initialization method.");
723 status
= BT_PLUGIN_STATUS_ERROR
;
729 if (cc_full_descr
->iterator_methods
.finalize
) {
730 ret
= bt_component_class_filter_set_notification_iterator_finalize_method(
732 cc_full_descr
->iterator_methods
.finalize
);
734 BT_LOGE_STR("Cannot set filter component class's notification iterator finalization method.");
735 status
= BT_PLUGIN_STATUS_ERROR
;
741 if (cc_full_descr
->iterator_methods
.seek_time
) {
742 ret
= bt_component_class_filter_set_notification_iterator_seek_time_method(
744 cc_full_descr
->iterator_methods
.seek_time
);
746 BT_LOGE_STR("Cannot set filter component class's notification iterator seek to time method.");
747 status
= BT_PLUGIN_STATUS_ERROR
;
753 case BT_COMPONENT_CLASS_TYPE_SINK
:
760 * Add component class to the plugin object.
762 * This will call back
763 * bt_plugin_so_on_add_component_class() so that we can
764 * add a mapping in comp_classes_to_shlib_handles when
765 * we know the component class is successfully added.
767 status
= bt_plugin_add_component_class(plugin
,
771 BT_LOGE("Cannot add component class to plugin.");
777 * All the plugin's component classes should be added at this
778 * point. We freeze the plugin so that it's not possible to add
779 * component classes to this plugin object after this stage
780 * (plugin object becomes immutable).
782 bt_plugin_freeze(plugin
);
785 g_array_free(comp_class_full_descriptors
, TRUE
);
790 struct bt_plugin
*bt_plugin_so_create_empty(
791 struct bt_plugin_so_shared_lib_handle
*shared_lib_handle
)
793 struct bt_plugin
*plugin
;
794 struct bt_plugin_so_spec_data
*spec
;
796 plugin
= bt_plugin_create_empty(BT_PLUGIN_TYPE_SO
);
801 plugin
->destroy_spec_data
= bt_plugin_so_destroy_spec_data
;
802 plugin
->spec_data
= g_new0(struct bt_plugin_so_spec_data
, 1);
803 if (!plugin
->spec_data
) {
804 BT_LOGE_STR("Failed to allocate one SO plugin specific data structure.");
808 spec
= plugin
->spec_data
;
809 spec
->shared_lib_handle
= bt_get(shared_lib_handle
);
820 struct bt_plugin_set
*bt_plugin_so_create_all_from_sections(
821 struct bt_plugin_so_shared_lib_handle
*shared_lib_handle
,
822 struct __bt_plugin_descriptor
const * const *descriptors_begin
,
823 struct __bt_plugin_descriptor
const * const *descriptors_end
,
824 struct __bt_plugin_descriptor_attribute
const * const *attrs_begin
,
825 struct __bt_plugin_descriptor_attribute
const * const *attrs_end
,
826 struct __bt_plugin_component_class_descriptor
const * const *cc_descriptors_begin
,
827 struct __bt_plugin_component_class_descriptor
const * const *cc_descriptors_end
,
828 struct __bt_plugin_component_class_descriptor_attribute
const * const *cc_descr_attrs_begin
,
829 struct __bt_plugin_component_class_descriptor_attribute
const * const *cc_descr_attrs_end
)
831 size_t descriptor_count
;
833 size_t cc_descriptors_count
;
834 size_t cc_descr_attrs_count
;
836 struct bt_plugin_set
*plugin_set
= NULL
;
838 descriptor_count
= descriptors_end
- descriptors_begin
;
839 attrs_count
= attrs_end
- attrs_begin
;
840 cc_descriptors_count
= cc_descriptors_end
- cc_descriptors_begin
;
841 cc_descr_attrs_count
= cc_descr_attrs_end
- cc_descr_attrs_begin
;
843 BT_LOGD("Creating all SO plugins from sections: "
844 "plugin-path=\"%s\", "
845 "descr-begin-addr=%p, descr-end-addr=%p, "
846 "attrs-begin-addr=%p, attrs-end-addr=%p, "
847 "cc-descr-begin-addr=%p, cc-descr-end-addr=%p, "
848 "cc-descr-attrs-begin-addr=%p, cc-descr-attrs-end-addr=%p, "
849 "descr-count=%zu, attrs-count=%zu, "
850 "cc-descr-count=%zu, cc-descr-attrs-count=%zu",
851 shared_lib_handle
->path
? shared_lib_handle
->path
->str
: NULL
,
852 descriptors_begin
, descriptors_end
,
853 attrs_begin
, attrs_end
,
854 cc_descriptors_begin
, cc_descriptors_end
,
855 cc_descr_attrs_begin
, cc_descr_attrs_end
,
856 descriptor_count
, attrs_count
,
857 cc_descriptors_count
, cc_descr_attrs_count
);
858 plugin_set
= bt_plugin_set_create();
860 BT_LOGE_STR("Cannot create empty plugin set.");
864 for (i
= 0; i
< descriptor_count
; i
++) {
865 enum bt_plugin_status status
;
866 const struct __bt_plugin_descriptor
*descriptor
=
867 descriptors_begin
[i
];
868 struct bt_plugin
*plugin
;
870 BT_LOGD("Creating plugin object for plugin: "
871 "name=\"%s\", abi-major=%d, abi-minor=%d",
872 descriptor
->name
, descriptor
->major
, descriptor
->minor
);
874 if (descriptor
->major
> __BT_PLUGIN_VERSION_MAJOR
) {
876 * DEBUG-level logging because we're only
877 * _trying_ to open this file as a compatible
878 * Babeltrace plugin: if it's not, it's not an
879 * error. And because this can be tried during
880 * bt_plugin_create_all_from_dir(), it's not
883 BT_LOGD("Unknown ABI major version: abi-major=%d",
888 plugin
= bt_plugin_so_create_empty(shared_lib_handle
);
890 BT_LOGE_STR("Cannot create empty shared library handle.");
894 if (shared_lib_handle
&& shared_lib_handle
->path
) {
895 bt_plugin_set_path(plugin
, shared_lib_handle
->path
->str
);
898 status
= bt_plugin_so_init(plugin
, descriptor
, attrs_begin
,
899 attrs_end
, cc_descriptors_begin
, cc_descriptors_end
,
900 cc_descr_attrs_begin
, cc_descr_attrs_end
);
903 * DEBUG-level logging because we're only
904 * _trying_ to open this file as a compatible
905 * Babeltrace plugin: if it's not, it's not an
906 * error. And because this can be tried during
907 * bt_plugin_create_all_from_dir(), it's not
910 BT_LOGD_STR("Cannot initialize SO plugin object from sections.");
915 /* Add to plugin set */
916 bt_plugin_set_add_plugin(plugin_set
, plugin
);
930 struct bt_plugin_set
*bt_plugin_so_create_all_from_static(void)
932 struct bt_plugin_set
*plugin_set
= NULL
;
933 struct bt_plugin_so_shared_lib_handle
*shared_lib_handle
=
934 bt_plugin_so_shared_lib_handle_create(NULL
);
936 if (!shared_lib_handle
) {
940 BT_LOGD_STR("Creating all SO plugins from built-in plugins.");
941 plugin_set
= bt_plugin_so_create_all_from_sections(shared_lib_handle
,
942 SECTION_BEGIN(__bt_plugin_descriptors
),
943 SECTION_END(__bt_plugin_descriptors
),
944 SECTION_BEGIN(__bt_plugin_descriptor_attributes
),
945 SECTION_END(__bt_plugin_descriptor_attributes
),
946 SECTION_BEGIN(__bt_plugin_component_class_descriptors
),
947 SECTION_END(__bt_plugin_component_class_descriptors
),
948 SECTION_BEGIN(__bt_plugin_component_class_descriptor_attributes
),
949 SECTION_END(__bt_plugin_component_class_descriptor_attributes
));
952 BT_PUT(shared_lib_handle
);
958 struct bt_plugin_set
*bt_plugin_so_create_all_from_file(const char *path
)
961 struct bt_plugin_set
*plugin_set
= NULL
;
962 struct __bt_plugin_descriptor
const * const *descriptors_begin
= NULL
;
963 struct __bt_plugin_descriptor
const * const *descriptors_end
= NULL
;
964 struct __bt_plugin_descriptor_attribute
const * const *attrs_begin
= NULL
;
965 struct __bt_plugin_descriptor_attribute
const * const *attrs_end
= NULL
;
966 struct __bt_plugin_component_class_descriptor
const * const *cc_descriptors_begin
= NULL
;
967 struct __bt_plugin_component_class_descriptor
const * const *cc_descriptors_end
= NULL
;
968 struct __bt_plugin_component_class_descriptor_attribute
const * const *cc_descr_attrs_begin
= NULL
;
969 struct __bt_plugin_component_class_descriptor_attribute
const * const *cc_descr_attrs_end
= NULL
;
970 bt_bool is_libtool_wrapper
= BT_FALSE
, is_shared_object
= BT_FALSE
;
971 struct bt_plugin_so_shared_lib_handle
*shared_lib_handle
= NULL
;
974 BT_LOGW_STR("Invalid parameter: path is NULL.");
978 BT_LOGD("Creating all SO plugins from file: path=\"%s\"", path
);
979 path_len
= strlen(path
);
980 if (path_len
<= PLUGIN_SUFFIX_LEN
) {
981 BT_LOGW("Invalid parameter: path length is too short: "
982 "path-length=%zu", path_len
);
988 * Check if the file ends with a known plugin file type suffix (i.e. .so
991 is_libtool_wrapper
= !strncmp(LIBTOOL_PLUGIN_SUFFIX
,
992 path
+ path_len
- LIBTOOL_PLUGIN_SUFFIX_LEN
,
993 LIBTOOL_PLUGIN_SUFFIX_LEN
);
994 is_shared_object
= !strncmp(NATIVE_PLUGIN_SUFFIX
,
995 path
+ path_len
- NATIVE_PLUGIN_SUFFIX_LEN
,
996 NATIVE_PLUGIN_SUFFIX_LEN
);
997 if (!is_shared_object
&& !is_libtool_wrapper
) {
998 /* Name indicates this is not a plugin file; not an error */
999 BT_LOGV("File is not a SO plugin file: path=\"%s\"", path
);
1003 shared_lib_handle
= bt_plugin_so_shared_lib_handle_create(path
);
1004 if (!shared_lib_handle
) {
1005 BT_LOGD_STR("Cannot create shared library handle.");
1009 if (!g_module_symbol(shared_lib_handle
->module
, "__start___bt_plugin_descriptors",
1010 (gpointer
*) &descriptors_begin
)) {
1011 BT_LOGD("Cannot resolve plugin symbol: path=\"%s\", "
1012 "symbol=\"%s\"", path
,
1013 "__start___bt_plugin_descriptors");
1017 if (!g_module_symbol(shared_lib_handle
->module
, "__stop___bt_plugin_descriptors",
1018 (gpointer
*) &descriptors_end
)) {
1019 BT_LOGD("Cannot resolve plugin symbol: path=\"%s\", "
1020 "symbol=\"%s\"", path
,
1021 "__stop___bt_plugin_descriptors");
1025 if (!g_module_symbol(shared_lib_handle
->module
, "__start___bt_plugin_descriptor_attributes",
1026 (gpointer
*) &attrs_begin
)) {
1027 BT_LOGD("Cannot resolve plugin symbol: path=\"%s\", "
1028 "symbol=\"%s\"", path
,
1029 "__start___bt_plugin_descriptor_attributes");
1032 if (!g_module_symbol(shared_lib_handle
->module
, "__stop___bt_plugin_descriptor_attributes",
1033 (gpointer
*) &attrs_end
)) {
1034 BT_LOGD("Cannot resolve plugin symbol: path=\"%s\", "
1035 "symbol=\"%s\"", path
,
1036 "__stop___bt_plugin_descriptor_attributes");
1039 if ((!!attrs_begin
- !!attrs_end
) != 0) {
1040 BT_LOGD("Found section start or end symbol, but not both: "
1041 "path=\"%s\", symbol-start=\"%s\", "
1042 "symbol-end=\"%s\", symbol-start-addr=%p, "
1043 "symbol-end-addr=%p",
1044 path
, "__start___bt_plugin_descriptor_attributes",
1045 "__stop___bt_plugin_descriptor_attributes",
1046 attrs_begin
, attrs_end
);
1050 if (!g_module_symbol(shared_lib_handle
->module
, "__start___bt_plugin_component_class_descriptors",
1051 (gpointer
*) &cc_descriptors_begin
)) {
1052 BT_LOGD("Cannot resolve plugin symbol: path=\"%s\", "
1053 "symbol=\"%s\"", path
,
1054 "__start___bt_plugin_component_class_descriptors");
1057 if (!g_module_symbol(shared_lib_handle
->module
, "__stop___bt_plugin_component_class_descriptors",
1058 (gpointer
*) &cc_descriptors_end
)) {
1059 BT_LOGD("Cannot resolve plugin symbol: path=\"%s\", "
1060 "symbol=\"%s\"", path
,
1061 "__stop___bt_plugin_component_class_descriptors");
1064 if ((!!cc_descriptors_begin
- !!cc_descriptors_end
) != 0) {
1065 BT_LOGD("Found section start or end symbol, but not both: "
1066 "path=\"%s\", symbol-start=\"%s\", "
1067 "symbol-end=\"%s\", symbol-start-addr=%p, "
1068 "symbol-end-addr=%p",
1069 path
, "__start___bt_plugin_component_class_descriptors",
1070 "__stop___bt_plugin_component_class_descriptors",
1071 cc_descriptors_begin
, cc_descriptors_end
);
1075 if (!g_module_symbol(shared_lib_handle
->module
, "__start___bt_plugin_component_class_descriptor_attributes",
1076 (gpointer
*) &cc_descr_attrs_begin
)) {
1077 BT_LOGD("Cannot resolve plugin symbol: path=\"%s\", "
1078 "symbol=\"%s\"", path
,
1079 "__start___bt_plugin_component_class_descriptor_attributes");
1082 if (!g_module_symbol(shared_lib_handle
->module
, "__stop___bt_plugin_component_class_descriptor_attributes",
1083 (gpointer
*) &cc_descr_attrs_end
)) {
1084 BT_LOGD("Cannot resolve plugin symbol: path=\"%s\", "
1085 "symbol=\"%s\"", path
,
1086 "__stop___bt_plugin_component_class_descriptor_attributes");
1089 if ((!!cc_descr_attrs_begin
- !!cc_descr_attrs_end
) != 0) {
1090 BT_LOGD("Found section start or end symbol, but not both: "
1091 "path=\"%s\", symbol-start=\"%s\", "
1092 "symbol-end=\"%s\", symbol-start-addr=%p, "
1093 "symbol-end-addr=%p",
1094 path
, "__start___bt_plugin_component_class_descriptor_attributes",
1095 "__stop___bt_plugin_component_class_descriptor_attributes",
1096 cc_descr_attrs_begin
, cc_descr_attrs_end
);
1100 /* Initialize plugin */
1101 BT_LOGD_STR("Initializing plugin object.");
1102 plugin_set
= bt_plugin_so_create_all_from_sections(shared_lib_handle
,
1103 descriptors_begin
, descriptors_end
, attrs_begin
, attrs_end
,
1104 cc_descriptors_begin
, cc_descriptors_end
,
1105 cc_descr_attrs_begin
, cc_descr_attrs_end
);
1108 BT_PUT(shared_lib_handle
);
1113 void plugin_comp_class_destroy_listener(struct bt_component_class
*comp_class
,
1116 gboolean exists
= g_hash_table_remove(comp_classes_to_shlib_handles
,
1119 BT_LOGV("Component class destroyed: removed entry from hash table: "
1120 "comp-cls-addr=%p", comp_class
);
1124 void bt_plugin_so_on_add_component_class(struct bt_plugin
*plugin
,
1125 struct bt_component_class
*comp_class
)
1127 struct bt_plugin_so_spec_data
*spec
= plugin
->spec_data
;
1129 assert(plugin
->spec_data
);
1130 assert(plugin
->type
== BT_PLUGIN_TYPE_SO
);
1132 /* Map component class pointer to shared lib handle in global HT */
1133 g_hash_table_insert(comp_classes_to_shlib_handles
, comp_class
,
1134 bt_get(spec
->shared_lib_handle
));
1136 /* Add our custom destroy listener */
1137 bt_component_class_add_destroy_listener(comp_class
,
1138 plugin_comp_class_destroy_listener
, NULL
);