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