cpp-common/bt2c/fmt.hpp: use `wise_enum::string_type` in `EnableIfIsWiseEnum` definition
[babeltrace.git] / src / lib / graph / component.c
1 /*
2 * SPDX-License-Identifier: MIT
3 *
4 * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
5 * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
6 */
7
8 #define BT_LOG_TAG "LIB/COMPONENT"
9 #include "lib/logging.h"
10
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 <stdint.h>
22
23 #include "component.h"
24 #include "component-class.h"
25 #include "component-source.h"
26 #include "component-filter.h"
27 #include "component-sink.h"
28 #include "connection.h"
29 #include "graph.h"
30 #include "iterator.h"
31 #include "port.h"
32 #include "lib/func-status.h"
33
34 static
35 struct bt_component * (* const component_create_funcs[])(void) = {
36 [BT_COMPONENT_CLASS_TYPE_SOURCE] = bt_component_source_create,
37 [BT_COMPONENT_CLASS_TYPE_SINK] = bt_component_sink_create,
38 [BT_COMPONENT_CLASS_TYPE_FILTER] = bt_component_filter_create,
39 };
40
41 static
42 void finalize_component(struct bt_component *comp)
43 {
44 typedef void (*method_t)(void *);
45 const char *method_name;
46
47 method_t method = NULL;
48
49 BT_ASSERT(comp);
50
51 switch (comp->class->type) {
52 case BT_COMPONENT_CLASS_TYPE_SOURCE:
53 {
54 struct bt_component_class_source *src_cc = (void *) comp->class;
55
56 method = (method_t) src_cc->methods.finalize;
57 method_name = "bt_component_class_source_finalize_method";
58 break;
59 }
60 case BT_COMPONENT_CLASS_TYPE_FILTER:
61 {
62 struct bt_component_class_filter *flt_cc = (void *) comp->class;
63
64 method = (method_t) flt_cc->methods.finalize;
65 method_name = "bt_component_class_filter_finalize_method";
66 break;
67 }
68 case BT_COMPONENT_CLASS_TYPE_SINK:
69 {
70 struct bt_component_class_sink *sink_cc = (void *) comp->class;
71
72 method = (method_t) sink_cc->methods.finalize;
73 method_name = "bt_component_class_sink_finalize_method";
74 break;
75 }
76 default:
77 bt_common_abort();
78 }
79
80 if (method) {
81 const struct bt_error *saved_error;
82
83 saved_error = bt_current_thread_take_error();
84
85 BT_LIB_LOGI("Calling user's component finalization method: "
86 "%![comp-]+c", comp);
87 method(comp);
88 BT_ASSERT_POST_NO_ERROR(method_name);
89
90 if (saved_error) {
91 BT_CURRENT_THREAD_MOVE_ERROR_AND_RESET(saved_error);
92 }
93 }
94 }
95
96 static
97 void destroy_component(struct bt_object *obj)
98 {
99 struct bt_component *component = NULL;
100 int i;
101
102 if (!obj) {
103 return;
104 }
105
106 /*
107 * The component's reference count is 0 if we're here. Increment
108 * it to avoid a double-destroy (possibly infinitely recursive).
109 * This could happen for example if the component's finalization
110 * function does bt_object_get_ref() (or anything that causes
111 * bt_object_get_ref() to be called) on itself (ref. count goes
112 * from 0 to 1), and then bt_object_put_ref(): the reference
113 * count would go from 1 to 0 again and this function would be
114 * called again.
115 */
116 obj->ref_count++;
117 component = container_of(obj, struct bt_component, base);
118 BT_LIB_LOGI("Destroying component: %![comp-]+c, %![graph-]+g",
119 component, bt_component_borrow_graph(component));
120
121 /* Call destroy listeners in reverse registration order */
122 BT_LOGD_STR("Calling destroy listeners.");
123
124 for (i = component->destroy_listeners->len - 1; i >= 0; i--) {
125 struct bt_component_destroy_listener *listener =
126 &bt_g_array_index(component->destroy_listeners,
127 struct bt_component_destroy_listener, i);
128
129 listener->func(component, listener->data);
130 }
131
132 /*
133 * User data is destroyed first, followed by the concrete
134 * component instance. Do not finalize if the component's user
135 * initialization method failed in the first place.
136 */
137 if (component->initialized) {
138 finalize_component(component);
139 }
140
141 if (component->input_ports) {
142 BT_LOGD_STR("Destroying input ports.");
143 g_ptr_array_free(component->input_ports, TRUE);
144 component->input_ports = NULL;
145 }
146
147 if (component->output_ports) {
148 BT_LOGD_STR("Destroying output ports.");
149 g_ptr_array_free(component->output_ports, TRUE);
150 component->output_ports = NULL;
151 }
152
153 if (component->destroy_listeners) {
154 g_array_free(component->destroy_listeners, TRUE);
155 component->destroy_listeners = NULL;
156 }
157
158 if (component->name) {
159 g_string_free(component->name, TRUE);
160 component->name = NULL;
161 }
162
163 BT_LOGD_STR("Putting component class.");
164 BT_OBJECT_PUT_REF_AND_RESET(component->class);
165 g_free(component);
166 }
167
168 BT_EXPORT
169 enum bt_component_class_type bt_component_get_class_type(
170 const struct bt_component *component)
171 {
172 BT_ASSERT_PRE_DEV_COMP_NON_NULL(component);
173 return component->class->type;
174 }
175
176 static
177 bool port_name_is_unique(GPtrArray *ports, const char *name)
178 {
179 guint i;
180 bool unique;
181
182 for (i = 0; i < ports->len; i++) {
183 struct bt_port *port = g_ptr_array_index(ports, i);
184
185 if (strcmp(port->name->str, name) == 0) {
186 unique = false;
187 goto end;
188 }
189 }
190
191 unique = true;
192
193 end:
194 return unique;
195 }
196
197 static
198 enum bt_self_component_add_port_status add_port(
199 struct bt_component *component, GPtrArray *ports,
200 enum bt_port_type port_type, const char *name, void *user_data,
201 struct bt_port **port, const char *api_func, bool input)
202 {
203 struct bt_port *new_port = NULL;
204 struct bt_graph *graph = NULL;
205 enum bt_self_component_add_port_status status;
206
207 BT_ASSERT_PRE_NO_ERROR_FROM_FUNC(api_func);
208 BT_ASSERT_PRE_COMP_NON_NULL_FROM_FUNC(api_func, component);
209 BT_ASSERT_PRE_NAME_NON_NULL_FROM_FUNC(api_func, name);
210 BT_ASSERT_PRE_FROM_FUNC(api_func,
211 input ? "input" : "output" "-port-name-is-unique",
212 port_name_is_unique(component->output_ports, name),
213 input ? "Input" : "Output"
214 " port name is not unique: name=\"%s\", %![comp-]c",
215 name, component);
216 BT_ASSERT_PRE_FROM_FUNC(api_func, "name-is-not-empty",
217 strlen(name) > 0, "Name is empty");
218 graph = bt_component_borrow_graph(component);
219 BT_ASSERT_PRE_FROM_FUNC(api_func, "graph-is-not-configured",
220 graph->config_state == BT_GRAPH_CONFIGURATION_STATE_CONFIGURING,
221 "Component's graph is already configured: "
222 "%![comp-]+c, %![graph-]+g", component, graph);
223
224 BT_LIB_LOGI("Adding port to component: %![comp-]+c, "
225 "port-type=%s, port-name=\"%s\"", component,
226 bt_port_type_string(port_type), name);
227
228 new_port = bt_port_create(component, port_type, name, user_data);
229 if (!new_port) {
230 BT_LIB_LOGE_APPEND_CAUSE("Cannot create port object.");
231 status = BT_FUNC_STATUS_MEMORY_ERROR;
232 goto error;
233 }
234
235 /*
236 * No name clash, add the port.
237 * The component is now the port's parent; it should _not_
238 * hold a reference to the port since the port's lifetime
239 * is now protected by the component's own lifetime.
240 */
241 g_ptr_array_add(ports, new_port);
242
243 /*
244 * Notify the graph's creator that a new port was added.
245 */
246 graph = bt_component_borrow_graph(component);
247 if (graph) {
248 enum bt_graph_listener_func_status listener_status;
249
250 listener_status = bt_graph_notify_port_added(graph, new_port);
251 if (listener_status != BT_FUNC_STATUS_OK) {
252 bt_graph_make_faulty(graph);
253 status = (int) listener_status;
254 goto error;
255 }
256 }
257
258 BT_LIB_LOGI("Created and added port to component: "
259 "%![comp-]+c, %![port-]+p", component, new_port);
260
261 *port = new_port;
262 status = BT_FUNC_STATUS_OK;
263
264 goto end;
265 error:
266 /*
267 * We need to release the reference that we would otherwise have
268 * returned to the caller.
269 */
270 BT_PORT_PUT_REF_AND_RESET(new_port);
271
272 end:
273 return status;
274 }
275
276 uint64_t bt_component_get_input_port_count(const struct bt_component *comp,
277 const char *api_func)
278 {
279 BT_ASSERT_PRE_DEV_COMP_NON_NULL_FROM_FUNC(api_func, comp);
280 return (uint64_t) comp->input_ports->len;
281 }
282
283 uint64_t bt_component_get_output_port_count(const struct bt_component *comp,
284 const char *api_func)
285 {
286 BT_ASSERT_PRE_DEV_COMP_NON_NULL_FROM_FUNC(api_func, comp);
287 return (uint64_t) comp->output_ports->len;
288 }
289
290 int bt_component_create(struct bt_component_class *component_class,
291 const char *name, bt_logging_level log_level,
292 struct bt_component **user_component)
293 {
294 int ret = 0;
295 struct bt_component *component = NULL;
296 enum bt_component_class_type type;
297
298 BT_ASSERT(user_component);
299 BT_ASSERT(component_class);
300 BT_ASSERT(name);
301 type = bt_component_class_get_type(component_class);
302 BT_LIB_LOGI("Creating empty component from component class: %![cc-]+C, "
303 "comp-name=\"%s\", log-level=%s", component_class, name,
304 bt_common_logging_level_string(log_level));
305 component = component_create_funcs[type]();
306 if (!component) {
307 BT_LIB_LOGE_APPEND_CAUSE(
308 "Cannot create specific component object.");
309 ret = -1;
310 goto end;
311 }
312
313 bt_object_init_shared_with_parent(&component->base, destroy_component);
314 component->class = component_class;
315 bt_object_get_ref_no_null_check(component->class);
316 component->name = g_string_new(name);
317 if (!component->name) {
318 BT_LIB_LOGE_APPEND_CAUSE("Failed to allocate one GString.");
319 ret = -1;
320 goto end;
321 }
322
323 component->log_level = log_level;
324 component->input_ports = g_ptr_array_new_with_free_func(
325 (GDestroyNotify) bt_object_try_spec_release);
326 if (!component->input_ports) {
327 BT_LIB_LOGE_APPEND_CAUSE("Failed to allocate one GPtrArray.");
328 ret = -1;
329 goto end;
330 }
331
332 component->output_ports = g_ptr_array_new_with_free_func(
333 (GDestroyNotify) bt_object_try_spec_release);
334 if (!component->output_ports) {
335 BT_LIB_LOGE_APPEND_CAUSE("Failed to allocate one GPtrArray.");
336 ret = -1;
337 goto end;
338 }
339
340 component->destroy_listeners = g_array_new(FALSE, TRUE,
341 sizeof(struct bt_component_destroy_listener));
342 if (!component->destroy_listeners) {
343 BT_LIB_LOGE_APPEND_CAUSE("Failed to allocate one GArray.");
344 ret = -1;
345 goto end;
346 }
347
348 BT_LIB_LOGI("Created empty component from component class: "
349 "%![cc-]+C, %![comp-]+c", component_class, component);
350 BT_OBJECT_MOVE_REF(*user_component, component);
351
352 end:
353 bt_object_put_ref(component);
354 return ret;
355 }
356
357 BT_EXPORT
358 const char *bt_component_get_name(const struct bt_component *component)
359 {
360 BT_ASSERT_PRE_DEV_COMP_NON_NULL(component);
361 return component->name->str;
362 }
363
364 BT_EXPORT
365 const struct bt_component_class *bt_component_borrow_class_const(
366 const struct bt_component *component)
367 {
368 BT_ASSERT_PRE_DEV_COMP_NON_NULL(component);
369 return component->class;
370 }
371
372 BT_EXPORT
373 void *bt_self_component_get_data(const struct bt_self_component *self_comp)
374 {
375 struct bt_component *component = (void *) self_comp;
376
377 BT_ASSERT_PRE_DEV_COMP_NON_NULL(component);
378 return component->user_data;
379 }
380
381 BT_EXPORT
382 void bt_self_component_set_data(struct bt_self_component *self_comp,
383 void *data)
384 {
385 struct bt_component *component = (void *) self_comp;
386
387 BT_ASSERT_PRE_DEV_COMP_NON_NULL(component);
388 component->user_data = data;
389 BT_LIB_LOGD("Set component's user data: %!+c", component);
390 }
391
392 void bt_component_set_graph(struct bt_component *component,
393 struct bt_graph *graph)
394 {
395 bt_object_set_parent(&component->base,
396 graph ? &graph->base : NULL);
397 }
398
399 static
400 struct bt_port *borrow_port_by_name(GPtrArray *ports,
401 const char *name, const char *api_func)
402 {
403 uint64_t i;
404 struct bt_port *ret_port = NULL;
405
406 BT_ASSERT_PRE_DEV_NAME_NON_NULL_FROM_FUNC(api_func, name);
407
408 for (i = 0; i < ports->len; i++) {
409 struct bt_port *port = g_ptr_array_index(ports, i);
410
411 if (strcmp(name, port->name->str) == 0) {
412 ret_port = port;
413 break;
414 }
415 }
416
417 return ret_port;
418 }
419
420 struct bt_port_input *bt_component_borrow_input_port_by_name(
421 struct bt_component *comp, const char *name,
422 const char *api_func)
423 {
424 BT_ASSERT_PRE_DEV_COMP_NON_NULL_FROM_FUNC(api_func, comp);
425 return (void *) borrow_port_by_name(comp->input_ports, name, api_func);
426 }
427
428 struct bt_port_output *bt_component_borrow_output_port_by_name(
429 struct bt_component *comp, const char *name,
430 const char *api_func)
431 {
432 BT_ASSERT_PRE_DEV_COMP_NON_NULL_FROM_FUNC(api_func, comp);
433 return (void *)
434 borrow_port_by_name(comp->output_ports, name, api_func);
435 }
436
437 static
438 struct bt_port *borrow_port_by_index(GPtrArray *ports, uint64_t index,
439 const char *api_func)
440 {
441 BT_ASSERT_PRE_DEV_VALID_INDEX_FROM_FUNC(api_func, index, ports->len);
442 return g_ptr_array_index(ports, index);
443 }
444
445 struct bt_port_input *bt_component_borrow_input_port_by_index(
446 struct bt_component *comp, uint64_t index,
447 const char *api_func)
448 {
449 BT_ASSERT_PRE_DEV_COMP_NON_NULL_FROM_FUNC(api_func, comp);
450 return (void *)
451 borrow_port_by_index(comp->input_ports, index, api_func);
452 }
453
454 struct bt_port_output *bt_component_borrow_output_port_by_index(
455 struct bt_component *comp, uint64_t index,
456 const char *api_func)
457 {
458 BT_ASSERT_PRE_DEV_COMP_NON_NULL_FROM_FUNC(api_func, comp);
459 return (void *)
460 borrow_port_by_index(comp->output_ports, index, api_func);
461 }
462
463 enum bt_self_component_add_port_status bt_component_add_input_port(
464 struct bt_component *component, const char *name,
465 void *user_data, struct bt_port **port, const char *api_func)
466 {
467 /* add_port() logs details and checks preconditions */
468 return add_port(component, component->input_ports,
469 BT_PORT_TYPE_INPUT, name, user_data, port, api_func, true);
470 }
471
472 enum bt_self_component_add_port_status bt_component_add_output_port(
473 struct bt_component *component, const char *name,
474 void *user_data, struct bt_port **port,
475 const char *api_func)
476 {
477 /* add_port() logs details and checks preconditions */
478 return add_port(component, component->output_ports,
479 BT_PORT_TYPE_OUTPUT, name, user_data, port, api_func, false);
480 }
481
482 enum bt_component_class_port_connected_method_status
483 bt_component_port_connected(
484 struct bt_component *comp, struct bt_port *self_port,
485 struct bt_port *other_port)
486 {
487 typedef enum bt_component_class_port_connected_method_status (*method_t)(
488 void *, void *, const void *);
489
490 enum bt_component_class_port_connected_method_status status =
491 BT_FUNC_STATUS_OK;
492 method_t method = NULL;
493 const char *method_name = NULL;
494
495 BT_ASSERT(comp);
496 BT_ASSERT(self_port);
497 BT_ASSERT(other_port);
498
499 switch (comp->class->type) {
500 case BT_COMPONENT_CLASS_TYPE_SOURCE:
501 {
502 struct bt_component_class_source *src_cc = (void *) comp->class;
503
504 switch (self_port->type) {
505 case BT_PORT_TYPE_OUTPUT:
506 method = (method_t) src_cc->methods.output_port_connected;
507 method_name = "bt_component_class_source_output_port_connected_method";
508 break;
509 default:
510 bt_common_abort();
511 }
512
513 break;
514 }
515 case BT_COMPONENT_CLASS_TYPE_FILTER:
516 {
517 struct bt_component_class_filter *flt_cc = (void *) comp->class;
518
519 switch (self_port->type) {
520 case BT_PORT_TYPE_INPUT:
521 method = (method_t) flt_cc->methods.input_port_connected;
522 method_name = "bt_component_class_filter_input_port_connected_method";
523 break;
524 case BT_PORT_TYPE_OUTPUT:
525 method = (method_t) flt_cc->methods.output_port_connected;
526 method_name = "bt_component_class_filter_output_port_connected_method";
527 break;
528 default:
529 bt_common_abort();
530 }
531
532 break;
533 }
534 case BT_COMPONENT_CLASS_TYPE_SINK:
535 {
536 struct bt_component_class_sink *sink_cc = (void *) comp->class;
537
538 switch (self_port->type) {
539 case BT_PORT_TYPE_INPUT:
540 method = (method_t) sink_cc->methods.input_port_connected;
541 method_name = "bt_component_class_sink_input_port_connected_method";
542 break;
543 default:
544 bt_common_abort();
545 }
546
547 break;
548 }
549 default:
550 bt_common_abort();
551 }
552
553 if (method) {
554 BT_LIB_LOGD("Calling user's \"port connected\" method: "
555 "%![comp-]+c, %![self-port-]+p, %![other-port-]+p",
556 comp, self_port, other_port);
557 status = (int) method(comp, self_port, (void *) other_port);
558 BT_LOGD("User method returned: status=%s",
559 bt_common_func_status_string(status));
560 BT_ASSERT_POST(method_name, "valid-status",
561 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(method_name, status);
567 }
568
569 return status;
570 }
571
572 void bt_component_add_destroy_listener(struct bt_component *component,
573 bt_component_destroy_listener_func func, void *data)
574 {
575 struct bt_component_destroy_listener listener;
576
577 BT_ASSERT(component);
578 BT_ASSERT(func);
579 listener.func = func;
580 listener.data = data;
581 g_array_append_val(component->destroy_listeners, listener);
582 BT_LIB_LOGD("Added destroy listener: %![comp-]+c, "
583 "func-addr=%p, data-addr=%p",
584 component, func, data);
585 }
586
587 void bt_component_remove_destroy_listener(struct bt_component *component,
588 bt_component_destroy_listener_func func, void *data)
589 {
590 uint64_t i;
591
592 BT_ASSERT(component);
593 BT_ASSERT(func);
594
595 for (i = 0; i < component->destroy_listeners->len; i++) {
596 struct bt_component_destroy_listener *listener =
597 &bt_g_array_index(component->destroy_listeners,
598 struct bt_component_destroy_listener, i);
599
600 if (listener->func == func && listener->data == data) {
601 g_array_remove_index(component->destroy_listeners, i);
602 i--;
603 BT_LIB_LOGD("Removed destroy listener: %![comp-]+c, "
604 "func-addr=%p, data-addr=%p",
605 component, func, data);
606 }
607 }
608 }
609
610 BT_EXPORT
611 bt_logging_level bt_component_get_logging_level(
612 const struct bt_component *component)
613 {
614 BT_ASSERT_PRE_DEV_COMP_NON_NULL(component);
615 return component->log_level;
616 }
617
618 BT_EXPORT
619 uint64_t bt_self_component_get_graph_mip_version(
620 bt_self_component *self_component)
621 {
622 struct bt_component *comp = (void *) self_component;
623
624 BT_ASSERT_PRE_COMP_NON_NULL(self_component);
625 return bt_component_borrow_graph(comp)->mip_version;
626 }
627
628 BT_EXPORT
629 void bt_component_get_ref(const struct bt_component *component)
630 {
631 bt_object_get_ref(component);
632 }
633
634 BT_EXPORT
635 void bt_component_put_ref(const struct bt_component *component)
636 {
637 bt_object_put_ref(component);
638 }
This page took 0.044033 seconds and 4 git commands to generate.