fix: bt_put on potentially unintialized variable
[babeltrace.git] / lib / graph / connection.c
CommitLineData
784cdc68 1/*
7d55361f 2 * connection.c
784cdc68
JG
3 *
4 * Babeltrace Connection
5 *
6 * Copyright 2017 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
b2e0c907
PP
29#include <babeltrace/graph/notification-iterator-internal.h>
30#include <babeltrace/graph/component-internal.h>
31#include <babeltrace/graph/component-source-internal.h>
32#include <babeltrace/graph/component-filter-internal.h>
33#include <babeltrace/graph/connection-internal.h>
34#include <babeltrace/graph/private-connection.h>
35#include <babeltrace/graph/graph-internal.h>
36#include <babeltrace/graph/port-internal.h>
784cdc68 37#include <babeltrace/object-internal.h>
3d9990ac 38#include <babeltrace/compiler-internal.h>
784cdc68
JG
39#include <glib.h>
40
41static
42void bt_connection_destroy(struct bt_object *obj)
43{
44 struct bt_connection *connection = container_of(obj,
45 struct bt_connection, base);
bd14d768
PP
46 size_t i;
47
48 /*
49 * Make sure that each notification iterator which was created
50 * for this connection is finalized before we destroy it. Once a
51 * notification iterator is finalized, all its method return
52 * NULL or the BT_NOTIFICATION_ITERATOR_STATUS_CANCELED status.
53 *
54 * Because connections are destroyed before components within a
55 * graph, this ensures that notification iterators are always
56 * finalized before their upstream component.
57 */
58 if (connection->iterators) {
59 for (i = 0; i < connection->iterators->len; i++) {
60 struct bt_notification_iterator *iterator =
61 g_ptr_array_index(connection->iterators, i);
62
63 bt_notification_iterator_finalize(iterator);
64
65 /*
66 * Make sure this iterator does not try to
67 * remove itself from this connection's
68 * iterators on destruction because this
69 * connection won't exist anymore.
70 */
71 bt_notification_iterator_set_connection(iterator,
72 NULL);
73 }
74
75 g_ptr_array_free(connection->iterators, TRUE);
76 }
784cdc68
JG
77
78 /*
79 * No bt_put on ports as a connection only holds _weak_ references
80 * to them.
81 */
82 g_free(connection);
83}
84
f167d3c0
PP
85static
86void bt_connection_try_remove_from_graph(struct bt_connection *connection)
87{
88 void *graph = bt_object_borrow_parent(&connection->base);
89
90 if (connection->base.ref_count.count > 0 ||
91 connection->downstream_port ||
92 connection->upstream_port ||
93 connection->iterators->len > 0) {
94 return;
95 }
96
97 /*
98 * At this point we know that:
99 *
100 * 1. The connection is dead (ports were disconnected).
101 * 2. All the notification iterators that this connection
102 * created, if any, are finalized.
103 * 3. The connection's reference count is 0, so only the
104 * parent (graph) owns this connection after this call.
105 *
106 * In other words, no other object than the graph knows this
107 * connection.
108 *
109 * It is safe to remove the connection from the graph, therefore
110 * destroying it.
111 */
112 bt_graph_remove_connection(graph, connection);
113}
114
115static
116void bt_connection_parent_is_owner(struct bt_object *obj)
117{
118 struct bt_connection *connection = container_of(obj,
119 struct bt_connection, base);
120
121 bt_connection_try_remove_from_graph(connection);
122}
123
890882ef
PP
124struct bt_connection *bt_connection_from_private_connection(
125 struct bt_private_connection *private_connection)
126{
127 return bt_get(bt_connection_from_private(private_connection));
128}
129
784cdc68
JG
130BT_HIDDEN
131struct bt_connection *bt_connection_create(
132 struct bt_graph *graph,
72b913fb
PP
133 struct bt_port *upstream_port,
134 struct bt_port *downstream_port)
784cdc68
JG
135{
136 struct bt_connection *connection = NULL;
137
72b913fb 138 if (bt_port_get_type(upstream_port) != BT_PORT_TYPE_OUTPUT) {
784cdc68
JG
139 goto end;
140 }
72b913fb 141 if (bt_port_get_type(downstream_port) != BT_PORT_TYPE_INPUT) {
784cdc68
JG
142 goto end;
143 }
144
145 connection = g_new0(struct bt_connection, 1);
146 if (!connection) {
147 goto end;
148 }
149
150 bt_object_init(connection, bt_connection_destroy);
f167d3c0
PP
151 bt_object_set_parent_is_owner_listener(connection,
152 bt_connection_parent_is_owner);
bd14d768
PP
153 connection->iterators = g_ptr_array_new();
154 if (!connection->iterators) {
155 BT_PUT(connection);
156 goto end;
157 }
158
784cdc68 159 /* Weak references are taken, see comment in header. */
72b913fb
PP
160 connection->upstream_port = upstream_port;
161 connection->downstream_port = downstream_port;
162 bt_port_set_connection(upstream_port, connection);
163 bt_port_set_connection(downstream_port, connection);
784cdc68
JG
164 bt_object_set_parent(connection, &graph->base);
165end:
166 return connection;
167}
168
72b913fb 169BT_HIDDEN
2038affb 170void bt_connection_disconnect_ports(struct bt_connection *conn)
72b913fb
PP
171{
172 struct bt_component *downstream_comp = NULL;
173 struct bt_component *upstream_comp = NULL;
174 struct bt_port *downstream_port = conn->downstream_port;
175 struct bt_port *upstream_port = conn->upstream_port;
f167d3c0
PP
176 struct bt_graph *graph = (void *) bt_object_borrow_parent(conn);
177 size_t i;
72b913fb
PP
178
179 if (downstream_port) {
180 downstream_comp = bt_port_get_component(downstream_port);
181 bt_port_set_connection(downstream_port, NULL);
182 conn->downstream_port = NULL;
183 }
184
185 if (upstream_port) {
186 upstream_comp = bt_port_get_component(upstream_port);
187 bt_port_set_connection(upstream_port, NULL);
188 conn->upstream_port = NULL;
189 }
190
2038affb 191 if (downstream_comp) {
72b913fb
PP
192 bt_component_port_disconnected(downstream_comp,
193 downstream_port);
194 }
195
2038affb 196 if (upstream_comp) {
72b913fb
PP
197 bt_component_port_disconnected(upstream_comp, upstream_port);
198 }
199
f345f8bb
PP
200 assert(graph);
201 bt_graph_notify_ports_disconnected(graph, upstream_comp,
202 downstream_comp, upstream_port, downstream_port);
72b913fb
PP
203 bt_put(downstream_comp);
204 bt_put(upstream_comp);
f167d3c0
PP
205
206 /*
207 * Because this connection is dead, finalize (cancel) each
208 * notification iterator created from it.
209 */
210 for (i = 0; i < conn->iterators->len; i++) {
211 struct bt_notification_iterator *iterator =
212 g_ptr_array_index(conn->iterators, i);
213
214 bt_notification_iterator_finalize(iterator);
215
216 /*
217 * Make sure this iterator does not try to remove itself
218 * from this connection's iterators on destruction
219 * because this connection won't exist anymore.
220 */
221 bt_notification_iterator_set_connection(iterator,
222 NULL);
223 }
224
225 g_ptr_array_set_size(conn->iterators, 0);
226 bt_connection_try_remove_from_graph(conn);
72b913fb
PP
227}
228
229struct bt_port *bt_connection_get_upstream_port(
784cdc68
JG
230 struct bt_connection *connection)
231{
72b913fb 232 return connection ? bt_get(connection->upstream_port) : NULL;
784cdc68
JG
233}
234
72b913fb 235struct bt_port *bt_connection_get_downstream_port(
784cdc68
JG
236 struct bt_connection *connection)
237{
72b913fb 238 return connection ? bt_get(connection->downstream_port) : NULL;
784cdc68
JG
239}
240
241struct bt_notification_iterator *
890882ef 242bt_private_connection_create_notification_iterator(
fa054faf
PP
243 struct bt_private_connection *private_connection,
244 const enum bt_notification_type *notification_types)
784cdc68 245{
890882ef
PP
246 enum bt_notification_iterator_status ret_iterator;
247 enum bt_component_class_type upstream_comp_class_type;
248 struct bt_notification_iterator *iterator = NULL;
249 struct bt_port *upstream_port = NULL;
784cdc68 250 struct bt_component *upstream_component = NULL;
890882ef
PP
251 struct bt_component_class *upstream_comp_class = NULL;
252 struct bt_connection *connection = NULL;
253 bt_component_class_notification_iterator_init_method init_method = NULL;
fa054faf
PP
254 static const enum bt_notification_type all_notif_types[] = {
255 BT_NOTIFICATION_TYPE_ALL,
256 BT_NOTIFICATION_TYPE_SENTINEL,
257 };
784cdc68 258
890882ef
PP
259 if (!private_connection) {
260 goto error;
784cdc68
JG
261 }
262
fa054faf
PP
263 if (!notification_types) {
264 notification_types = all_notif_types;
265 }
266
890882ef 267 connection = bt_connection_from_private(private_connection);
72b913fb 268 if (!connection->upstream_port || !connection->downstream_port) {
890882ef 269 goto error;
72b913fb
PP
270 }
271
890882ef
PP
272 upstream_port = connection->upstream_port;
273 assert(upstream_port);
274 upstream_component = bt_port_get_component(upstream_port);
784cdc68 275 assert(upstream_component);
890882ef
PP
276 upstream_comp_class = upstream_component->class;
277
278 if (!upstream_component) {
279 goto error;
280 }
281
282 upstream_comp_class_type =
283 bt_component_get_class_type(upstream_component);
284 if (upstream_comp_class_type != BT_COMPONENT_CLASS_TYPE_SOURCE &&
285 upstream_comp_class_type != BT_COMPONENT_CLASS_TYPE_FILTER) {
286 /* Unsupported operation. */
287 goto error;
288 }
784cdc68 289
3230ee6b 290 iterator = bt_notification_iterator_create(upstream_component,
bd14d768 291 upstream_port, notification_types, connection);
890882ef
PP
292 if (!iterator) {
293 goto error;
294 }
295
296 switch (upstream_comp_class_type) {
784cdc68 297 case BT_COMPONENT_CLASS_TYPE_SOURCE:
890882ef
PP
298 {
299 struct bt_component_class_source *source_class =
300 container_of(upstream_comp_class,
301 struct bt_component_class_source, parent);
302 init_method = source_class->methods.iterator.init;
784cdc68 303 break;
890882ef 304 }
784cdc68 305 case BT_COMPONENT_CLASS_TYPE_FILTER:
890882ef
PP
306 {
307 struct bt_component_class_filter *filter_class =
308 container_of(upstream_comp_class,
309 struct bt_component_class_filter, parent);
310 init_method = filter_class->methods.iterator.init;
784cdc68 311 break;
890882ef 312 }
784cdc68 313 default:
890882ef
PP
314 /* Unreachable. */
315 assert(0);
316 }
317
318 if (init_method) {
319 enum bt_notification_iterator_status status = init_method(
91457551
PP
320 bt_private_notification_iterator_from_notification_iterator(iterator),
321 bt_private_port_from_port(upstream_port));
890882ef
PP
322 if (status < 0) {
323 goto error;
324 }
325 }
326
327 ret_iterator = bt_notification_iterator_validate(iterator);
328 if (ret_iterator != BT_NOTIFICATION_ITERATOR_STATUS_OK) {
329 goto error;
784cdc68 330 }
890882ef 331
bd14d768 332 g_ptr_array_add(connection->iterators, iterator);
890882ef
PP
333 goto end;
334
335error:
336 BT_PUT(iterator);
337
784cdc68
JG
338end:
339 bt_put(upstream_component);
890882ef 340 return iterator;
784cdc68 341}
bd14d768
PP
342
343BT_HIDDEN
344void bt_connection_remove_iterator(struct bt_connection *conn,
345 struct bt_notification_iterator *iterator)
346{
347 g_ptr_array_remove(conn->iterators, iterator);
f167d3c0 348 bt_connection_try_remove_from_graph(conn);
bd14d768 349}
This page took 0.043123 seconds and 4 git commands to generate.