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