Visibility: split graph API into public and private interfaces
[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/private-component.h>
30 #include <babeltrace/component/component.h>
31 #include <babeltrace/component/component-internal.h>
32 #include <babeltrace/component/component-class-internal.h>
33 #include <babeltrace/component/component-source-internal.h>
34 #include <babeltrace/component/component-filter-internal.h>
35 #include <babeltrace/component/component-sink-internal.h>
36 #include <babeltrace/component/private-connection.h>
37 #include <babeltrace/component/connection-internal.h>
38 #include <babeltrace/component/graph-internal.h>
39 #include <babeltrace/component/notification/iterator-internal.h>
40 #include <babeltrace/component/notification/private-iterator.h>
41 #include <babeltrace/babeltrace-internal.h>
42 #include <babeltrace/compiler.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.destroy) {
86 component->class->methods.destroy(
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 if (!component_class) {
199 goto end;
200 }
201
202 type = bt_component_class_get_type(component_class);
203 if (type <= BT_COMPONENT_CLASS_TYPE_UNKNOWN ||
204 type > BT_COMPONENT_CLASS_TYPE_FILTER) {
205 goto end;
206 }
207
208 component = component_create_funcs[type](component_class, params);
209 if (!component) {
210 goto end;
211 }
212
213 bt_object_init(component, bt_component_destroy);
214 component->class = bt_get(component_class);
215 component->destroy = component_destroy_funcs[type];
216 component->name = g_string_new(name);
217 if (!component->name) {
218 BT_PUT(component);
219 goto end;
220 }
221
222 component->input_ports = g_ptr_array_new_with_free_func(
223 bt_object_release);
224 if (!component->input_ports) {
225 BT_PUT(component);
226 goto end;
227 }
228
229 component->output_ports = g_ptr_array_new_with_free_func(
230 bt_object_release);
231 if (!component->output_ports) {
232 BT_PUT(component);
233 goto end;
234 }
235
236 if (type == BT_COMPONENT_CLASS_TYPE_SOURCE ||
237 type == BT_COMPONENT_CLASS_TYPE_FILTER) {
238 default_port = bt_component_add_port(component,
239 component->output_ports, BT_PORT_TYPE_OUTPUT,
240 DEFAULT_OUTPUT_PORT_NAME);
241 if (!default_port) {
242 BT_PUT(component);
243 goto end;
244 }
245
246 BT_PUT(default_port);
247 }
248
249 if (type == BT_COMPONENT_CLASS_TYPE_FILTER ||
250 type == BT_COMPONENT_CLASS_TYPE_SINK) {
251 default_port = bt_component_add_port(component,
252 component->input_ports, BT_PORT_TYPE_INPUT,
253 DEFAULT_INPUT_PORT_NAME);
254 if (!default_port) {
255 BT_PUT(component);
256 goto end;
257 }
258
259 BT_PUT(default_port);
260 }
261
262 component->initializing = true;
263
264 if (component_class->methods.init) {
265 ret = component_class->methods.init(
266 bt_private_component_from_component(component), params,
267 init_method_data);
268 component->initializing = false;
269 if (ret != BT_COMPONENT_STATUS_OK) {
270 BT_PUT(component);
271 goto end;
272 }
273 }
274
275 component->initializing = false;
276 ret = component_validation_funcs[type](component);
277 if (ret != BT_COMPONENT_STATUS_OK) {
278 BT_PUT(component);
279 goto end;
280 }
281
282 bt_component_class_freeze(component->class);
283 end:
284 bt_put(default_port);
285 return component;
286 }
287
288 struct bt_component *bt_component_create(
289 struct bt_component_class *component_class, const char *name,
290 struct bt_value *params)
291 {
292 return bt_component_create_with_init_method_data(component_class, name,
293 params, NULL);
294 }
295
296 const char *bt_component_get_name(struct bt_component *component)
297 {
298 const char *ret = NULL;
299
300 if (!component) {
301 goto end;
302 }
303
304 ret = component->name->len == 0 ? NULL : component->name->str;
305 end:
306 return ret;
307 }
308
309 enum bt_component_status bt_component_set_name(struct bt_component *component,
310 const char *name)
311 {
312 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
313
314 if (!component || !name || name[0] == '\0') {
315 ret = BT_COMPONENT_STATUS_INVALID;
316 goto end;
317 }
318
319 g_string_assign(component->name, name);
320 end:
321 return ret;
322 }
323
324 struct bt_component_class *bt_component_get_class(
325 struct bt_component *component)
326 {
327 return component ? bt_get(component->class) : NULL;
328 }
329
330 void *bt_private_component_get_user_data(
331 struct bt_private_component *private_component)
332 {
333 struct bt_component *component =
334 bt_component_from_private(private_component);
335
336 return component ? component->user_data : NULL;
337 }
338
339 enum bt_component_status bt_private_component_set_user_data(
340 struct bt_private_component *private_component,
341 void *data)
342 {
343 struct bt_component *component =
344 bt_component_from_private(private_component);
345 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
346
347 if (!component || !component->initializing) {
348 ret = BT_COMPONENT_STATUS_INVALID;
349 goto end;
350 }
351
352 component->user_data = data;
353 end:
354 return ret;
355 }
356
357 BT_HIDDEN
358 void bt_component_set_graph(struct bt_component *component,
359 struct bt_graph *graph)
360 {
361 struct bt_object *parent = bt_object_get_parent(&component->base);
362
363 assert(!parent || parent == &graph->base);
364 if (!parent) {
365 bt_object_set_parent(component, &graph->base);
366 }
367 bt_put(parent);
368 }
369
370 struct bt_graph *bt_component_get_graph(
371 struct bt_component *component)
372 {
373 return (struct bt_graph *) bt_object_get_parent(&component->base);
374 }
375
376 static
377 struct bt_port *bt_component_get_port(GPtrArray *ports, const char *name)
378 {
379 size_t i;
380 struct bt_port *ret_port = NULL;
381
382 assert(name);
383
384 for (i = 0; i < ports->len; i++) {
385 struct bt_port *port = g_ptr_array_index(ports, i);
386 const char *port_name = bt_port_get_name(port);
387
388 if (!port_name) {
389 continue;
390 }
391
392 if (!strcmp(name, port_name)) {
393 ret_port = bt_get(port);
394 break;
395 }
396 }
397
398 return ret_port;
399 }
400
401 BT_HIDDEN
402 struct bt_port *bt_component_get_input_port(struct bt_component *comp,
403 const char *name)
404 {
405 assert(comp);
406
407 return bt_component_get_port(comp->input_ports, name);
408 }
409
410 BT_HIDDEN
411 struct bt_port *bt_component_get_output_port(struct bt_component *comp,
412 const char *name)
413 {
414 assert(comp);
415
416 return bt_component_get_port(comp->output_ports, name);
417 }
418
419 static
420 struct bt_port *bt_component_get_port_at_index(GPtrArray *ports, int index)
421 {
422 struct bt_port *port = NULL;
423
424 if (index < 0 || index >= ports->len) {
425 goto end;
426 }
427
428 port = bt_get(g_ptr_array_index(ports, index));
429 end:
430 return port;
431 }
432
433 BT_HIDDEN
434 struct bt_port *bt_component_get_input_port_at_index(struct bt_component *comp,
435 int index)
436 {
437 assert(comp);
438
439 return bt_component_get_port_at_index(comp->input_ports, index);
440 }
441
442 BT_HIDDEN
443 struct bt_port *bt_component_get_output_port_at_index(struct bt_component *comp,
444 int index)
445 {
446 assert(comp);
447
448 return bt_component_get_port_at_index(comp->output_ports, index);
449 }
450
451 BT_HIDDEN
452 struct bt_port *bt_component_add_input_port(
453 struct bt_component *component, const char *name)
454 {
455 return bt_component_add_port(component, component->input_ports,
456 BT_PORT_TYPE_INPUT, name);
457 }
458
459 BT_HIDDEN
460 struct bt_port *bt_component_add_output_port(
461 struct bt_component *component, const char *name)
462 {
463 return bt_component_add_port(component, component->output_ports,
464 BT_PORT_TYPE_OUTPUT, name);
465 }
466
467 static
468 void bt_component_remove_port_at_index(struct bt_component *component,
469 GPtrArray *ports, size_t index)
470 {
471 struct bt_port *port;
472 struct bt_graph *graph;
473
474 assert(ports);
475 assert(index < ports->len);
476 port = g_ptr_array_index(ports, index);
477
478 /* Disconnect both ports of this port's connection, if any */
479 if (port->connection) {
480 bt_connection_disconnect_ports(port->connection, component);
481 }
482
483 /* Remove from parent's array of ports (weak refs) */
484 g_ptr_array_remove_index(ports, index);
485
486 /* Detach port from its component parent */
487 BT_PUT(port->base.parent);
488
489 /*
490 * Notify the graph's creator that a port is removed.
491 */
492 graph = bt_component_get_graph(component);
493 if (graph) {
494 bt_graph_notify_port_removed(graph, component, port);
495 BT_PUT(graph);
496 }
497 }
498
499 BT_HIDDEN
500 enum bt_component_status bt_component_remove_port(
501 struct bt_component *component, struct bt_port *port)
502 {
503 size_t i;
504 enum bt_component_status status = BT_COMPONENT_STATUS_OK;
505 GPtrArray *ports = NULL;
506
507 if (!component || !port) {
508 status = BT_COMPONENT_STATUS_INVALID;
509 goto end;
510 }
511
512 if (bt_port_get_type(port) == BT_PORT_TYPE_INPUT) {
513 ports = component->input_ports;
514 } else if (bt_port_get_type(port) == BT_PORT_TYPE_OUTPUT) {
515 ports = component->output_ports;
516 }
517
518 assert(ports);
519
520 for (i = 0; i < ports->len; i++) {
521 struct bt_port *cur_port = g_ptr_array_index(ports, i);
522
523 if (cur_port == port) {
524 bt_component_remove_port_at_index(component,
525 ports, i);
526 goto end;
527 }
528 }
529
530 status = BT_COMPONENT_STATUS_NOT_FOUND;
531 end:
532 return status;
533 }
534
535 BT_HIDDEN
536 enum bt_component_status bt_component_accept_port_connection(
537 struct bt_component *comp, struct bt_port *port)
538 {
539 enum bt_component_status status = BT_COMPONENT_STATUS_OK;
540
541 assert(comp);
542 assert(port);
543
544 if (comp->class->methods.accept_port_connection) {
545 status = comp->class->methods.accept_port_connection(
546 bt_private_component_from_component(comp),
547 bt_private_port_from_port(port));
548 }
549
550 return status;
551 }
552
553 BT_HIDDEN
554 void bt_component_port_disconnected(struct bt_component *comp,
555 struct bt_port *port)
556 {
557 assert(comp);
558 assert(port);
559
560 if (comp->class->methods.port_disconnected) {
561 comp->class->methods.port_disconnected(
562 bt_private_component_from_component(comp),
563 bt_private_port_from_port(port));
564 }
565 }
This page took 0.040267 seconds and 4 git commands to generate.