Add graph event listeners
[babeltrace.git] / lib / component / 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
33b34c43
PP
29#include <babeltrace/component/component.h>
30#include <babeltrace/component/component-internal.h>
d3e4dcd8 31#include <babeltrace/component/component-class-internal.h>
d71dcf2c
PP
32#include <babeltrace/component/component-source-internal.h>
33#include <babeltrace/component/component-filter-internal.h>
34#include <babeltrace/component/component-sink-internal.h>
72b913fb 35#include <babeltrace/component/connection-internal.h>
7d55361f 36#include <babeltrace/component/graph-internal.h>
33b34c43 37#include <babeltrace/component/notification/iterator-internal.h>
de713ce0
JG
38#include <babeltrace/babeltrace-internal.h>
39#include <babeltrace/compiler.h>
b8a06801 40#include <babeltrace/ref.h>
de713ce0 41
7c7c0433
JG
42static
43struct bt_component * (* const component_create_funcs[])(
44 struct bt_component_class *, struct bt_value *) = {
d3e4dcd8
PP
45 [BT_COMPONENT_CLASS_TYPE_SOURCE] = bt_component_source_create,
46 [BT_COMPONENT_CLASS_TYPE_SINK] = bt_component_sink_create,
47 [BT_COMPONENT_CLASS_TYPE_FILTER] = bt_component_filter_create,
7c7c0433
JG
48};
49
72b913fb
PP
50static
51void (*component_destroy_funcs[])(struct bt_component *) = {
52 [BT_COMPONENT_CLASS_TYPE_SOURCE] = bt_component_source_destroy,
53 [BT_COMPONENT_CLASS_TYPE_SINK] = bt_component_sink_destroy,
54 [BT_COMPONENT_CLASS_TYPE_FILTER] = bt_component_filter_destroy,
55};
56
7c7c0433
JG
57static
58enum bt_component_status (* const component_validation_funcs[])(
59 struct bt_component *) = {
d3e4dcd8
PP
60 [BT_COMPONENT_CLASS_TYPE_SOURCE] = bt_component_source_validate,
61 [BT_COMPONENT_CLASS_TYPE_SINK] = bt_component_sink_validate,
62 [BT_COMPONENT_CLASS_TYPE_FILTER] = bt_component_filter_validate,
7c7c0433
JG
63};
64
b8a06801
JG
65static
66void bt_component_destroy(struct bt_object *obj)
67{
68 struct bt_component *component = NULL;
69 struct bt_component_class *component_class = NULL;
70
71 if (!obj) {
72 return;
73 }
74
75 component = container_of(obj, struct bt_component, base);
7c7c0433
JG
76 component_class = component->class;
77
78 /*
b8a06801
JG
79 * User data is destroyed first, followed by the concrete component
80 * instance.
81 */
d3e4dcd8
PP
82 if (component->class->methods.destroy) {
83 component->class->methods.destroy(component);
7c7c0433 84 }
b8a06801 85
ab09f844
JG
86 if (component->destroy) {
87 component->destroy(component);
88 }
89
72b913fb
PP
90 if (component->input_ports) {
91 g_ptr_array_free(component->input_ports, TRUE);
92 }
b8a06801 93
72b913fb
PP
94 if (component->output_ports) {
95 g_ptr_array_free(component->output_ports, TRUE);
b8a06801
JG
96 }
97
72b913fb
PP
98 g_string_free(component->name, TRUE);
99 bt_put(component_class);
100 g_free(component);
b8a06801 101}
de713ce0 102
d3e4dcd8
PP
103enum bt_component_class_type bt_component_get_class_type(
104 struct bt_component *component)
38b48196 105{
d3e4dcd8 106 return component ? component->class->type : BT_COMPONENT_CLASS_TYPE_UNKNOWN;
38b48196
JG
107}
108
5645cd95
JG
109BT_HIDDEN
110struct bt_notification_iterator *bt_component_create_iterator(
8b0ce102 111 struct bt_component *component, void *init_method_data)
5645cd95
JG
112{
113 enum bt_notification_iterator_status ret_iterator;
d3e4dcd8 114 enum bt_component_class_type type;
5645cd95 115 struct bt_notification_iterator *iterator = NULL;
d3e4dcd8 116 struct bt_component_class *class = component->class;
5645cd95
JG
117
118 if (!component) {
119 goto error;
120 }
121
d3e4dcd8
PP
122 type = bt_component_get_class_type(component);
123 if (type != BT_COMPONENT_CLASS_TYPE_SOURCE &&
124 type != BT_COMPONENT_CLASS_TYPE_FILTER) {
5645cd95
JG
125 /* Unsupported operation. */
126 goto error;
127 }
128
129 iterator = bt_notification_iterator_create(component);
130 if (!iterator) {
131 goto error;
132 }
133
d3e4dcd8
PP
134 switch (type) {
135 case BT_COMPONENT_CLASS_TYPE_SOURCE:
5645cd95 136 {
d3e4dcd8 137 struct bt_component_class_source *source_class;
d3eb6e8f 138 enum bt_notification_iterator_status status;
5645cd95 139
d3e4dcd8 140 source_class = container_of(class, struct bt_component_class_source, parent);
5964a444
PP
141
142 if (source_class->methods.iterator.init) {
143 status = source_class->methods.iterator.init(component,
144 iterator, init_method_data);
145 if (status < 0) {
146 goto error;
147 }
5645cd95
JG
148 }
149 break;
5645cd95 150 }
d3e4dcd8 151 case BT_COMPONENT_CLASS_TYPE_FILTER:
5645cd95 152 {
d3e4dcd8 153 struct bt_component_class_filter *filter_class;
d3eb6e8f 154 enum bt_notification_iterator_status status;
5645cd95 155
d3e4dcd8 156 filter_class = container_of(class, struct bt_component_class_filter, parent);
5964a444
PP
157
158 if (filter_class->methods.iterator.init) {
159 status = filter_class->methods.iterator.init(component,
160 iterator, init_method_data);
161 if (status < 0) {
162 goto error;
163 }
5645cd95
JG
164 }
165 break;
166 }
167 default:
168 /* Unreachable. */
169 assert(0);
170 }
171
172 ret_iterator = bt_notification_iterator_validate(iterator);
173 if (ret_iterator != BT_NOTIFICATION_ITERATOR_STATUS_OK) {
174 goto error;
175 }
176
177 return iterator;
178error:
179 BT_PUT(iterator);
180 return iterator;
181}
182
72b913fb
PP
183static
184struct bt_port *bt_component_add_port(
185 struct bt_component *component, GPtrArray *ports,
186 enum bt_port_type port_type, const char *name)
187{
188 size_t i;
189 struct bt_port *new_port = NULL;
1bf957a0 190 struct bt_graph *graph = NULL;
72b913fb
PP
191
192 if (!name || strlen(name) == 0) {
193 goto end;
194 }
195
196 /* Look for a port having the same name. */
197 for (i = 0; i < ports->len; i++) {
198 const char *port_name;
199 struct bt_port *port = g_ptr_array_index(
200 ports, i);
201
202 port_name = bt_port_get_name(port);
203 if (!port_name) {
204 continue;
205 }
206
207 if (!strcmp(name, port_name)) {
208 /* Port name clash, abort. */
209 goto end;
210 }
211 }
212
213 new_port = bt_port_create(component, port_type, name);
214 if (!new_port) {
215 goto end;
216 }
217
218 /*
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.
223 */
224 g_ptr_array_add(ports, new_port);
1bf957a0
PP
225
226 /*
227 * Notify the graph's creator that a new port was added.
228 */
229 graph = bt_component_get_graph(component);
230 if (graph) {
231 bt_graph_notify_port_added(graph, new_port);
232 BT_PUT(graph);
233 }
234
72b913fb
PP
235end:
236 return new_port;
237}
238
239BT_HIDDEN
240uint64_t bt_component_get_input_port_count(struct bt_component *comp)
241{
242 assert(comp);
243 return comp->input_ports->len;
244}
245
246BT_HIDDEN
247uint64_t bt_component_get_output_port_count(struct bt_component *comp)
248{
249 assert(comp);
250 return comp->output_ports->len;
251}
252
6358c163 253struct bt_component *bt_component_create_with_init_method_data(
7c7c0433 254 struct bt_component_class *component_class, const char *name,
6358c163 255 struct bt_value *params, void *init_method_data)
38b48196 256{
7c7c0433 257 int ret;
38b48196 258 struct bt_component *component = NULL;
d3e4dcd8 259 enum bt_component_class_type type;
72b913fb 260 struct bt_port *default_port = NULL;
38b48196
JG
261
262 if (!component_class) {
263 goto end;
264 }
265
7c7c0433 266 type = bt_component_class_get_type(component_class);
d3e4dcd8
PP
267 if (type <= BT_COMPONENT_CLASS_TYPE_UNKNOWN ||
268 type > BT_COMPONENT_CLASS_TYPE_FILTER) {
7c7c0433
JG
269 goto end;
270 }
271
272 component = component_create_funcs[type](component_class, params);
273 if (!component) {
274 goto end;
275 }
276
277 bt_object_init(component, bt_component_destroy);
72b913fb
PP
278 component->class = bt_get(component_class);
279 component->destroy = component_destroy_funcs[type];
7c7c0433 280 component->name = g_string_new(name);
4b70dd83 281 if (!component->name) {
7c7c0433
JG
282 BT_PUT(component);
283 goto end;
284 }
285
72b913fb
PP
286 component->input_ports = g_ptr_array_new_with_free_func(
287 bt_object_release);
288 if (!component->input_ports) {
289 BT_PUT(component);
290 goto end;
291 }
292
293 component->output_ports = g_ptr_array_new_with_free_func(
294 bt_object_release);
295 if (!component->output_ports) {
296 BT_PUT(component);
297 goto end;
298 }
299
300 if (type == BT_COMPONENT_CLASS_TYPE_SOURCE ||
301 type == BT_COMPONENT_CLASS_TYPE_FILTER) {
302 default_port = bt_component_add_port(component,
303 component->output_ports, BT_PORT_TYPE_OUTPUT,
304 DEFAULT_OUTPUT_PORT_NAME);
305 if (!default_port) {
306 BT_PUT(component);
307 goto end;
308 }
309
310 BT_PUT(default_port);
311 }
312
313 if (type == BT_COMPONENT_CLASS_TYPE_FILTER ||
314 type == BT_COMPONENT_CLASS_TYPE_SINK) {
315 default_port = bt_component_add_port(component,
316 component->input_ports, BT_PORT_TYPE_INPUT,
317 DEFAULT_INPUT_PORT_NAME);
318 if (!default_port) {
319 BT_PUT(component);
320 goto end;
321 }
322
323 BT_PUT(default_port);
324 }
325
326 component->initializing = true;
327
d3e4dcd8 328 if (component_class->methods.init) {
6358c163
PP
329 ret = component_class->methods.init(component, params,
330 init_method_data);
d3e4dcd8
PP
331 component->initializing = false;
332 if (ret != BT_COMPONENT_STATUS_OK) {
333 BT_PUT(component);
334 goto end;
335 }
528debdf 336 }
d3e4dcd8
PP
337
338 component->initializing = false;
7c7c0433 339 ret = component_validation_funcs[type](component);
692b38d2 340 if (ret != BT_COMPONENT_STATUS_OK) {
7c7c0433 341 BT_PUT(component);
38b48196
JG
342 goto end;
343 }
1e4d8103
PP
344
345 bt_component_class_freeze(component->class);
38b48196 346end:
72b913fb 347 bt_put(default_port);
38b48196
JG
348 return component;
349}
350
6358c163
PP
351struct bt_component *bt_component_create(
352 struct bt_component_class *component_class, const char *name,
353 struct bt_value *params)
354{
355 return bt_component_create_with_init_method_data(component_class, name,
356 params, NULL);
357}
358
de713ce0
JG
359const char *bt_component_get_name(struct bt_component *component)
360{
361 const char *ret = NULL;
362
363 if (!component) {
364 goto end;
365 }
366
f1222e7d 367 ret = component->name->len == 0 ? NULL : component->name->str;
de713ce0
JG
368end:
369 return ret;
370}
371
372enum bt_component_status bt_component_set_name(struct bt_component *component,
373 const char *name)
374{
375 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
376
377 if (!component || !name || name[0] == '\0') {
30d619df 378 ret = BT_COMPONENT_STATUS_INVALID;
de713ce0
JG
379 goto end;
380 }
381
382 g_string_assign(component->name, name);
383end:
384 return ret;
385}
386
38b48196
JG
387struct bt_component_class *bt_component_get_class(
388 struct bt_component *component)
de713ce0 389{
38b48196 390 return component ? bt_get(component->class) : NULL;
de713ce0
JG
391}
392
de713ce0
JG
393void *bt_component_get_private_data(struct bt_component *component)
394{
38b48196 395 return component ? component->user_data : NULL;
de713ce0
JG
396}
397
398enum bt_component_status
399bt_component_set_private_data(struct bt_component *component,
400 void *data)
401{
402 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
403
fec2a9f2 404 if (!component || !component->initializing) {
30d619df 405 ret = BT_COMPONENT_STATUS_INVALID;
de713ce0
JG
406 goto end;
407 }
408
409 component->user_data = data;
410end:
411 return ret;
412}
366e034f
JG
413
414BT_HIDDEN
f60c8b34 415void bt_component_set_graph(struct bt_component *component,
366e034f
JG
416 struct bt_graph *graph)
417{
f60c8b34
JG
418 struct bt_object *parent = bt_object_get_parent(&component->base);
419
420 assert(!parent || parent == &graph->base);
421 if (!parent) {
422 bt_object_set_parent(component, &graph->base);
423 }
424 bt_put(parent);
366e034f
JG
425}
426
427struct bt_graph *bt_component_get_graph(
428 struct bt_component *component)
429{
430 return (struct bt_graph *) bt_object_get_parent(&component->base);
431}
432
72b913fb 433static
366e034f
JG
434struct bt_port *bt_component_get_port(GPtrArray *ports, const char *name)
435{
436 size_t i;
437 struct bt_port *ret_port = NULL;
438
72b913fb
PP
439 assert(name);
440
366e034f
JG
441 for (i = 0; i < ports->len; i++) {
442 struct bt_port *port = g_ptr_array_index(ports, i);
443 const char *port_name = bt_port_get_name(port);
444
445 if (!port_name) {
446 continue;
447 }
448
449 if (!strcmp(name, port_name)) {
450 ret_port = bt_get(port);
451 break;
452 }
453 }
454
455 return ret_port;
456}
457
458BT_HIDDEN
72b913fb
PP
459struct bt_port *bt_component_get_input_port(struct bt_component *comp,
460 const char *name)
461{
462 assert(comp);
463
464 return bt_component_get_port(comp->input_ports, name);
465}
466
467BT_HIDDEN
468struct bt_port *bt_component_get_output_port(struct bt_component *comp,
469 const char *name)
470{
471 assert(comp);
472
473 return bt_component_get_port(comp->output_ports, name);
474}
475
476static
366e034f
JG
477struct bt_port *bt_component_get_port_at_index(GPtrArray *ports, int index)
478{
479 struct bt_port *port = NULL;
480
481 if (index < 0 || index >= ports->len) {
482 goto end;
483 }
484
485 port = bt_get(g_ptr_array_index(ports, index));
486end:
487 return port;
488}
489
490BT_HIDDEN
72b913fb
PP
491struct bt_port *bt_component_get_input_port_at_index(struct bt_component *comp,
492 int index)
366e034f 493{
72b913fb 494 assert(comp);
366e034f 495
72b913fb
PP
496 return bt_component_get_port_at_index(comp->input_ports, index);
497}
366e034f 498
72b913fb
PP
499BT_HIDDEN
500struct bt_port *bt_component_get_output_port_at_index(struct bt_component *comp,
501 int index)
502{
503 assert(comp);
366e034f 504
72b913fb
PP
505 return bt_component_get_port_at_index(comp->output_ports, index);
506}
366e034f 507
72b913fb
PP
508BT_HIDDEN
509struct bt_port *bt_component_add_input_port(
510 struct bt_component *component, const char *name)
511{
512 return bt_component_add_port(component, component->input_ports,
513 BT_PORT_TYPE_INPUT, name);
514}
366e034f 515
72b913fb
PP
516BT_HIDDEN
517struct bt_port *bt_component_add_output_port(
518 struct bt_component *component, const char *name)
519{
520 return bt_component_add_port(component, component->output_ports,
521 BT_PORT_TYPE_OUTPUT, name);
522}
523
524static
525void bt_component_remove_port_at_index(struct bt_component *component,
526 GPtrArray *ports, size_t index)
527{
528 struct bt_port *port;
1bf957a0 529 struct bt_graph *graph;
72b913fb
PP
530
531 assert(ports);
532 assert(index < ports->len);
533 port = g_ptr_array_index(ports, index);
534
535 /* Disconnect both ports of this port's connection, if any */
536 if (port->connection) {
537 bt_connection_disconnect_ports(port->connection, component);
f60c8b34
JG
538 }
539
72b913fb
PP
540 /* Remove from parent's array of ports (weak refs) */
541 g_ptr_array_remove_index(ports, index);
542
543 /* Detach port from its component parent */
544 BT_PUT(port->base.parent);
545
1bf957a0
PP
546 /*
547 * Notify the graph's creator that a port is removed.
548 */
549 graph = bt_component_get_graph(component);
550 if (graph) {
551 bt_graph_notify_port_removed(graph, component, port);
552 BT_PUT(graph);
553 }
366e034f
JG
554}
555
556BT_HIDDEN
557enum bt_component_status bt_component_remove_port(
72b913fb 558 struct bt_component *component, struct bt_port *port)
366e034f
JG
559{
560 size_t i;
561 enum bt_component_status status = BT_COMPONENT_STATUS_OK;
72b913fb 562 GPtrArray *ports = NULL;
366e034f 563
72b913fb 564 if (!component || !port) {
366e034f
JG
565 status = BT_COMPONENT_STATUS_INVALID;
566 goto end;
567 }
568
72b913fb
PP
569 if (bt_port_get_type(port) == BT_PORT_TYPE_INPUT) {
570 ports = component->input_ports;
571 } else if (bt_port_get_type(port) == BT_PORT_TYPE_OUTPUT) {
572 ports = component->output_ports;
573 }
366e034f 574
72b913fb 575 assert(ports);
366e034f 576
72b913fb
PP
577 for (i = 0; i < ports->len; i++) {
578 struct bt_port *cur_port = g_ptr_array_index(ports, i);
579
580 if (cur_port == port) {
581 bt_component_remove_port_at_index(component,
582 ports, i);
366e034f
JG
583 goto end;
584 }
585 }
72b913fb 586
366e034f
JG
587 status = BT_COMPONENT_STATUS_NOT_FOUND;
588end:
589 return status;
590}
f60c8b34
JG
591
592BT_HIDDEN
72b913fb
PP
593enum bt_component_status bt_component_accept_port_connection(
594 struct bt_component *comp, struct bt_port *port)
f60c8b34
JG
595{
596 enum bt_component_status status = BT_COMPONENT_STATUS_OK;
597
72b913fb
PP
598 assert(comp);
599 assert(port);
600
601 if (comp->class->methods.accept_port_connection) {
602 status = comp->class->methods.accept_port_connection(
603 comp, port);
f60c8b34
JG
604 }
605
606 return status;
607}
72b913fb
PP
608
609BT_HIDDEN
610void bt_component_port_disconnected(struct bt_component *comp,
611 struct bt_port *port)
612{
613 assert(comp);
614 assert(port);
615
616 if (comp->class->methods.port_disconnected) {
617 comp->class->methods.port_disconnected(comp, port);
618 }
619}
This page took 0.054879 seconds and 4 git commands to generate.