Notification iterator: generate automatic notifications when missing
[babeltrace.git] / lib / graph / 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/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>
41 #include <babeltrace/babeltrace-internal.h>
42 #include <babeltrace/compiler-internal.h>
43 #include <babeltrace/ref.h>
44
45 static
46 struct bt_component * (* const component_create_funcs[])(
47 struct bt_component_class *, struct bt_value *) = {
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,
51 };
52
53 static
54 void (*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
60 static
61 enum bt_component_status (* const component_validation_funcs[])(
62 struct bt_component *) = {
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,
66 };
67
68 static
69 void bt_component_destroy(struct bt_object *obj)
70 {
71 struct bt_component *component = NULL;
72 struct bt_component_class *component_class = NULL;
73 int i;
74
75 if (!obj) {
76 return;
77 }
78
79 component = container_of(obj, struct bt_component, base);
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
90 component_class = component->class;
91
92 /*
93 * User data is destroyed first, followed by the concrete component
94 * instance.
95 */
96 if (component->class->methods.finalize) {
97 component->class->methods.finalize(
98 bt_private_component_from_component(component));
99 }
100
101 if (component->destroy) {
102 component->destroy(component);
103 }
104
105 if (component->input_ports) {
106 g_ptr_array_free(component->input_ports, TRUE);
107 }
108
109 if (component->output_ports) {
110 g_ptr_array_free(component->output_ports, TRUE);
111 }
112
113 if (component->destroy_listeners) {
114 g_array_free(component->destroy_listeners, TRUE);
115 }
116
117 g_string_free(component->name, TRUE);
118 bt_put(component_class);
119 g_free(component);
120 }
121
122 struct bt_component *bt_component_from_private_component(
123 struct bt_private_component *private_component)
124 {
125 return bt_get(bt_component_from_private(private_component));
126 }
127
128 enum bt_component_class_type bt_component_get_class_type(
129 struct bt_component *component)
130 {
131 return component ? component->class->type : BT_COMPONENT_CLASS_TYPE_UNKNOWN;
132 }
133
134 static
135 struct 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;
141 struct bt_graph *graph = NULL;
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);
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
186 end:
187 return new_port;
188 }
189
190 BT_HIDDEN
191 uint64_t bt_component_get_input_port_count(struct bt_component *comp)
192 {
193 assert(comp);
194 return comp->input_ports->len;
195 }
196
197 BT_HIDDEN
198 uint64_t bt_component_get_output_port_count(struct bt_component *comp)
199 {
200 assert(comp);
201 return comp->output_ports->len;
202 }
203
204 struct bt_component *bt_component_create_with_init_method_data(
205 struct bt_component_class *component_class, const char *name,
206 struct bt_value *params, void *init_method_data)
207 {
208 int ret;
209 struct bt_component *component = NULL;
210 enum bt_component_class_type type;
211 struct bt_port *default_port = NULL;
212
213 bt_get(params);
214
215 if (!component_class) {
216 goto end;
217 }
218
219 type = bt_component_class_get_type(component_class);
220 if (type <= BT_COMPONENT_CLASS_TYPE_UNKNOWN ||
221 type > BT_COMPONENT_CLASS_TYPE_FILTER) {
222 goto end;
223 }
224
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
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);
246 component->class = bt_get(component_class);
247 component->destroy = component_destroy_funcs[type];
248 component->name = g_string_new(name);
249 if (!component->name) {
250 BT_PUT(component);
251 goto end;
252 }
253
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
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
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
303 if (component_class->methods.init) {
304 ret = component_class->methods.init(
305 bt_private_component_from_component(component), params,
306 init_method_data);
307 component->initializing = false;
308 if (ret != BT_COMPONENT_STATUS_OK) {
309 BT_PUT(component);
310 goto end;
311 }
312 }
313
314 component->initializing = false;
315 ret = component_validation_funcs[type](component);
316 if (ret != BT_COMPONENT_STATUS_OK) {
317 BT_PUT(component);
318 goto end;
319 }
320
321 bt_component_class_freeze(component->class);
322 end:
323 bt_put(params);
324 bt_put(default_port);
325 return component;
326 }
327
328 struct 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
336 const char *bt_component_get_name(struct bt_component *component)
337 {
338 const char *ret = NULL;
339
340 if (!component) {
341 goto end;
342 }
343
344 ret = component->name->len == 0 ? NULL : component->name->str;
345 end:
346 return ret;
347 }
348
349 enum 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') {
355 ret = BT_COMPONENT_STATUS_INVALID;
356 goto end;
357 }
358
359 g_string_assign(component->name, name);
360 end:
361 return ret;
362 }
363
364 struct bt_component_class *bt_component_get_class(
365 struct bt_component *component)
366 {
367 return component ? bt_get(component->class) : NULL;
368 }
369
370 void *bt_private_component_get_user_data(
371 struct bt_private_component *private_component)
372 {
373 struct bt_component *component =
374 bt_component_from_private(private_component);
375
376 return component ? component->user_data : NULL;
377 }
378
379 enum bt_component_status bt_private_component_set_user_data(
380 struct bt_private_component *private_component,
381 void *data)
382 {
383 struct bt_component *component =
384 bt_component_from_private(private_component);
385 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
386
387 if (!component || !component->initializing) {
388 ret = BT_COMPONENT_STATUS_INVALID;
389 goto end;
390 }
391
392 component->user_data = data;
393 end:
394 return ret;
395 }
396
397 BT_HIDDEN
398 void bt_component_set_graph(struct bt_component *component,
399 struct bt_graph *graph)
400 {
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);
408 }
409
410 struct 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
416 static
417 struct bt_port *bt_component_get_port(GPtrArray *ports, const char *name)
418 {
419 size_t i;
420 struct bt_port *ret_port = NULL;
421
422 assert(name);
423
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
441 BT_HIDDEN
442 struct 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
450 BT_HIDDEN
451 struct 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
459 static
460 struct 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));
469 end:
470 return port;
471 }
472
473 BT_HIDDEN
474 struct bt_port *bt_component_get_input_port_at_index(struct bt_component *comp,
475 int index)
476 {
477 assert(comp);
478
479 return bt_component_get_port_at_index(comp->input_ports, index);
480 }
481
482 BT_HIDDEN
483 struct bt_port *bt_component_get_output_port_at_index(struct bt_component *comp,
484 int index)
485 {
486 assert(comp);
487
488 return bt_component_get_port_at_index(comp->output_ports, index);
489 }
490
491 BT_HIDDEN
492 struct 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 }
498
499 BT_HIDDEN
500 struct 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
507 static
508 void bt_component_remove_port_at_index(struct bt_component *component,
509 GPtrArray *ports, size_t index)
510 {
511 struct bt_port *port;
512 struct bt_graph *graph;
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) {
520 bt_connection_disconnect_ports(port->connection);
521 }
522
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
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 }
537 }
538
539 BT_HIDDEN
540 enum bt_component_status bt_component_remove_port(
541 struct bt_component *component, struct bt_port *port)
542 {
543 size_t i;
544 enum bt_component_status status = BT_COMPONENT_STATUS_OK;
545 GPtrArray *ports = NULL;
546
547 if (!component || !port) {
548 status = BT_COMPONENT_STATUS_INVALID;
549 goto end;
550 }
551
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 }
557
558 assert(ports);
559
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);
566 goto end;
567 }
568 }
569
570 status = BT_COMPONENT_STATUS_NOT_FOUND;
571 end:
572 return status;
573 }
574
575 BT_HIDDEN
576 enum bt_component_status bt_component_accept_port_connection(
577 struct bt_component *comp, struct bt_port *self_port,
578 struct bt_port *other_port)
579 {
580 enum bt_component_status status = BT_COMPONENT_STATUS_OK;
581
582 assert(comp);
583 assert(self_port);
584 assert(other_port);
585
586 if (comp->class->methods.accept_port_connection) {
587 status = comp->class->methods.accept_port_connection(
588 bt_private_component_from_component(comp),
589 bt_private_port_from_port(self_port),
590 other_port);
591 }
592
593 return status;
594 }
595
596 BT_HIDDEN
597 void 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
611 BT_HIDDEN
612 void 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) {
619 comp->class->methods.port_disconnected(
620 bt_private_component_from_component(comp),
621 bt_private_port_from_port(port));
622 }
623 }
624
625 BT_HIDDEN
626 void 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
638 BT_HIDDEN
639 void 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.042226 seconds and 4 git commands to generate.