Make libctfcopytrace a convenience lib. and link to it in plugins
[babeltrace.git] / lib / graph / component.c
CommitLineData
de713ce0
JG
1/*
2 * component.c
3 *
4 * Babeltrace Plugin Component
5 *
6 * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
7 *
8 * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a copy
11 * of this software and associated documentation files (the "Software"), to deal
12 * in the Software without restriction, including without limitation the rights
13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the Software is
15 * furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 * SOFTWARE.
27 */
28
b2e0c907
PP
29#include <babeltrace/graph/private-component.h>
30#include <babeltrace/graph/component.h>
31#include <babeltrace/graph/component-internal.h>
32#include <babeltrace/graph/component-class-internal.h>
33#include <babeltrace/graph/component-source-internal.h>
34#include <babeltrace/graph/component-filter-internal.h>
35#include <babeltrace/graph/component-sink-internal.h>
36#include <babeltrace/graph/private-connection.h>
37#include <babeltrace/graph/connection-internal.h>
38#include <babeltrace/graph/graph-internal.h>
39#include <babeltrace/graph/notification-iterator-internal.h>
40#include <babeltrace/graph/private-notification-iterator.h>
de713ce0 41#include <babeltrace/babeltrace-internal.h>
3d9990ac 42#include <babeltrace/compiler-internal.h>
b8a06801 43#include <babeltrace/ref.h>
de713ce0 44
7c7c0433
JG
45static
46struct bt_component * (* const component_create_funcs[])(
47 struct bt_component_class *, struct bt_value *) = {
d3e4dcd8
PP
48 [BT_COMPONENT_CLASS_TYPE_SOURCE] = bt_component_source_create,
49 [BT_COMPONENT_CLASS_TYPE_SINK] = bt_component_sink_create,
50 [BT_COMPONENT_CLASS_TYPE_FILTER] = bt_component_filter_create,
7c7c0433
JG
51};
52
72b913fb
PP
53static
54void (*component_destroy_funcs[])(struct bt_component *) = {
55 [BT_COMPONENT_CLASS_TYPE_SOURCE] = bt_component_source_destroy,
56 [BT_COMPONENT_CLASS_TYPE_SINK] = bt_component_sink_destroy,
57 [BT_COMPONENT_CLASS_TYPE_FILTER] = bt_component_filter_destroy,
58};
59
7c7c0433
JG
60static
61enum bt_component_status (* const component_validation_funcs[])(
62 struct bt_component *) = {
d3e4dcd8
PP
63 [BT_COMPONENT_CLASS_TYPE_SOURCE] = bt_component_source_validate,
64 [BT_COMPONENT_CLASS_TYPE_SINK] = bt_component_sink_validate,
65 [BT_COMPONENT_CLASS_TYPE_FILTER] = bt_component_filter_validate,
7c7c0433
JG
66};
67
b8a06801
JG
68static
69void bt_component_destroy(struct bt_object *obj)
70{
71 struct bt_component *component = NULL;
72 struct bt_component_class *component_class = NULL;
3230ee6b 73 int i;
b8a06801
JG
74
75 if (!obj) {
76 return;
77 }
78
79 component = container_of(obj, struct bt_component, base);
3230ee6b
PP
80
81 /* Call destroy listeners in reverse registration order */
82 for (i = component->destroy_listeners->len - 1; i >= 0; i--) {
83 struct bt_component_destroy_listener *listener =
84 &g_array_index(component->destroy_listeners,
85 struct bt_component_destroy_listener, i);
86
87 listener->func(component, listener->data);
88 }
89
7c7c0433
JG
90 component_class = component->class;
91
92 /*
b8a06801
JG
93 * User data is destroyed first, followed by the concrete component
94 * instance.
95 */
64cadc66
PP
96 if (component->class->methods.finalize) {
97 component->class->methods.finalize(
890882ef 98 bt_private_component_from_component(component));
7c7c0433 99 }
b8a06801 100
ab09f844
JG
101 if (component->destroy) {
102 component->destroy(component);
103 }
104
72b913fb
PP
105 if (component->input_ports) {
106 g_ptr_array_free(component->input_ports, TRUE);
107 }
b8a06801 108
72b913fb
PP
109 if (component->output_ports) {
110 g_ptr_array_free(component->output_ports, TRUE);
b8a06801
JG
111 }
112
3230ee6b
PP
113 if (component->destroy_listeners) {
114 g_array_free(component->destroy_listeners, TRUE);
115 }
116
72b913fb
PP
117 g_string_free(component->name, TRUE);
118 bt_put(component_class);
119 g_free(component);
b8a06801 120}
de713ce0 121
890882ef
PP
122struct bt_component *bt_component_from_private_component(
123 struct bt_private_component *private_component)
38b48196 124{
890882ef 125 return bt_get(bt_component_from_private(private_component));
38b48196
JG
126}
127
890882ef
PP
128enum bt_component_class_type bt_component_get_class_type(
129 struct bt_component *component)
5645cd95 130{
890882ef 131 return component ? component->class->type : BT_COMPONENT_CLASS_TYPE_UNKNOWN;
5645cd95
JG
132}
133
72b913fb
PP
134static
135struct bt_port *bt_component_add_port(
136 struct bt_component *component, GPtrArray *ports,
137 enum bt_port_type port_type, const char *name)
138{
139 size_t i;
140 struct bt_port *new_port = NULL;
1bf957a0 141 struct bt_graph *graph = NULL;
72b913fb
PP
142
143 if (!name || strlen(name) == 0) {
144 goto end;
145 }
146
147 /* Look for a port having the same name. */
148 for (i = 0; i < ports->len; i++) {
149 const char *port_name;
150 struct bt_port *port = g_ptr_array_index(
151 ports, i);
152
153 port_name = bt_port_get_name(port);
154 if (!port_name) {
155 continue;
156 }
157
158 if (!strcmp(name, port_name)) {
159 /* Port name clash, abort. */
160 goto end;
161 }
162 }
163
164 new_port = bt_port_create(component, port_type, name);
165 if (!new_port) {
166 goto end;
167 }
168
169 /*
170 * No name clash, add the port.
171 * The component is now the port's parent; it should _not_
172 * hold a reference to the port since the port's lifetime
173 * is now protected by the component's own lifetime.
174 */
175 g_ptr_array_add(ports, new_port);
1bf957a0
PP
176
177 /*
178 * Notify the graph's creator that a new port was added.
179 */
180 graph = bt_component_get_graph(component);
181 if (graph) {
182 bt_graph_notify_port_added(graph, new_port);
183 BT_PUT(graph);
184 }
185
72b913fb
PP
186end:
187 return new_port;
188}
189
190BT_HIDDEN
544d0515 191int64_t bt_component_get_input_port_count(struct bt_component *comp)
72b913fb
PP
192{
193 assert(comp);
194 return comp->input_ports->len;
195}
196
197BT_HIDDEN
544d0515 198int64_t bt_component_get_output_port_count(struct bt_component *comp)
72b913fb
PP
199{
200 assert(comp);
201 return comp->output_ports->len;
202}
203
6358c163 204struct bt_component *bt_component_create_with_init_method_data(
7c7c0433 205 struct bt_component_class *component_class, const char *name,
6358c163 206 struct bt_value *params, void *init_method_data)
38b48196 207{
7c7c0433 208 int ret;
38b48196 209 struct bt_component *component = NULL;
d3e4dcd8 210 enum bt_component_class_type type;
72b913fb 211 struct bt_port *default_port = NULL;
38b48196 212
0df078e5
PP
213 bt_get(params);
214
38b48196
JG
215 if (!component_class) {
216 goto end;
217 }
218
7c7c0433 219 type = bt_component_class_get_type(component_class);
d3e4dcd8
PP
220 if (type <= BT_COMPONENT_CLASS_TYPE_UNKNOWN ||
221 type > BT_COMPONENT_CLASS_TYPE_FILTER) {
7c7c0433
JG
222 goto end;
223 }
224
0df078e5
PP
225 /*
226 * Parameters must be a map value, but we create a convenient
227 * empty one if it's NULL.
228 */
229 if (params) {
230 if (!bt_value_is_map(params)) {
231 goto end;
232 }
233 } else {
234 params = bt_value_map_create();
235 if (!params) {
236 goto end;
237 }
238 }
239
7c7c0433
JG
240 component = component_create_funcs[type](component_class, params);
241 if (!component) {
242 goto end;
243 }
244
245 bt_object_init(component, bt_component_destroy);
72b913fb
PP
246 component->class = bt_get(component_class);
247 component->destroy = component_destroy_funcs[type];
7c7c0433 248 component->name = g_string_new(name);
4b70dd83 249 if (!component->name) {
7c7c0433
JG
250 BT_PUT(component);
251 goto end;
252 }
253
72b913fb
PP
254 component->input_ports = g_ptr_array_new_with_free_func(
255 bt_object_release);
256 if (!component->input_ports) {
257 BT_PUT(component);
258 goto end;
259 }
260
261 component->output_ports = g_ptr_array_new_with_free_func(
262 bt_object_release);
263 if (!component->output_ports) {
264 BT_PUT(component);
265 goto end;
266 }
267
3230ee6b
PP
268 component->destroy_listeners = g_array_new(FALSE, TRUE,
269 sizeof(struct bt_component_destroy_listener));
270 if (!component->destroy_listeners) {
271 BT_PUT(component);
272 goto end;
273 }
274
72b913fb
PP
275 if (type == BT_COMPONENT_CLASS_TYPE_SOURCE ||
276 type == BT_COMPONENT_CLASS_TYPE_FILTER) {
277 default_port = bt_component_add_port(component,
278 component->output_ports, BT_PORT_TYPE_OUTPUT,
279 DEFAULT_OUTPUT_PORT_NAME);
280 if (!default_port) {
281 BT_PUT(component);
282 goto end;
283 }
284
285 BT_PUT(default_port);
286 }
287
288 if (type == BT_COMPONENT_CLASS_TYPE_FILTER ||
289 type == BT_COMPONENT_CLASS_TYPE_SINK) {
290 default_port = bt_component_add_port(component,
291 component->input_ports, BT_PORT_TYPE_INPUT,
292 DEFAULT_INPUT_PORT_NAME);
293 if (!default_port) {
294 BT_PUT(component);
295 goto end;
296 }
297
298 BT_PUT(default_port);
299 }
300
301 component->initializing = true;
302
d3e4dcd8 303 if (component_class->methods.init) {
890882ef
PP
304 ret = component_class->methods.init(
305 bt_private_component_from_component(component), params,
6358c163 306 init_method_data);
d3e4dcd8
PP
307 component->initializing = false;
308 if (ret != BT_COMPONENT_STATUS_OK) {
309 BT_PUT(component);
310 goto end;
311 }
528debdf 312 }
d3e4dcd8
PP
313
314 component->initializing = false;
7c7c0433 315 ret = component_validation_funcs[type](component);
692b38d2 316 if (ret != BT_COMPONENT_STATUS_OK) {
7c7c0433 317 BT_PUT(component);
38b48196
JG
318 goto end;
319 }
1e4d8103
PP
320
321 bt_component_class_freeze(component->class);
38b48196 322end:
0df078e5 323 bt_put(params);
72b913fb 324 bt_put(default_port);
38b48196
JG
325 return component;
326}
327
6358c163
PP
328struct bt_component *bt_component_create(
329 struct bt_component_class *component_class, const char *name,
330 struct bt_value *params)
331{
332 return bt_component_create_with_init_method_data(component_class, name,
333 params, NULL);
334}
335
de713ce0
JG
336const char *bt_component_get_name(struct bt_component *component)
337{
338 const char *ret = NULL;
339
340 if (!component) {
341 goto end;
342 }
343
f1222e7d 344 ret = component->name->len == 0 ? NULL : component->name->str;
de713ce0
JG
345end:
346 return ret;
347}
348
349enum bt_component_status bt_component_set_name(struct bt_component *component,
350 const char *name)
351{
352 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
353
354 if (!component || !name || name[0] == '\0') {
30d619df 355 ret = BT_COMPONENT_STATUS_INVALID;
de713ce0
JG
356 goto end;
357 }
358
359 g_string_assign(component->name, name);
360end:
361 return ret;
362}
363
38b48196
JG
364struct bt_component_class *bt_component_get_class(
365 struct bt_component *component)
de713ce0 366{
38b48196 367 return component ? bt_get(component->class) : NULL;
de713ce0
JG
368}
369
890882ef
PP
370void *bt_private_component_get_user_data(
371 struct bt_private_component *private_component)
de713ce0 372{
890882ef
PP
373 struct bt_component *component =
374 bt_component_from_private(private_component);
375
38b48196 376 return component ? component->user_data : NULL;
de713ce0
JG
377}
378
890882ef
PP
379enum bt_component_status bt_private_component_set_user_data(
380 struct bt_private_component *private_component,
de713ce0
JG
381 void *data)
382{
890882ef
PP
383 struct bt_component *component =
384 bt_component_from_private(private_component);
de713ce0
JG
385 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
386
fec2a9f2 387 if (!component || !component->initializing) {
30d619df 388 ret = BT_COMPONENT_STATUS_INVALID;
de713ce0
JG
389 goto end;
390 }
391
392 component->user_data = data;
393end:
394 return ret;
395}
366e034f
JG
396
397BT_HIDDEN
f60c8b34 398void bt_component_set_graph(struct bt_component *component,
366e034f
JG
399 struct bt_graph *graph)
400{
f60c8b34
JG
401 struct bt_object *parent = bt_object_get_parent(&component->base);
402
403 assert(!parent || parent == &graph->base);
404 if (!parent) {
405 bt_object_set_parent(component, &graph->base);
406 }
407 bt_put(parent);
366e034f
JG
408}
409
410struct bt_graph *bt_component_get_graph(
411 struct bt_component *component)
412{
413 return (struct bt_graph *) bt_object_get_parent(&component->base);
414}
415
72b913fb 416static
366e034f
JG
417struct bt_port *bt_component_get_port(GPtrArray *ports, const char *name)
418{
419 size_t i;
420 struct bt_port *ret_port = NULL;
421
72b913fb
PP
422 assert(name);
423
366e034f
JG
424 for (i = 0; i < ports->len; i++) {
425 struct bt_port *port = g_ptr_array_index(ports, i);
426 const char *port_name = bt_port_get_name(port);
427
428 if (!port_name) {
429 continue;
430 }
431
432 if (!strcmp(name, port_name)) {
433 ret_port = bt_get(port);
434 break;
435 }
436 }
437
438 return ret_port;
439}
440
441BT_HIDDEN
72b913fb
PP
442struct bt_port *bt_component_get_input_port(struct bt_component *comp,
443 const char *name)
444{
445 assert(comp);
446
447 return bt_component_get_port(comp->input_ports, name);
448}
449
450BT_HIDDEN
451struct bt_port *bt_component_get_output_port(struct bt_component *comp,
452 const char *name)
453{
454 assert(comp);
455
456 return bt_component_get_port(comp->output_ports, name);
457}
458
459static
366e034f
JG
460struct bt_port *bt_component_get_port_at_index(GPtrArray *ports, int index)
461{
462 struct bt_port *port = NULL;
463
464 if (index < 0 || index >= ports->len) {
465 goto end;
466 }
467
468 port = bt_get(g_ptr_array_index(ports, index));
469end:
470 return port;
471}
472
473BT_HIDDEN
72b913fb
PP
474struct bt_port *bt_component_get_input_port_at_index(struct bt_component *comp,
475 int index)
366e034f 476{
72b913fb 477 assert(comp);
366e034f 478
72b913fb
PP
479 return bt_component_get_port_at_index(comp->input_ports, index);
480}
366e034f 481
72b913fb
PP
482BT_HIDDEN
483struct bt_port *bt_component_get_output_port_at_index(struct bt_component *comp,
484 int index)
485{
486 assert(comp);
366e034f 487
72b913fb
PP
488 return bt_component_get_port_at_index(comp->output_ports, index);
489}
366e034f 490
72b913fb
PP
491BT_HIDDEN
492struct bt_port *bt_component_add_input_port(
493 struct bt_component *component, const char *name)
494{
495 return bt_component_add_port(component, component->input_ports,
496 BT_PORT_TYPE_INPUT, name);
497}
366e034f 498
72b913fb
PP
499BT_HIDDEN
500struct bt_port *bt_component_add_output_port(
501 struct bt_component *component, const char *name)
502{
503 return bt_component_add_port(component, component->output_ports,
504 BT_PORT_TYPE_OUTPUT, name);
505}
506
507static
508void bt_component_remove_port_at_index(struct bt_component *component,
509 GPtrArray *ports, size_t index)
510{
511 struct bt_port *port;
1bf957a0 512 struct bt_graph *graph;
72b913fb
PP
513
514 assert(ports);
515 assert(index < ports->len);
516 port = g_ptr_array_index(ports, index);
517
518 /* Disconnect both ports of this port's connection, if any */
519 if (port->connection) {
2038affb 520 bt_connection_disconnect_ports(port->connection);
f60c8b34
JG
521 }
522
72b913fb
PP
523 /* Remove from parent's array of ports (weak refs) */
524 g_ptr_array_remove_index(ports, index);
525
526 /* Detach port from its component parent */
527 BT_PUT(port->base.parent);
528
1bf957a0
PP
529 /*
530 * Notify the graph's creator that a port is removed.
531 */
532 graph = bt_component_get_graph(component);
533 if (graph) {
534 bt_graph_notify_port_removed(graph, component, port);
535 BT_PUT(graph);
536 }
366e034f
JG
537}
538
539BT_HIDDEN
540enum bt_component_status bt_component_remove_port(
72b913fb 541 struct bt_component *component, struct bt_port *port)
366e034f
JG
542{
543 size_t i;
544 enum bt_component_status status = BT_COMPONENT_STATUS_OK;
72b913fb 545 GPtrArray *ports = NULL;
366e034f 546
72b913fb 547 if (!component || !port) {
366e034f
JG
548 status = BT_COMPONENT_STATUS_INVALID;
549 goto end;
550 }
551
72b913fb
PP
552 if (bt_port_get_type(port) == BT_PORT_TYPE_INPUT) {
553 ports = component->input_ports;
554 } else if (bt_port_get_type(port) == BT_PORT_TYPE_OUTPUT) {
555 ports = component->output_ports;
556 }
366e034f 557
72b913fb 558 assert(ports);
366e034f 559
72b913fb
PP
560 for (i = 0; i < ports->len; i++) {
561 struct bt_port *cur_port = g_ptr_array_index(ports, i);
562
563 if (cur_port == port) {
564 bt_component_remove_port_at_index(component,
565 ports, i);
366e034f
JG
566 goto end;
567 }
568 }
72b913fb 569
366e034f
JG
570 status = BT_COMPONENT_STATUS_NOT_FOUND;
571end:
572 return status;
573}
f60c8b34
JG
574
575BT_HIDDEN
72b913fb 576enum bt_component_status bt_component_accept_port_connection(
8f4799f7
PP
577 struct bt_component *comp, struct bt_port *self_port,
578 struct bt_port *other_port)
f60c8b34
JG
579{
580 enum bt_component_status status = BT_COMPONENT_STATUS_OK;
581
72b913fb 582 assert(comp);
8f4799f7
PP
583 assert(self_port);
584 assert(other_port);
72b913fb
PP
585
586 if (comp->class->methods.accept_port_connection) {
587 status = comp->class->methods.accept_port_connection(
890882ef 588 bt_private_component_from_component(comp),
8f4799f7
PP
589 bt_private_port_from_port(self_port),
590 other_port);
f60c8b34
JG
591 }
592
593 return status;
594}
72b913fb 595
0d8b4d8e
PP
596BT_HIDDEN
597void bt_component_port_connected(struct bt_component *comp,
598 struct bt_port *self_port, struct bt_port *other_port)
599{
600 assert(comp);
601 assert(self_port);
602 assert(other_port);
603
604 if (comp->class->methods.port_connected) {
605 comp->class->methods.port_connected(
606 bt_private_component_from_component(comp),
607 bt_private_port_from_port(self_port), other_port);
608 }
609}
610
72b913fb
PP
611BT_HIDDEN
612void bt_component_port_disconnected(struct bt_component *comp,
613 struct bt_port *port)
614{
615 assert(comp);
616 assert(port);
617
618 if (comp->class->methods.port_disconnected) {
890882ef
PP
619 comp->class->methods.port_disconnected(
620 bt_private_component_from_component(comp),
621 bt_private_port_from_port(port));
72b913fb
PP
622 }
623}
3230ee6b
PP
624
625BT_HIDDEN
626void bt_component_add_destroy_listener(struct bt_component *component,
627 bt_component_destroy_listener_func func, void *data)
628{
629 struct bt_component_destroy_listener listener;
630
631 assert(component);
632 assert(func);
633 listener.func = func;
634 listener.data = data;
635 g_array_append_val(component->destroy_listeners, listener);
636}
637
638BT_HIDDEN
639void bt_component_remove_destroy_listener(struct bt_component *component,
640 bt_component_destroy_listener_func func, void *data)
641{
642 size_t i;
643
644 assert(component);
645 assert(func);
646
647 for (i = 0; i < component->destroy_listeners->len; i++) {
648 struct bt_component_destroy_listener *listener =
649 &g_array_index(component->destroy_listeners,
650 struct bt_component_destroy_listener, i);
651
652 if (listener->func == func && listener->data == data) {
653 g_array_remove_index(component->destroy_listeners, i);
654 i--;
655 }
656 }
657}
This page took 0.056828 seconds and 4 git commands to generate.