Allow a component to remove a port and any user to disconnect one
[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;
190
191 if (!name || strlen(name) == 0) {
192 goto end;
193 }
194
195 /* Look for a port having the same name. */
196 for (i = 0; i < ports->len; i++) {
197 const char *port_name;
198 struct bt_port *port = g_ptr_array_index(
199 ports, i);
200
201 port_name = bt_port_get_name(port);
202 if (!port_name) {
203 continue;
204 }
205
206 if (!strcmp(name, port_name)) {
207 /* Port name clash, abort. */
208 goto end;
209 }
210 }
211
212 new_port = bt_port_create(component, port_type, name);
213 if (!new_port) {
214 goto end;
215 }
216
217 /*
218 * No name clash, add the port.
219 * The component is now the port's parent; it should _not_
220 * hold a reference to the port since the port's lifetime
221 * is now protected by the component's own lifetime.
222 */
223 g_ptr_array_add(ports, new_port);
224end:
225 return new_port;
226}
227
228BT_HIDDEN
229uint64_t bt_component_get_input_port_count(struct bt_component *comp)
230{
231 assert(comp);
232 return comp->input_ports->len;
233}
234
235BT_HIDDEN
236uint64_t bt_component_get_output_port_count(struct bt_component *comp)
237{
238 assert(comp);
239 return comp->output_ports->len;
240}
241
6358c163 242struct bt_component *bt_component_create_with_init_method_data(
7c7c0433 243 struct bt_component_class *component_class, const char *name,
6358c163 244 struct bt_value *params, void *init_method_data)
38b48196 245{
7c7c0433 246 int ret;
38b48196 247 struct bt_component *component = NULL;
d3e4dcd8 248 enum bt_component_class_type type;
72b913fb 249 struct bt_port *default_port = NULL;
38b48196
JG
250
251 if (!component_class) {
252 goto end;
253 }
254
7c7c0433 255 type = bt_component_class_get_type(component_class);
d3e4dcd8
PP
256 if (type <= BT_COMPONENT_CLASS_TYPE_UNKNOWN ||
257 type > BT_COMPONENT_CLASS_TYPE_FILTER) {
7c7c0433
JG
258 goto end;
259 }
260
261 component = component_create_funcs[type](component_class, params);
262 if (!component) {
263 goto end;
264 }
265
266 bt_object_init(component, bt_component_destroy);
72b913fb
PP
267 component->class = bt_get(component_class);
268 component->destroy = component_destroy_funcs[type];
7c7c0433 269 component->name = g_string_new(name);
4b70dd83 270 if (!component->name) {
7c7c0433
JG
271 BT_PUT(component);
272 goto end;
273 }
274
72b913fb
PP
275 component->input_ports = g_ptr_array_new_with_free_func(
276 bt_object_release);
277 if (!component->input_ports) {
278 BT_PUT(component);
279 goto end;
280 }
281
282 component->output_ports = g_ptr_array_new_with_free_func(
283 bt_object_release);
284 if (!component->output_ports) {
285 BT_PUT(component);
286 goto end;
287 }
288
289 if (type == BT_COMPONENT_CLASS_TYPE_SOURCE ||
290 type == BT_COMPONENT_CLASS_TYPE_FILTER) {
291 default_port = bt_component_add_port(component,
292 component->output_ports, BT_PORT_TYPE_OUTPUT,
293 DEFAULT_OUTPUT_PORT_NAME);
294 if (!default_port) {
295 BT_PUT(component);
296 goto end;
297 }
298
299 BT_PUT(default_port);
300 }
301
302 if (type == BT_COMPONENT_CLASS_TYPE_FILTER ||
303 type == BT_COMPONENT_CLASS_TYPE_SINK) {
304 default_port = bt_component_add_port(component,
305 component->input_ports, BT_PORT_TYPE_INPUT,
306 DEFAULT_INPUT_PORT_NAME);
307 if (!default_port) {
308 BT_PUT(component);
309 goto end;
310 }
311
312 BT_PUT(default_port);
313 }
314
315 component->initializing = true;
316
d3e4dcd8 317 if (component_class->methods.init) {
6358c163
PP
318 ret = component_class->methods.init(component, params,
319 init_method_data);
d3e4dcd8
PP
320 component->initializing = false;
321 if (ret != BT_COMPONENT_STATUS_OK) {
322 BT_PUT(component);
323 goto end;
324 }
528debdf 325 }
d3e4dcd8
PP
326
327 component->initializing = false;
7c7c0433 328 ret = component_validation_funcs[type](component);
692b38d2 329 if (ret != BT_COMPONENT_STATUS_OK) {
7c7c0433 330 BT_PUT(component);
38b48196
JG
331 goto end;
332 }
1e4d8103
PP
333
334 bt_component_class_freeze(component->class);
38b48196 335end:
72b913fb 336 bt_put(default_port);
38b48196
JG
337 return component;
338}
339
6358c163
PP
340struct bt_component *bt_component_create(
341 struct bt_component_class *component_class, const char *name,
342 struct bt_value *params)
343{
344 return bt_component_create_with_init_method_data(component_class, name,
345 params, NULL);
346}
347
de713ce0
JG
348const char *bt_component_get_name(struct bt_component *component)
349{
350 const char *ret = NULL;
351
352 if (!component) {
353 goto end;
354 }
355
f1222e7d 356 ret = component->name->len == 0 ? NULL : component->name->str;
de713ce0
JG
357end:
358 return ret;
359}
360
361enum bt_component_status bt_component_set_name(struct bt_component *component,
362 const char *name)
363{
364 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
365
366 if (!component || !name || name[0] == '\0') {
30d619df 367 ret = BT_COMPONENT_STATUS_INVALID;
de713ce0
JG
368 goto end;
369 }
370
371 g_string_assign(component->name, name);
372end:
373 return ret;
374}
375
38b48196
JG
376struct bt_component_class *bt_component_get_class(
377 struct bt_component *component)
de713ce0 378{
38b48196 379 return component ? bt_get(component->class) : NULL;
de713ce0
JG
380}
381
de713ce0
JG
382void *bt_component_get_private_data(struct bt_component *component)
383{
38b48196 384 return component ? component->user_data : NULL;
de713ce0
JG
385}
386
387enum bt_component_status
388bt_component_set_private_data(struct bt_component *component,
389 void *data)
390{
391 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
392
fec2a9f2 393 if (!component || !component->initializing) {
30d619df 394 ret = BT_COMPONENT_STATUS_INVALID;
de713ce0
JG
395 goto end;
396 }
397
398 component->user_data = data;
399end:
400 return ret;
401}
366e034f
JG
402
403BT_HIDDEN
f60c8b34 404void bt_component_set_graph(struct bt_component *component,
366e034f
JG
405 struct bt_graph *graph)
406{
f60c8b34
JG
407 struct bt_object *parent = bt_object_get_parent(&component->base);
408
409 assert(!parent || parent == &graph->base);
410 if (!parent) {
411 bt_object_set_parent(component, &graph->base);
412 }
413 bt_put(parent);
366e034f
JG
414}
415
416struct bt_graph *bt_component_get_graph(
417 struct bt_component *component)
418{
419 return (struct bt_graph *) bt_object_get_parent(&component->base);
420}
421
72b913fb 422static
366e034f
JG
423struct bt_port *bt_component_get_port(GPtrArray *ports, const char *name)
424{
425 size_t i;
426 struct bt_port *ret_port = NULL;
427
72b913fb
PP
428 assert(name);
429
366e034f
JG
430 for (i = 0; i < ports->len; i++) {
431 struct bt_port *port = g_ptr_array_index(ports, i);
432 const char *port_name = bt_port_get_name(port);
433
434 if (!port_name) {
435 continue;
436 }
437
438 if (!strcmp(name, port_name)) {
439 ret_port = bt_get(port);
440 break;
441 }
442 }
443
444 return ret_port;
445}
446
447BT_HIDDEN
72b913fb
PP
448struct bt_port *bt_component_get_input_port(struct bt_component *comp,
449 const char *name)
450{
451 assert(comp);
452
453 return bt_component_get_port(comp->input_ports, name);
454}
455
456BT_HIDDEN
457struct bt_port *bt_component_get_output_port(struct bt_component *comp,
458 const char *name)
459{
460 assert(comp);
461
462 return bt_component_get_port(comp->output_ports, name);
463}
464
465static
366e034f
JG
466struct bt_port *bt_component_get_port_at_index(GPtrArray *ports, int index)
467{
468 struct bt_port *port = NULL;
469
470 if (index < 0 || index >= ports->len) {
471 goto end;
472 }
473
474 port = bt_get(g_ptr_array_index(ports, index));
475end:
476 return port;
477}
478
479BT_HIDDEN
72b913fb
PP
480struct bt_port *bt_component_get_input_port_at_index(struct bt_component *comp,
481 int index)
366e034f 482{
72b913fb 483 assert(comp);
366e034f 484
72b913fb
PP
485 return bt_component_get_port_at_index(comp->input_ports, index);
486}
366e034f 487
72b913fb
PP
488BT_HIDDEN
489struct bt_port *bt_component_get_output_port_at_index(struct bt_component *comp,
490 int index)
491{
492 assert(comp);
366e034f 493
72b913fb
PP
494 return bt_component_get_port_at_index(comp->output_ports, index);
495}
366e034f 496
72b913fb
PP
497BT_HIDDEN
498struct bt_port *bt_component_add_input_port(
499 struct bt_component *component, const char *name)
500{
501 return bt_component_add_port(component, component->input_ports,
502 BT_PORT_TYPE_INPUT, name);
503}
366e034f 504
72b913fb
PP
505BT_HIDDEN
506struct bt_port *bt_component_add_output_port(
507 struct bt_component *component, const char *name)
508{
509 return bt_component_add_port(component, component->output_ports,
510 BT_PORT_TYPE_OUTPUT, name);
511}
512
513static
514void bt_component_remove_port_at_index(struct bt_component *component,
515 GPtrArray *ports, size_t index)
516{
517 struct bt_port *port;
518
519 assert(ports);
520 assert(index < ports->len);
521 port = g_ptr_array_index(ports, index);
522
523 /* Disconnect both ports of this port's connection, if any */
524 if (port->connection) {
525 bt_connection_disconnect_ports(port->connection, component);
f60c8b34
JG
526 }
527
72b913fb
PP
528 /* Remove from parent's array of ports (weak refs) */
529 g_ptr_array_remove_index(ports, index);
530
531 /* Detach port from its component parent */
532 BT_PUT(port->base.parent);
533
534 // TODO: notify graph user: component's port removed
366e034f
JG
535}
536
537BT_HIDDEN
538enum bt_component_status bt_component_remove_port(
72b913fb 539 struct bt_component *component, struct bt_port *port)
366e034f
JG
540{
541 size_t i;
542 enum bt_component_status status = BT_COMPONENT_STATUS_OK;
72b913fb 543 GPtrArray *ports = NULL;
366e034f 544
72b913fb 545 if (!component || !port) {
366e034f
JG
546 status = BT_COMPONENT_STATUS_INVALID;
547 goto end;
548 }
549
72b913fb
PP
550 if (bt_port_get_type(port) == BT_PORT_TYPE_INPUT) {
551 ports = component->input_ports;
552 } else if (bt_port_get_type(port) == BT_PORT_TYPE_OUTPUT) {
553 ports = component->output_ports;
554 }
366e034f 555
72b913fb 556 assert(ports);
366e034f 557
72b913fb
PP
558 for (i = 0; i < ports->len; i++) {
559 struct bt_port *cur_port = g_ptr_array_index(ports, i);
560
561 if (cur_port == port) {
562 bt_component_remove_port_at_index(component,
563 ports, i);
366e034f
JG
564 goto end;
565 }
566 }
72b913fb 567
366e034f
JG
568 status = BT_COMPONENT_STATUS_NOT_FOUND;
569end:
570 return status;
571}
f60c8b34
JG
572
573BT_HIDDEN
72b913fb
PP
574enum bt_component_status bt_component_accept_port_connection(
575 struct bt_component *comp, struct bt_port *port)
f60c8b34
JG
576{
577 enum bt_component_status status = BT_COMPONENT_STATUS_OK;
578
72b913fb
PP
579 assert(comp);
580 assert(port);
581
582 if (comp->class->methods.accept_port_connection) {
583 status = comp->class->methods.accept_port_connection(
584 comp, port);
f60c8b34
JG
585 }
586
587 return status;
588}
72b913fb
PP
589
590BT_HIDDEN
591void bt_component_port_disconnected(struct bt_component *comp,
592 struct bt_port *port)
593{
594 assert(comp);
595 assert(port);
596
597 if (comp->class->methods.port_disconnected) {
598 comp->class->methods.port_disconnected(comp, port);
599 }
600}
This page took 0.053986 seconds and 4 git commands to generate.