Fix possible leaks in graph's current design
[babeltrace.git] / lib / graph / connection.c
1 /*
2 * connection.c
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
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>
37 #include <babeltrace/object-internal.h>
38 #include <babeltrace/compiler-internal.h>
39 #include <glib.h>
40
41 static
42 void bt_connection_destroy(struct bt_object *obj)
43 {
44 struct bt_connection *connection = container_of(obj,
45 struct bt_connection, base);
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 }
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
85 struct bt_connection *bt_connection_from_private_connection(
86 struct bt_private_connection *private_connection)
87 {
88 return bt_get(bt_connection_from_private(private_connection));
89 }
90
91 BT_HIDDEN
92 struct bt_connection *bt_connection_create(
93 struct bt_graph *graph,
94 struct bt_port *upstream_port,
95 struct bt_port *downstream_port)
96 {
97 struct bt_connection *connection = NULL;
98
99 if (bt_port_get_type(upstream_port) != BT_PORT_TYPE_OUTPUT) {
100 goto end;
101 }
102 if (bt_port_get_type(downstream_port) != BT_PORT_TYPE_INPUT) {
103 goto end;
104 }
105
106 connection = g_new0(struct bt_connection, 1);
107 if (!connection) {
108 goto end;
109 }
110
111 bt_object_init(connection, bt_connection_destroy);
112 connection->iterators = g_ptr_array_new();
113 if (!connection->iterators) {
114 BT_PUT(connection);
115 goto end;
116 }
117
118 /* Weak references are taken, see comment in header. */
119 connection->upstream_port = upstream_port;
120 connection->downstream_port = downstream_port;
121 bt_port_set_connection(upstream_port, connection);
122 bt_port_set_connection(downstream_port, connection);
123 bt_object_set_parent(connection, &graph->base);
124 end:
125 return connection;
126 }
127
128 BT_HIDDEN
129 void bt_connection_disconnect_ports(struct bt_connection *conn)
130 {
131 struct bt_component *downstream_comp = NULL;
132 struct bt_component *upstream_comp = NULL;
133 struct bt_port *downstream_port = conn->downstream_port;
134 struct bt_port *upstream_port = conn->upstream_port;
135 struct bt_graph *graph = (void *) bt_object_get_parent(conn);
136
137 if (downstream_port) {
138 downstream_comp = bt_port_get_component(downstream_port);
139 bt_port_set_connection(downstream_port, NULL);
140 conn->downstream_port = NULL;
141 }
142
143 if (upstream_port) {
144 upstream_comp = bt_port_get_component(upstream_port);
145 bt_port_set_connection(upstream_port, NULL);
146 conn->upstream_port = NULL;
147 }
148
149 if (downstream_comp) {
150 bt_component_port_disconnected(downstream_comp,
151 downstream_port);
152 }
153
154 if (upstream_comp) {
155 bt_component_port_disconnected(upstream_comp, upstream_port);
156 }
157
158 assert(graph);
159 bt_graph_notify_ports_disconnected(graph, upstream_comp,
160 downstream_comp, upstream_port, downstream_port);
161 bt_put(downstream_comp);
162 bt_put(upstream_comp);
163 bt_put(graph);
164 }
165
166 struct bt_port *bt_connection_get_upstream_port(
167 struct bt_connection *connection)
168 {
169 return connection ? bt_get(connection->upstream_port) : NULL;
170 }
171
172 struct bt_port *bt_connection_get_downstream_port(
173 struct bt_connection *connection)
174 {
175 return connection ? bt_get(connection->downstream_port) : NULL;
176 }
177
178 struct bt_notification_iterator *
179 bt_private_connection_create_notification_iterator(
180 struct bt_private_connection *private_connection,
181 const enum bt_notification_type *notification_types)
182 {
183 enum bt_notification_iterator_status ret_iterator;
184 enum bt_component_class_type upstream_comp_class_type;
185 struct bt_notification_iterator *iterator = NULL;
186 struct bt_port *upstream_port = NULL;
187 struct bt_component *upstream_component = NULL;
188 struct bt_component_class *upstream_comp_class = NULL;
189 struct bt_connection *connection = NULL;
190 bt_component_class_notification_iterator_init_method init_method = NULL;
191 static const enum bt_notification_type all_notif_types[] = {
192 BT_NOTIFICATION_TYPE_ALL,
193 BT_NOTIFICATION_TYPE_SENTINEL,
194 };
195
196 if (!private_connection) {
197 goto error;
198 }
199
200 if (!notification_types) {
201 notification_types = all_notif_types;
202 }
203
204 connection = bt_connection_from_private(private_connection);
205 if (!connection->upstream_port || !connection->downstream_port) {
206 goto error;
207 }
208
209 upstream_port = connection->upstream_port;
210 assert(upstream_port);
211 upstream_component = bt_port_get_component(upstream_port);
212 assert(upstream_component);
213 upstream_comp_class = upstream_component->class;
214
215 if (!upstream_component) {
216 goto error;
217 }
218
219 upstream_comp_class_type =
220 bt_component_get_class_type(upstream_component);
221 if (upstream_comp_class_type != BT_COMPONENT_CLASS_TYPE_SOURCE &&
222 upstream_comp_class_type != BT_COMPONENT_CLASS_TYPE_FILTER) {
223 /* Unsupported operation. */
224 goto error;
225 }
226
227 iterator = bt_notification_iterator_create(upstream_component,
228 upstream_port, notification_types, connection);
229 if (!iterator) {
230 goto error;
231 }
232
233 switch (upstream_comp_class_type) {
234 case BT_COMPONENT_CLASS_TYPE_SOURCE:
235 {
236 struct bt_component_class_source *source_class =
237 container_of(upstream_comp_class,
238 struct bt_component_class_source, parent);
239 init_method = source_class->methods.iterator.init;
240 break;
241 }
242 case BT_COMPONENT_CLASS_TYPE_FILTER:
243 {
244 struct bt_component_class_filter *filter_class =
245 container_of(upstream_comp_class,
246 struct bt_component_class_filter, parent);
247 init_method = filter_class->methods.iterator.init;
248 break;
249 }
250 default:
251 /* Unreachable. */
252 assert(0);
253 }
254
255 if (init_method) {
256 enum bt_notification_iterator_status status = init_method(
257 bt_private_notification_iterator_from_notification_iterator(iterator),
258 bt_private_port_from_port(upstream_port));
259 if (status < 0) {
260 goto error;
261 }
262 }
263
264 ret_iterator = bt_notification_iterator_validate(iterator);
265 if (ret_iterator != BT_NOTIFICATION_ITERATOR_STATUS_OK) {
266 goto error;
267 }
268
269 g_ptr_array_add(connection->iterators, iterator);
270 goto end;
271
272 error:
273 BT_PUT(iterator);
274
275 end:
276 bt_put(upstream_component);
277 return iterator;
278 }
279
280 BT_HIDDEN
281 void bt_connection_remove_iterator(struct bt_connection *conn,
282 struct bt_notification_iterator *iterator)
283 {
284 g_ptr_array_remove(conn->iterators, iterator);
285 }
This page took 0.036197 seconds and 4 git commands to generate.