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