2 * SPDX-License-Identifier: MIT
4 * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
5 * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
8 #define BT_LOG_TAG "LIB/COMPONENT"
9 #include "lib/logging.h"
11 #include "common/common.h"
12 #include "common/assert.h"
13 #include "lib/assert-cond.h"
14 #include <babeltrace2/graph/self-component.h>
15 #include <babeltrace2/graph/component.h>
16 #include <babeltrace2/graph/graph.h>
17 #include "common/macros.h"
18 #include "compat/compiler.h"
19 #include <babeltrace2/types.h>
20 #include <babeltrace2/value.h>
21 #include "lib/value.h"
25 #include "component.h"
26 #include "component-class.h"
27 #include "component-source.h"
28 #include "component-filter.h"
29 #include "component-sink.h"
30 #include "connection.h"
32 #include "message/iterator.h"
34 #include "lib/func-status.h"
37 struct bt_component
* (* const component_create_funcs
[])(
38 const struct bt_component_class
*) = {
39 [BT_COMPONENT_CLASS_TYPE_SOURCE
] = bt_component_source_create
,
40 [BT_COMPONENT_CLASS_TYPE_SINK
] = bt_component_sink_create
,
41 [BT_COMPONENT_CLASS_TYPE_FILTER
] = bt_component_filter_create
,
45 void (*component_destroy_funcs
[])(struct bt_component
*) = {
46 [BT_COMPONENT_CLASS_TYPE_SOURCE
] = bt_component_source_destroy
,
47 [BT_COMPONENT_CLASS_TYPE_SINK
] = bt_component_sink_destroy
,
48 [BT_COMPONENT_CLASS_TYPE_FILTER
] = bt_component_filter_destroy
,
52 void finalize_component(struct bt_component
*comp
)
54 typedef void (*method_t
)(void *);
56 method_t method
= NULL
;
60 switch (comp
->class->type
) {
61 case BT_COMPONENT_CLASS_TYPE_SOURCE
:
63 struct bt_component_class_source
*src_cc
= (void *) comp
->class;
65 method
= (method_t
) src_cc
->methods
.finalize
;
68 case BT_COMPONENT_CLASS_TYPE_FILTER
:
70 struct bt_component_class_filter
*flt_cc
= (void *) comp
->class;
72 method
= (method_t
) flt_cc
->methods
.finalize
;
75 case BT_COMPONENT_CLASS_TYPE_SINK
:
77 struct bt_component_class_sink
*sink_cc
= (void *) comp
->class;
79 method
= (method_t
) sink_cc
->methods
.finalize
;
87 const struct bt_error
*saved_error
;
89 saved_error
= bt_current_thread_take_error();
91 BT_LIB_LOGI("Calling user's component finalization method: "
94 BT_ASSERT_POST_NO_ERROR();
97 BT_CURRENT_THREAD_MOVE_ERROR_AND_RESET(saved_error
);
103 void destroy_component(struct bt_object
*obj
)
105 struct bt_component
*component
= NULL
;
113 * The component's reference count is 0 if we're here. Increment
114 * it to avoid a double-destroy (possibly infinitely recursive).
115 * This could happen for example if the component's finalization
116 * function does bt_object_get_ref() (or anything that causes
117 * bt_object_get_ref() to be called) on itself (ref. count goes
118 * from 0 to 1), and then bt_object_put_ref(): the reference
119 * count would go from 1 to 0 again and this function would be
123 component
= container_of(obj
, struct bt_component
, base
);
124 BT_LIB_LOGI("Destroying component: %![comp-]+c, %![graph-]+g",
125 component
, bt_component_borrow_graph(component
));
127 /* Call destroy listeners in reverse registration order */
128 BT_LOGD_STR("Calling destroy listeners.");
130 for (i
= component
->destroy_listeners
->len
- 1; i
>= 0; i
--) {
131 struct bt_component_destroy_listener
*listener
=
132 &g_array_index(component
->destroy_listeners
,
133 struct bt_component_destroy_listener
, i
);
135 listener
->func(component
, listener
->data
);
139 * User data is destroyed first, followed by the concrete
140 * component instance. Do not finalize if the component's user
141 * initialization method failed in the first place.
143 if (component
->initialized
) {
144 finalize_component(component
);
147 if (component
->destroy
) {
148 BT_LOGD_STR("Destroying type-specific data.");
149 component
->destroy(component
);
152 if (component
->input_ports
) {
153 BT_LOGD_STR("Destroying input ports.");
154 g_ptr_array_free(component
->input_ports
, TRUE
);
155 component
->input_ports
= NULL
;
158 if (component
->output_ports
) {
159 BT_LOGD_STR("Destroying output ports.");
160 g_ptr_array_free(component
->output_ports
, TRUE
);
161 component
->output_ports
= NULL
;
164 if (component
->destroy_listeners
) {
165 g_array_free(component
->destroy_listeners
, TRUE
);
166 component
->destroy_listeners
= NULL
;
169 if (component
->name
) {
170 g_string_free(component
->name
, TRUE
);
171 component
->name
= NULL
;
174 BT_LOGD_STR("Putting component class.");
175 BT_OBJECT_PUT_REF_AND_RESET(component
->class);
179 enum bt_component_class_type
bt_component_get_class_type(
180 const struct bt_component
*component
)
182 BT_ASSERT_PRE_DEV_COMP_NON_NULL(component
);
183 return component
->class->type
;
187 enum bt_self_component_add_port_status
add_port(
188 struct bt_component
*component
, GPtrArray
*ports
,
189 enum bt_port_type port_type
, const char *name
, void *user_data
,
190 struct bt_port
**port
)
192 struct bt_port
*new_port
= NULL
;
193 struct bt_graph
*graph
= NULL
;
194 enum bt_self_component_add_port_status status
;
196 BT_ASSERT_PRE_COMP_NON_NULL(component
);
197 BT_ASSERT_PRE_NAME_NON_NULL(name
);
198 BT_ASSERT_PRE(strlen(name
) > 0, "Name is empty");
199 graph
= bt_component_borrow_graph(component
);
201 graph
->config_state
== BT_GRAPH_CONFIGURATION_STATE_CONFIGURING
,
202 "Component's graph is already configured: "
203 "%![comp-]+c, %![graph-]+g", component
, graph
);
205 // TODO: Validate that the name is not already used.
207 BT_LIB_LOGI("Adding port to component: %![comp-]+c, "
208 "port-type=%s, port-name=\"%s\"", component
,
209 bt_port_type_string(port_type
), name
);
211 new_port
= bt_port_create(component
, port_type
, name
, user_data
);
213 BT_LIB_LOGE_APPEND_CAUSE("Cannot create port object.");
214 status
= BT_FUNC_STATUS_MEMORY_ERROR
;
219 * No name clash, add the port.
220 * The component is now the port's parent; it should _not_
221 * hold a reference to the port since the port's lifetime
222 * is now protected by the component's own lifetime.
224 g_ptr_array_add(ports
, new_port
);
227 * Notify the graph's creator that a new port was added.
229 graph
= bt_component_borrow_graph(component
);
231 enum bt_graph_listener_func_status listener_status
;
233 listener_status
= bt_graph_notify_port_added(graph
, new_port
);
234 if (listener_status
!= BT_FUNC_STATUS_OK
) {
235 bt_graph_make_faulty(graph
);
236 status
= (int) listener_status
;
241 BT_LIB_LOGI("Created and added port to component: "
242 "%![comp-]+c, %![port-]+p", component
, new_port
);
245 status
= BT_FUNC_STATUS_OK
;
250 * We need to release the reference that we would otherwise have
251 * returned to the caller.
253 BT_PORT_PUT_REF_AND_RESET(new_port
);
260 uint64_t bt_component_get_input_port_count(const struct bt_component
*comp
)
262 BT_ASSERT_PRE_DEV_COMP_NON_NULL(comp
);
263 return (uint64_t) comp
->input_ports
->len
;
267 uint64_t bt_component_get_output_port_count(const struct bt_component
*comp
)
269 BT_ASSERT_PRE_DEV_COMP_NON_NULL(comp
);
270 return (uint64_t) comp
->output_ports
->len
;
274 int bt_component_create(struct bt_component_class
*component_class
,
275 const char *name
, bt_logging_level log_level
,
276 struct bt_component
**user_component
)
279 struct bt_component
*component
= NULL
;
280 enum bt_component_class_type type
;
282 BT_ASSERT(user_component
);
283 BT_ASSERT(component_class
);
285 type
= bt_component_class_get_type(component_class
);
286 BT_LIB_LOGI("Creating empty component from component class: %![cc-]+C, "
287 "comp-name=\"%s\", log-level=%s", component_class
, name
,
288 bt_common_logging_level_string(log_level
));
289 component
= component_create_funcs
[type
](component_class
);
291 BT_LIB_LOGE_APPEND_CAUSE(
292 "Cannot create specific component object.");
297 bt_object_init_shared_with_parent(&component
->base
, destroy_component
);
298 component
->class = component_class
;
299 bt_object_get_ref_no_null_check(component
->class);
300 component
->destroy
= component_destroy_funcs
[type
];
301 component
->name
= g_string_new(name
);
302 if (!component
->name
) {
303 BT_LIB_LOGE_APPEND_CAUSE("Failed to allocate one GString.");
308 component
->log_level
= log_level
;
309 component
->input_ports
= g_ptr_array_new_with_free_func(
310 (GDestroyNotify
) bt_object_try_spec_release
);
311 if (!component
->input_ports
) {
312 BT_LIB_LOGE_APPEND_CAUSE("Failed to allocate one GPtrArray.");
317 component
->output_ports
= g_ptr_array_new_with_free_func(
318 (GDestroyNotify
) bt_object_try_spec_release
);
319 if (!component
->output_ports
) {
320 BT_LIB_LOGE_APPEND_CAUSE("Failed to allocate one GPtrArray.");
325 component
->destroy_listeners
= g_array_new(FALSE
, TRUE
,
326 sizeof(struct bt_component_destroy_listener
));
327 if (!component
->destroy_listeners
) {
328 BT_LIB_LOGE_APPEND_CAUSE("Failed to allocate one GArray.");
333 BT_LIB_LOGI("Created empty component from component class: "
334 "%![cc-]+C, %![comp-]+c", component_class
, component
);
335 BT_OBJECT_MOVE_REF(*user_component
, component
);
338 bt_object_put_ref(component
);
342 const char *bt_component_get_name(const struct bt_component
*component
)
344 BT_ASSERT_PRE_DEV_COMP_NON_NULL(component
);
345 return component
->name
->str
;
348 const struct bt_component_class
*bt_component_borrow_class_const(
349 const struct bt_component
*component
)
351 BT_ASSERT_PRE_DEV_COMP_NON_NULL(component
);
352 return component
->class;
355 void *bt_self_component_get_data(const struct bt_self_component
*self_comp
)
357 struct bt_component
*component
= (void *) self_comp
;
359 BT_ASSERT_PRE_DEV_COMP_NON_NULL(component
);
360 return component
->user_data
;
363 void bt_self_component_set_data(struct bt_self_component
*self_comp
,
366 struct bt_component
*component
= (void *) self_comp
;
368 BT_ASSERT_PRE_DEV_COMP_NON_NULL(component
);
369 component
->user_data
= data
;
370 BT_LIB_LOGD("Set component's user data: %!+c", component
);
374 void bt_component_set_graph(struct bt_component
*component
,
375 struct bt_graph
*graph
)
377 bt_object_set_parent(&component
->base
,
378 graph
? &graph
->base
: NULL
);
382 struct bt_port
*borrow_port_by_name(GPtrArray
*ports
,
386 struct bt_port
*ret_port
= NULL
;
390 for (i
= 0; i
< ports
->len
; i
++) {
391 struct bt_port
*port
= g_ptr_array_index(ports
, i
);
393 if (strcmp(name
, port
->name
->str
) == 0) {
403 struct bt_port_input
*bt_component_borrow_input_port_by_name(
404 struct bt_component
*comp
, const char *name
)
407 return (void *) borrow_port_by_name(comp
->input_ports
, name
);
411 struct bt_port_output
*bt_component_borrow_output_port_by_name(
412 struct bt_component
*comp
, const char *name
)
414 BT_ASSERT_PRE_DEV_COMP_NON_NULL(comp
);
416 borrow_port_by_name(comp
->output_ports
, name
);
420 struct bt_port
*borrow_port_by_index(GPtrArray
*ports
, uint64_t index
)
422 BT_ASSERT(index
< ports
->len
);
423 return g_ptr_array_index(ports
, index
);
427 struct bt_port_input
*bt_component_borrow_input_port_by_index(
428 struct bt_component
*comp
, uint64_t index
)
430 BT_ASSERT_PRE_DEV_COMP_NON_NULL(comp
);
431 BT_ASSERT_PRE_DEV_VALID_INDEX(index
, comp
->input_ports
->len
);
433 borrow_port_by_index(comp
->input_ports
, index
);
437 struct bt_port_output
*bt_component_borrow_output_port_by_index(
438 struct bt_component
*comp
, uint64_t index
)
440 BT_ASSERT_PRE_DEV_COMP_NON_NULL(comp
);
441 BT_ASSERT_PRE_DEV_VALID_INDEX(index
, comp
->output_ports
->len
);
443 borrow_port_by_index(comp
->output_ports
, index
);
447 enum bt_self_component_add_port_status
bt_component_add_input_port(
448 struct bt_component
*component
, const char *name
,
449 void *user_data
, struct bt_port
**port
)
451 /* add_port() logs details */
452 return add_port(component
, component
->input_ports
,
453 BT_PORT_TYPE_INPUT
, name
, user_data
, port
);
457 enum bt_self_component_add_port_status
bt_component_add_output_port(
458 struct bt_component
*component
, const char *name
,
459 void *user_data
, struct bt_port
**port
)
461 /* add_port() logs details */
462 return add_port(component
, component
->output_ports
,
463 BT_PORT_TYPE_OUTPUT
, name
, user_data
, port
);
467 bool bt_component_port_name_is_unique(GPtrArray
*ports
, const char *name
)
472 for (i
= 0; i
< ports
->len
; i
++) {
473 struct bt_port
*port
= g_ptr_array_index(ports
, i
);
475 if (strcmp(port
->name
->str
, name
) == 0) {
488 enum bt_component_class_port_connected_method_status
489 bt_component_port_connected(
490 struct bt_component
*comp
, struct bt_port
*self_port
,
491 struct bt_port
*other_port
)
493 typedef enum bt_component_class_port_connected_method_status (*method_t
)(
494 void *, void *, const void *);
496 enum bt_component_class_port_connected_method_status status
=
498 method_t method
= NULL
;
501 BT_ASSERT(self_port
);
502 BT_ASSERT(other_port
);
504 switch (comp
->class->type
) {
505 case BT_COMPONENT_CLASS_TYPE_SOURCE
:
507 struct bt_component_class_source
*src_cc
= (void *) comp
->class;
509 switch (self_port
->type
) {
510 case BT_PORT_TYPE_OUTPUT
:
511 method
= (method_t
) src_cc
->methods
.output_port_connected
;
519 case BT_COMPONENT_CLASS_TYPE_FILTER
:
521 struct bt_component_class_filter
*flt_cc
= (void *) comp
->class;
523 switch (self_port
->type
) {
524 case BT_PORT_TYPE_INPUT
:
525 method
= (method_t
) flt_cc
->methods
.input_port_connected
;
527 case BT_PORT_TYPE_OUTPUT
:
528 method
= (method_t
) flt_cc
->methods
.output_port_connected
;
536 case BT_COMPONENT_CLASS_TYPE_SINK
:
538 struct bt_component_class_sink
*sink_cc
= (void *) comp
->class;
540 switch (self_port
->type
) {
541 case BT_PORT_TYPE_INPUT
:
542 method
= (method_t
) sink_cc
->methods
.input_port_connected
;
555 BT_LIB_LOGD("Calling user's \"port connected\" method: "
556 "%![comp-]+c, %![self-port-]+p, %![other-port-]+p",
557 comp
, self_port
, other_port
);
558 status
= (int) method(comp
, self_port
, (void *) other_port
);
559 BT_LOGD("User method returned: status=%s",
560 bt_common_func_status_string(status
));
561 BT_ASSERT_POST(status
== BT_FUNC_STATUS_OK
||
562 status
== BT_FUNC_STATUS_ERROR
||
563 status
== BT_FUNC_STATUS_MEMORY_ERROR
,
564 "Unexpected returned component status: status=%s",
565 bt_common_func_status_string(status
));
566 BT_ASSERT_POST_NO_ERROR_IF_NO_ERROR_STATUS(status
);
573 void bt_component_add_destroy_listener(struct bt_component
*component
,
574 bt_component_destroy_listener_func func
, void *data
)
576 struct bt_component_destroy_listener listener
;
578 BT_ASSERT(component
);
580 listener
.func
= func
;
581 listener
.data
= data
;
582 g_array_append_val(component
->destroy_listeners
, listener
);
583 BT_LIB_LOGD("Added destroy listener: %![comp-]+c, "
584 "func-addr=%p, data-addr=%p",
585 component
, func
, data
);
589 void bt_component_remove_destroy_listener(struct bt_component
*component
,
590 bt_component_destroy_listener_func func
, void *data
)
594 BT_ASSERT(component
);
597 for (i
= 0; i
< component
->destroy_listeners
->len
; i
++) {
598 struct bt_component_destroy_listener
*listener
=
599 &g_array_index(component
->destroy_listeners
,
600 struct bt_component_destroy_listener
, i
);
602 if (listener
->func
== func
&& listener
->data
== data
) {
603 g_array_remove_index(component
->destroy_listeners
, i
);
605 BT_LIB_LOGD("Removed destroy listener: %![comp-]+c, "
606 "func-addr=%p, data-addr=%p",
607 component
, func
, data
);
612 bt_logging_level
bt_component_get_logging_level(
613 const struct bt_component
*component
)
615 BT_ASSERT_PRE_DEV_COMP_NON_NULL(component
);
616 return component
->log_level
;
619 uint64_t bt_self_component_get_graph_mip_version(
620 bt_self_component
*self_component
)
622 struct bt_component
*comp
= (void *) self_component
;
624 BT_ASSERT_PRE_COMP_NON_NULL(self_component
);
625 return bt_component_borrow_graph(comp
)->mip_version
;
628 void bt_component_get_ref(const struct bt_component
*component
)
630 bt_object_get_ref(component
);
633 void bt_component_put_ref(const struct bt_component
*component
)
635 bt_object_put_ref(component
);