Logging: standardize logging tags
[babeltrace.git] / src / lib / graph / component.c
1 /*
2 * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
3 * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
24 #define BT_LOG_TAG "LIB/COMPONENT"
25 #include "lib/lib-logging.h"
26
27 #include "common/assert.h"
28 #include "lib/assert-pre.h"
29 #include <babeltrace2/graph/self-component.h>
30 #include <babeltrace2/graph/component-const.h>
31 #include <babeltrace2/graph/component-source-const.h>
32 #include <babeltrace2/graph/component-filter-const.h>
33 #include <babeltrace2/graph/component-sink-const.h>
34 #include "common/macros.h"
35 #include "compat/compiler.h"
36 #include <babeltrace2/types.h>
37 #include <babeltrace2/value.h>
38 #include "lib/value.h"
39 #include <stdint.h>
40 #include <inttypes.h>
41
42 #include "component.h"
43 #include "component-class.h"
44 #include "component-source.h"
45 #include "component-filter.h"
46 #include "component-sink.h"
47 #include "connection.h"
48 #include "graph.h"
49 #include "message/iterator.h"
50 #include "port.h"
51
52 static
53 struct bt_component * (* const component_create_funcs[])(
54 const struct bt_component_class *) = {
55 [BT_COMPONENT_CLASS_TYPE_SOURCE] = bt_component_source_create,
56 [BT_COMPONENT_CLASS_TYPE_SINK] = bt_component_sink_create,
57 [BT_COMPONENT_CLASS_TYPE_FILTER] = bt_component_filter_create,
58 };
59
60 static
61 void (*component_destroy_funcs[])(struct bt_component *) = {
62 [BT_COMPONENT_CLASS_TYPE_SOURCE] = bt_component_source_destroy,
63 [BT_COMPONENT_CLASS_TYPE_SINK] = bt_component_sink_destroy,
64 [BT_COMPONENT_CLASS_TYPE_FILTER] = bt_component_filter_destroy,
65 };
66
67 static
68 void finalize_component(struct bt_component *comp)
69 {
70 typedef void (*method_t)(void *);
71
72 method_t method = NULL;
73
74 BT_ASSERT(comp);
75
76 switch (comp->class->type) {
77 case BT_COMPONENT_CLASS_TYPE_SOURCE:
78 {
79 struct bt_component_class_source *src_cc = (void *) comp->class;
80
81 method = (method_t) src_cc->methods.finalize;
82 break;
83 }
84 case BT_COMPONENT_CLASS_TYPE_FILTER:
85 {
86 struct bt_component_class_filter *flt_cc = (void *) comp->class;
87
88 method = (method_t) flt_cc->methods.finalize;
89 break;
90 }
91 case BT_COMPONENT_CLASS_TYPE_SINK:
92 {
93 struct bt_component_class_sink *sink_cc = (void *) comp->class;
94
95 method = (method_t) sink_cc->methods.finalize;
96 break;
97 }
98 default:
99 abort();
100 }
101
102 if (method) {
103 BT_LIB_LOGI("Calling user's component finalization method: "
104 "%![comp-]+c", comp);
105 method(comp);
106 }
107 }
108
109 static
110 void destroy_component(struct bt_object *obj)
111 {
112 struct bt_component *component = NULL;
113 int i;
114
115 if (!obj) {
116 return;
117 }
118
119 /*
120 * The component's reference count is 0 if we're here. Increment
121 * it to avoid a double-destroy (possibly infinitely recursive).
122 * This could happen for example if the component's finalization
123 * function does bt_object_get_ref() (or anything that causes
124 * bt_object_get_ref() to be called) on itself (ref. count goes
125 * from 0 to 1), and then bt_object_put_ref(): the reference
126 * count would go from 1 to 0 again and this function would be
127 * called again.
128 */
129 obj->ref_count++;
130 component = container_of(obj, struct bt_component, base);
131 BT_LIB_LOGI("Destroying component: %![comp-]+c, %![graph-]+g",
132 component, bt_component_borrow_graph(component));
133
134 /* Call destroy listeners in reverse registration order */
135 BT_LOGD_STR("Calling destroy listeners.");
136
137 for (i = component->destroy_listeners->len - 1; i >= 0; i--) {
138 struct bt_component_destroy_listener *listener =
139 &g_array_index(component->destroy_listeners,
140 struct bt_component_destroy_listener, i);
141
142 listener->func(component, listener->data);
143 }
144
145 /*
146 * User data is destroyed first, followed by the concrete
147 * component instance. Do not finalize if the component's user
148 * initialization method failed in the first place.
149 */
150 if (component->initialized) {
151 finalize_component(component);
152 }
153
154 if (component->destroy) {
155 BT_LOGD_STR("Destroying type-specific data.");
156 component->destroy(component);
157 }
158
159 if (component->input_ports) {
160 BT_LOGD_STR("Destroying input ports.");
161 g_ptr_array_free(component->input_ports, TRUE);
162 component->input_ports = NULL;
163 }
164
165 if (component->output_ports) {
166 BT_LOGD_STR("Destroying output ports.");
167 g_ptr_array_free(component->output_ports, TRUE);
168 component->output_ports = NULL;
169 }
170
171 if (component->destroy_listeners) {
172 g_array_free(component->destroy_listeners, TRUE);
173 component->destroy_listeners = NULL;
174 }
175
176 if (component->name) {
177 g_string_free(component->name, TRUE);
178 component->name = NULL;
179 }
180
181 BT_LOGD_STR("Putting component class.");
182 BT_OBJECT_PUT_REF_AND_RESET(component->class);
183 g_free(component);
184 }
185
186 enum bt_component_class_type bt_component_get_class_type(
187 const struct bt_component *component)
188 {
189 BT_ASSERT_PRE_NON_NULL(component, "Component");
190 return component->class->type;
191 }
192
193 static
194 enum bt_self_component_status add_port(
195 struct bt_component *component, GPtrArray *ports,
196 enum bt_port_type port_type, const char *name, void *user_data,
197 struct bt_port **port)
198 {
199 struct bt_port *new_port = NULL;
200 struct bt_graph *graph = NULL;
201 enum bt_self_component_status status;
202
203 BT_ASSERT_PRE_NON_NULL(component, "Component");
204 BT_ASSERT_PRE_NON_NULL(name, "Name");
205 BT_ASSERT_PRE(strlen(name) > 0, "Name is empty");
206 graph = bt_component_borrow_graph(component);
207 BT_ASSERT_PRE(graph && !bt_graph_is_canceled(graph),
208 "Component's graph is canceled: %![comp-]+c, %![graph-]+g",
209 component, graph);
210 BT_ASSERT_PRE(
211 graph->config_state == BT_GRAPH_CONFIGURATION_STATE_CONFIGURING,
212 "Component's graph is already configured: "
213 "%![comp-]+c, %![graph-]+g", component, graph);
214
215 // TODO: Validate that the name is not already used.
216
217 BT_LIB_LOGI("Adding port to component: %![comp-]+c, "
218 "port-type=%s, port-name=\"%s\"", component,
219 bt_port_type_string(port_type), name);
220
221 new_port = bt_port_create(component, port_type, name, user_data);
222 if (!new_port) {
223 BT_LOGE_STR("Cannot create port object.");
224 status = BT_SELF_COMPONENT_STATUS_NOMEM;
225 goto error;
226 }
227
228 /*
229 * No name clash, add the port.
230 * The component is now the port's parent; it should _not_
231 * hold a reference to the port since the port's lifetime
232 * is now protected by the component's own lifetime.
233 */
234 g_ptr_array_add(ports, new_port);
235
236 /*
237 * Notify the graph's creator that a new port was added.
238 */
239 graph = bt_component_borrow_graph(component);
240 if (graph) {
241 enum bt_graph_listener_status listener_status;
242
243 listener_status = bt_graph_notify_port_added(graph, new_port);
244 if (listener_status != BT_GRAPH_LISTENER_STATUS_OK) {
245 bt_graph_make_faulty(graph);
246 status = listener_status;
247 goto error;
248 }
249 }
250
251 BT_LIB_LOGI("Created and added port to component: "
252 "%![comp-]+c, %![port-]+p", component, new_port);
253
254 *port = new_port;
255 status = BT_SELF_COMPONENT_STATUS_OK;
256
257 goto end;
258 error:
259 /*
260 * We need to release the reference that we would otherwise have
261 * returned to the caller.
262 */
263 BT_PORT_PUT_REF_AND_RESET(new_port);
264
265 end:
266 return status;
267 }
268
269 BT_HIDDEN
270 uint64_t bt_component_get_input_port_count(const struct bt_component *comp)
271 {
272 BT_ASSERT_PRE_NON_NULL(comp, "Component");
273 return (uint64_t) comp->input_ports->len;
274 }
275
276 BT_HIDDEN
277 uint64_t bt_component_get_output_port_count(const struct bt_component *comp)
278 {
279 BT_ASSERT_PRE_NON_NULL(comp, "Component");
280 return (uint64_t) comp->output_ports->len;
281 }
282
283 BT_HIDDEN
284 int bt_component_create(struct bt_component_class *component_class,
285 const char *name, struct bt_component **user_component)
286 {
287 int ret = 0;
288 struct bt_component *component = NULL;
289 enum bt_component_class_type type;
290
291 BT_ASSERT(user_component);
292 BT_ASSERT(component_class);
293 BT_ASSERT(name);
294 type = bt_component_class_get_type(component_class);
295 BT_LIB_LOGI("Creating empty component from component class: %![cc-]+C, "
296 "comp-name=\"%s\"", component_class, name);
297 component = component_create_funcs[type](component_class);
298 if (!component) {
299 BT_LOGE_STR("Cannot create specific component object.");
300 ret = -1;
301 goto end;
302 }
303
304 bt_object_init_shared_with_parent(&component->base, destroy_component);
305 component->class = component_class;
306 bt_object_get_no_null_check(component->class);
307 component->destroy = component_destroy_funcs[type];
308 component->name = g_string_new(name);
309 if (!component->name) {
310 BT_LOGE_STR("Failed to allocate one GString.");
311 ret = -1;
312 goto end;
313 }
314
315 component->input_ports = g_ptr_array_new_with_free_func(
316 (GDestroyNotify) bt_object_try_spec_release);
317 if (!component->input_ports) {
318 BT_LOGE_STR("Failed to allocate one GPtrArray.");
319 ret = -1;
320 goto end;
321 }
322
323 component->output_ports = g_ptr_array_new_with_free_func(
324 (GDestroyNotify) bt_object_try_spec_release);
325 if (!component->output_ports) {
326 BT_LOGE_STR("Failed to allocate one GPtrArray.");
327 ret = -1;
328 goto end;
329 }
330
331 component->destroy_listeners = g_array_new(FALSE, TRUE,
332 sizeof(struct bt_component_destroy_listener));
333 if (!component->destroy_listeners) {
334 BT_LOGE_STR("Failed to allocate one GArray.");
335 ret = -1;
336 goto end;
337 }
338
339 BT_LIB_LOGI("Created empty component from component class: "
340 "%![cc-]+C, %![comp-]+c", component_class, component);
341 BT_OBJECT_MOVE_REF(*user_component, component);
342
343 end:
344 bt_object_put_ref(component);
345 return ret;
346 }
347
348 const char *bt_component_get_name(const struct bt_component *component)
349 {
350 BT_ASSERT_PRE_NON_NULL(component, "Component");
351 return component->name->str;
352 }
353
354 const struct bt_component_class *bt_component_borrow_class_const(
355 const struct bt_component *component)
356 {
357 BT_ASSERT_PRE_NON_NULL(component, "Component");
358 return component->class;
359 }
360
361 void *bt_self_component_get_data(const struct bt_self_component *self_comp)
362 {
363 struct bt_component *component = (void *) self_comp;
364
365 BT_ASSERT_PRE_NON_NULL(component, "Component");
366 return component->user_data;
367 }
368
369 void bt_self_component_set_data(struct bt_self_component *self_comp,
370 void *data)
371 {
372 struct bt_component *component = (void *) self_comp;
373
374 BT_ASSERT_PRE_NON_NULL(component, "Component");
375 component->user_data = data;
376 BT_LIB_LOGD("Set component's user data: %!+c", component);
377 }
378
379 BT_HIDDEN
380 void bt_component_set_graph(struct bt_component *component,
381 struct bt_graph *graph)
382 {
383 bt_object_set_parent(&component->base,
384 graph ? &graph->base : NULL);
385 }
386
387 bt_bool bt_component_graph_is_canceled(const struct bt_component *component)
388 {
389 return bt_graph_is_canceled(
390 (void *) bt_object_borrow_parent(&component->base));
391 }
392
393 static
394 struct bt_port *borrow_port_by_name(GPtrArray *ports,
395 const char *name)
396 {
397 uint64_t i;
398 struct bt_port *ret_port = NULL;
399
400 BT_ASSERT(name);
401
402 for (i = 0; i < ports->len; i++) {
403 struct bt_port *port = g_ptr_array_index(ports, i);
404
405 if (!strcmp(name, port->name->str)) {
406 ret_port = port;
407 break;
408 }
409 }
410
411 return ret_port;
412 }
413
414 BT_HIDDEN
415 struct bt_port_input *bt_component_borrow_input_port_by_name(
416 struct bt_component *comp, const char *name)
417 {
418 BT_ASSERT(comp);
419 return (void *) borrow_port_by_name(comp->input_ports, name);
420 }
421
422 BT_HIDDEN
423 struct bt_port_output *bt_component_borrow_output_port_by_name(
424 struct bt_component *comp, const char *name)
425 {
426 BT_ASSERT_PRE_NON_NULL(comp, "Component");
427 return (void *)
428 borrow_port_by_name(comp->output_ports, name);
429 }
430
431 static
432 struct bt_port *borrow_port_by_index(GPtrArray *ports, uint64_t index)
433 {
434 BT_ASSERT(index < ports->len);
435 return g_ptr_array_index(ports, index);
436 }
437
438 BT_HIDDEN
439 struct bt_port_input *bt_component_borrow_input_port_by_index(
440 struct bt_component *comp, uint64_t index)
441 {
442 BT_ASSERT_PRE_NON_NULL(comp, "Component");
443 BT_ASSERT_PRE_VALID_INDEX(index, comp->input_ports->len);
444 return (void *)
445 borrow_port_by_index(comp->input_ports, index);
446 }
447
448 BT_HIDDEN
449 struct bt_port_output *bt_component_borrow_output_port_by_index(
450 struct bt_component *comp, uint64_t index)
451 {
452 BT_ASSERT_PRE_NON_NULL(comp, "Component");
453 BT_ASSERT_PRE_VALID_INDEX(index, comp->output_ports->len);
454 return (void *)
455 borrow_port_by_index(comp->output_ports, index);
456 }
457
458 BT_HIDDEN
459 enum bt_self_component_status bt_component_add_input_port(
460 struct bt_component *component, const char *name,
461 void *user_data, struct bt_port **port)
462 {
463 /* add_port() logs details */
464 return add_port(component, component->input_ports,
465 BT_PORT_TYPE_INPUT, name, user_data, port);
466 }
467
468 BT_HIDDEN
469 enum bt_self_component_status bt_component_add_output_port(
470 struct bt_component *component, const char *name,
471 void *user_data, struct bt_port **port)
472 {
473 /* add_port() logs details */
474 return add_port(component, component->output_ports,
475 BT_PORT_TYPE_OUTPUT, name, user_data, port);
476 }
477
478 BT_HIDDEN
479 enum bt_self_component_status bt_component_accept_port_connection(
480 struct bt_component *comp, struct bt_port *self_port,
481 struct bt_port *other_port)
482 {
483 typedef enum bt_self_component_status (*method_t)(
484 void *, void *, const void *);
485
486 enum bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
487 method_t method = NULL;
488
489 BT_ASSERT(comp);
490 BT_ASSERT(self_port);
491 BT_ASSERT(other_port);
492
493 switch (comp->class->type) {
494 case BT_COMPONENT_CLASS_TYPE_SOURCE:
495 {
496 struct bt_component_class_source *src_cc = (void *) comp->class;
497
498 switch (self_port->type) {
499 case BT_PORT_TYPE_OUTPUT:
500 method = (method_t) src_cc->methods.accept_output_port_connection;
501 break;
502 default:
503 abort();
504 }
505
506 break;
507 }
508 case BT_COMPONENT_CLASS_TYPE_FILTER:
509 {
510 struct bt_component_class_filter *flt_cc = (void *) comp->class;
511
512 switch (self_port->type) {
513 case BT_PORT_TYPE_INPUT:
514 method = (method_t) flt_cc->methods.accept_input_port_connection;
515 break;
516 case BT_PORT_TYPE_OUTPUT:
517 method = (method_t) flt_cc->methods.accept_output_port_connection;
518 break;
519 default:
520 abort();
521 }
522
523 break;
524 }
525 case BT_COMPONENT_CLASS_TYPE_SINK:
526 {
527 struct bt_component_class_sink *sink_cc = (void *) comp->class;
528
529 switch (self_port->type) {
530 case BT_PORT_TYPE_INPUT:
531 method = (method_t) sink_cc->methods.accept_input_port_connection;
532 break;
533 default:
534 abort();
535 }
536
537 break;
538 }
539 default:
540 abort();
541 }
542
543 if (method) {
544 BT_LIB_LOGD("Calling user's \"accept port connection\" method: "
545 "%![comp-]+c, %![self-port-]+p, %![other-port-]+p",
546 comp, self_port, other_port);
547 status = method(comp, self_port, (void *) other_port);
548 BT_LOGD("User method returned: status=%s",
549 bt_self_component_status_string(status));
550 }
551
552 return status;
553 }
554
555 BT_HIDDEN
556 enum bt_self_component_status bt_component_port_connected(
557 struct bt_component *comp, struct bt_port *self_port,
558 struct bt_port *other_port)
559 {
560 typedef enum bt_self_component_status (*method_t)(
561 void *, void *, const void *);
562
563 enum bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
564 method_t method = NULL;
565
566 BT_ASSERT(comp);
567 BT_ASSERT(self_port);
568 BT_ASSERT(other_port);
569
570 switch (comp->class->type) {
571 case BT_COMPONENT_CLASS_TYPE_SOURCE:
572 {
573 struct bt_component_class_source *src_cc = (void *) comp->class;
574
575 switch (self_port->type) {
576 case BT_PORT_TYPE_OUTPUT:
577 method = (method_t) src_cc->methods.output_port_connected;
578 break;
579 default:
580 abort();
581 }
582
583 break;
584 }
585 case BT_COMPONENT_CLASS_TYPE_FILTER:
586 {
587 struct bt_component_class_filter *flt_cc = (void *) comp->class;
588
589 switch (self_port->type) {
590 case BT_PORT_TYPE_INPUT:
591 method = (method_t) flt_cc->methods.input_port_connected;
592 break;
593 case BT_PORT_TYPE_OUTPUT:
594 method = (method_t) flt_cc->methods.output_port_connected;
595 break;
596 default:
597 abort();
598 }
599
600 break;
601 }
602 case BT_COMPONENT_CLASS_TYPE_SINK:
603 {
604 struct bt_component_class_sink *sink_cc = (void *) comp->class;
605
606 switch (self_port->type) {
607 case BT_PORT_TYPE_INPUT:
608 method = (method_t) sink_cc->methods.input_port_connected;
609 break;
610 default:
611 abort();
612 }
613
614 break;
615 }
616 default:
617 abort();
618 }
619
620 if (method) {
621 BT_LIB_LOGD("Calling user's \"port connected\" method: "
622 "%![comp-]+c, %![self-port-]+p, %![other-port-]+p",
623 comp, self_port, other_port);
624 status = method(comp, self_port, (void *) other_port);
625 BT_LOGD("User method returned: status=%s",
626 bt_self_component_status_string(status));
627 BT_ASSERT_PRE(status == BT_SELF_COMPONENT_STATUS_OK ||
628 status == BT_SELF_COMPONENT_STATUS_ERROR ||
629 status == BT_SELF_COMPONENT_STATUS_NOMEM,
630 "Unexpected returned component status: status=%s",
631 bt_self_component_status_string(status));
632 }
633
634 return status;
635 }
636
637 BT_HIDDEN
638 void bt_component_add_destroy_listener(struct bt_component *component,
639 bt_component_destroy_listener_func func, void *data)
640 {
641 struct bt_component_destroy_listener listener;
642
643 BT_ASSERT(component);
644 BT_ASSERT(func);
645 listener.func = func;
646 listener.data = data;
647 g_array_append_val(component->destroy_listeners, listener);
648 BT_LIB_LOGD("Added destroy listener: %![comp-]+c, "
649 "func-addr=%p, data-addr=%p",
650 component, func, data);
651 }
652
653 BT_HIDDEN
654 void bt_component_remove_destroy_listener(struct bt_component *component,
655 bt_component_destroy_listener_func func, void *data)
656 {
657 uint64_t i;
658
659 BT_ASSERT(component);
660 BT_ASSERT(func);
661
662 for (i = 0; i < component->destroy_listeners->len; i++) {
663 struct bt_component_destroy_listener *listener =
664 &g_array_index(component->destroy_listeners,
665 struct bt_component_destroy_listener, i);
666
667 if (listener->func == func && listener->data == data) {
668 g_array_remove_index(component->destroy_listeners, i);
669 i--;
670 BT_LIB_LOGD("Removed destroy listener: %![comp-]+c, "
671 "func-addr=%p, data-addr=%p",
672 component, func, data);
673 }
674 }
675 }
676
677 void bt_component_get_ref(const struct bt_component *component)
678 {
679 bt_object_get_ref(component);
680 }
681
682 void bt_component_put_ref(const struct bt_component *component)
683 {
684 bt_object_put_ref(component);
685 }
This page took 0.042422 seconds and 4 git commands to generate.