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