Allow a component to remove a port and any user to disconnect one
[babeltrace.git] / lib / component / component.c
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
29 #include <babeltrace/component/component.h>
30 #include <babeltrace/component/component-internal.h>
31 #include <babeltrace/component/component-class-internal.h>
32 #include <babeltrace/component/component-source-internal.h>
33 #include <babeltrace/component/component-filter-internal.h>
34 #include <babeltrace/component/component-sink-internal.h>
35 #include <babeltrace/component/connection-internal.h>
36 #include <babeltrace/component/graph-internal.h>
37 #include <babeltrace/component/notification/iterator-internal.h>
38 #include <babeltrace/babeltrace-internal.h>
39 #include <babeltrace/compiler.h>
40 #include <babeltrace/ref.h>
41
42 static
43 struct bt_component * (* const component_create_funcs[])(
44 struct bt_component_class *, struct bt_value *) = {
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,
48 };
49
50 static
51 void (*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
57 static
58 enum bt_component_status (* const component_validation_funcs[])(
59 struct bt_component *) = {
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,
63 };
64
65 static
66 void 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);
76 component_class = component->class;
77
78 /*
79 * User data is destroyed first, followed by the concrete component
80 * instance.
81 */
82 if (component->class->methods.destroy) {
83 component->class->methods.destroy(component);
84 }
85
86 if (component->destroy) {
87 component->destroy(component);
88 }
89
90 if (component->input_ports) {
91 g_ptr_array_free(component->input_ports, TRUE);
92 }
93
94 if (component->output_ports) {
95 g_ptr_array_free(component->output_ports, TRUE);
96 }
97
98 g_string_free(component->name, TRUE);
99 bt_put(component_class);
100 g_free(component);
101 }
102
103 enum bt_component_class_type bt_component_get_class_type(
104 struct bt_component *component)
105 {
106 return component ? component->class->type : BT_COMPONENT_CLASS_TYPE_UNKNOWN;
107 }
108
109 BT_HIDDEN
110 struct bt_notification_iterator *bt_component_create_iterator(
111 struct bt_component *component, void *init_method_data)
112 {
113 enum bt_notification_iterator_status ret_iterator;
114 enum bt_component_class_type type;
115 struct bt_notification_iterator *iterator = NULL;
116 struct bt_component_class *class = component->class;
117
118 if (!component) {
119 goto error;
120 }
121
122 type = bt_component_get_class_type(component);
123 if (type != BT_COMPONENT_CLASS_TYPE_SOURCE &&
124 type != BT_COMPONENT_CLASS_TYPE_FILTER) {
125 /* Unsupported operation. */
126 goto error;
127 }
128
129 iterator = bt_notification_iterator_create(component);
130 if (!iterator) {
131 goto error;
132 }
133
134 switch (type) {
135 case BT_COMPONENT_CLASS_TYPE_SOURCE:
136 {
137 struct bt_component_class_source *source_class;
138 enum bt_notification_iterator_status status;
139
140 source_class = container_of(class, struct bt_component_class_source, parent);
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 }
148 }
149 break;
150 }
151 case BT_COMPONENT_CLASS_TYPE_FILTER:
152 {
153 struct bt_component_class_filter *filter_class;
154 enum bt_notification_iterator_status status;
155
156 filter_class = container_of(class, struct bt_component_class_filter, parent);
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 }
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;
178 error:
179 BT_PUT(iterator);
180 return iterator;
181 }
182
183 static
184 struct 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);
224 end:
225 return new_port;
226 }
227
228 BT_HIDDEN
229 uint64_t bt_component_get_input_port_count(struct bt_component *comp)
230 {
231 assert(comp);
232 return comp->input_ports->len;
233 }
234
235 BT_HIDDEN
236 uint64_t bt_component_get_output_port_count(struct bt_component *comp)
237 {
238 assert(comp);
239 return comp->output_ports->len;
240 }
241
242 struct bt_component *bt_component_create_with_init_method_data(
243 struct bt_component_class *component_class, const char *name,
244 struct bt_value *params, void *init_method_data)
245 {
246 int ret;
247 struct bt_component *component = NULL;
248 enum bt_component_class_type type;
249 struct bt_port *default_port = NULL;
250
251 if (!component_class) {
252 goto end;
253 }
254
255 type = bt_component_class_get_type(component_class);
256 if (type <= BT_COMPONENT_CLASS_TYPE_UNKNOWN ||
257 type > BT_COMPONENT_CLASS_TYPE_FILTER) {
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);
267 component->class = bt_get(component_class);
268 component->destroy = component_destroy_funcs[type];
269 component->name = g_string_new(name);
270 if (!component->name) {
271 BT_PUT(component);
272 goto end;
273 }
274
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
317 if (component_class->methods.init) {
318 ret = component_class->methods.init(component, params,
319 init_method_data);
320 component->initializing = false;
321 if (ret != BT_COMPONENT_STATUS_OK) {
322 BT_PUT(component);
323 goto end;
324 }
325 }
326
327 component->initializing = false;
328 ret = component_validation_funcs[type](component);
329 if (ret != BT_COMPONENT_STATUS_OK) {
330 BT_PUT(component);
331 goto end;
332 }
333
334 bt_component_class_freeze(component->class);
335 end:
336 bt_put(default_port);
337 return component;
338 }
339
340 struct 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
348 const char *bt_component_get_name(struct bt_component *component)
349 {
350 const char *ret = NULL;
351
352 if (!component) {
353 goto end;
354 }
355
356 ret = component->name->len == 0 ? NULL : component->name->str;
357 end:
358 return ret;
359 }
360
361 enum 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') {
367 ret = BT_COMPONENT_STATUS_INVALID;
368 goto end;
369 }
370
371 g_string_assign(component->name, name);
372 end:
373 return ret;
374 }
375
376 struct bt_component_class *bt_component_get_class(
377 struct bt_component *component)
378 {
379 return component ? bt_get(component->class) : NULL;
380 }
381
382 void *bt_component_get_private_data(struct bt_component *component)
383 {
384 return component ? component->user_data : NULL;
385 }
386
387 enum bt_component_status
388 bt_component_set_private_data(struct bt_component *component,
389 void *data)
390 {
391 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
392
393 if (!component || !component->initializing) {
394 ret = BT_COMPONENT_STATUS_INVALID;
395 goto end;
396 }
397
398 component->user_data = data;
399 end:
400 return ret;
401 }
402
403 BT_HIDDEN
404 void bt_component_set_graph(struct bt_component *component,
405 struct bt_graph *graph)
406 {
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);
414 }
415
416 struct 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
422 static
423 struct bt_port *bt_component_get_port(GPtrArray *ports, const char *name)
424 {
425 size_t i;
426 struct bt_port *ret_port = NULL;
427
428 assert(name);
429
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
447 BT_HIDDEN
448 struct 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
456 BT_HIDDEN
457 struct 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
465 static
466 struct 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));
475 end:
476 return port;
477 }
478
479 BT_HIDDEN
480 struct bt_port *bt_component_get_input_port_at_index(struct bt_component *comp,
481 int index)
482 {
483 assert(comp);
484
485 return bt_component_get_port_at_index(comp->input_ports, index);
486 }
487
488 BT_HIDDEN
489 struct bt_port *bt_component_get_output_port_at_index(struct bt_component *comp,
490 int index)
491 {
492 assert(comp);
493
494 return bt_component_get_port_at_index(comp->output_ports, index);
495 }
496
497 BT_HIDDEN
498 struct 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 }
504
505 BT_HIDDEN
506 struct 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
513 static
514 void 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);
526 }
527
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
535 }
536
537 BT_HIDDEN
538 enum bt_component_status bt_component_remove_port(
539 struct bt_component *component, struct bt_port *port)
540 {
541 size_t i;
542 enum bt_component_status status = BT_COMPONENT_STATUS_OK;
543 GPtrArray *ports = NULL;
544
545 if (!component || !port) {
546 status = BT_COMPONENT_STATUS_INVALID;
547 goto end;
548 }
549
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 }
555
556 assert(ports);
557
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);
564 goto end;
565 }
566 }
567
568 status = BT_COMPONENT_STATUS_NOT_FOUND;
569 end:
570 return status;
571 }
572
573 BT_HIDDEN
574 enum bt_component_status bt_component_accept_port_connection(
575 struct bt_component *comp, struct bt_port *port)
576 {
577 enum bt_component_status status = BT_COMPONENT_STATUS_OK;
578
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);
585 }
586
587 return status;
588 }
589
590 BT_HIDDEN
591 void 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.043219 seconds and 4 git commands to generate.