Commit | Line | Data |
---|---|---|
784cdc68 | 1 | /* |
0235b0db MJ |
2 | * SPDX-License-Identifier: MIT |
3 | * | |
e2f7325d | 4 | * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com> |
784cdc68 | 5 | * Copyright 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com> |
784cdc68 JG |
6 | */ |
7 | ||
350ad6c1 | 8 | #define BT_LOG_TAG "LIB/CONNECTION" |
c2d9d9cf | 9 | #include "lib/logging.h" |
a36bfb16 | 10 | |
578e048b | 11 | #include "common/assert.h" |
d98421f2 | 12 | #include "lib/assert-cond.h" |
43c59509 | 13 | #include <babeltrace2/graph/connection.h> |
578e048b MJ |
14 | #include "lib/object.h" |
15 | #include "compat/compiler.h" | |
c4f23e30 | 16 | #include <stdbool.h> |
0fbb9a9f | 17 | #include <stdlib.h> |
784cdc68 JG |
18 | #include <glib.h> |
19 | ||
578e048b MJ |
20 | #include "component.h" |
21 | #include "connection.h" | |
22 | #include "graph.h" | |
23 | #include "message/iterator.h" | |
24 | #include "port.h" | |
25 | ||
784cdc68 | 26 | static |
d94d92ac | 27 | void destroy_connection(struct bt_object *obj) |
784cdc68 JG |
28 | { |
29 | struct bt_connection *connection = container_of(obj, | |
30 | struct bt_connection, base); | |
bd14d768 | 31 | |
3f7d4d90 | 32 | BT_LIB_LOGI("Destroying connection: %!+x", connection); |
a36bfb16 | 33 | |
bd14d768 | 34 | /* |
d0fea130 PP |
35 | * Make sure that each message iterator which was created for |
36 | * this connection is finalized before we destroy it. Once a | |
9b4f9b42 | 37 | * message iterator is finalized, you cannot use it. |
bd14d768 PP |
38 | * |
39 | * Because connections are destroyed before components within a | |
d6e69534 | 40 | * graph, this ensures that message iterators are always |
bd14d768 | 41 | * finalized before their upstream component. |
c42ea0af PP |
42 | * |
43 | * Ending the connection does exactly this. We pass `false` to | |
44 | * bt_connection_end() here to avoid removing this connection | |
45 | * from the graph: if we're here, we're already in the graph's | |
46 | * destructor. | |
bd14d768 | 47 | */ |
c42ea0af PP |
48 | bt_connection_end(connection, false); |
49 | g_ptr_array_free(connection->iterators, TRUE); | |
d94d92ac | 50 | connection->iterators = NULL; |
784cdc68 JG |
51 | |
52 | /* | |
65300d60 | 53 | * No bt_object_put_ref on ports as a connection only holds _weak_ |
c42ea0af | 54 | * references to them. |
784cdc68 JG |
55 | */ |
56 | g_free(connection); | |
57 | } | |
58 | ||
f167d3c0 | 59 | static |
d94d92ac | 60 | void try_remove_connection_from_graph(struct bt_connection *connection) |
f167d3c0 | 61 | { |
3fea54f6 | 62 | void *graph = (void *) bt_object_borrow_parent(&connection->base); |
f167d3c0 | 63 | |
3fea54f6 | 64 | if (connection->base.ref_count > 0 || |
f167d3c0 PP |
65 | connection->downstream_port || |
66 | connection->upstream_port || | |
67 | connection->iterators->len > 0) { | |
68 | return; | |
69 | } | |
70 | ||
71 | /* | |
72 | * At this point we know that: | |
73 | * | |
a36bfb16 | 74 | * 1. The connection is ended (ports were disconnected). |
d6e69534 | 75 | * 2. All the message iterators that this connection |
f167d3c0 PP |
76 | * created, if any, are finalized. |
77 | * 3. The connection's reference count is 0, so only the | |
78 | * parent (graph) owns this connection after this call. | |
79 | * | |
80 | * In other words, no other object than the graph knows this | |
81 | * connection. | |
82 | * | |
83 | * It is safe to remove the connection from the graph, therefore | |
84 | * destroying it. | |
85 | */ | |
d94d92ac PP |
86 | BT_LIB_LOGD("Removing self from graph's connections: " |
87 | "%![graph-]+g, %![conn-]+x", graph, connection); | |
f167d3c0 PP |
88 | bt_graph_remove_connection(graph, connection); |
89 | } | |
90 | ||
91 | static | |
d94d92ac | 92 | void parent_is_owner(struct bt_object *obj) |
f167d3c0 PP |
93 | { |
94 | struct bt_connection *connection = container_of(obj, | |
95 | struct bt_connection, base); | |
96 | ||
d94d92ac | 97 | try_remove_connection_from_graph(connection); |
890882ef PP |
98 | } |
99 | ||
d94d92ac | 100 | struct bt_connection *bt_connection_create(struct bt_graph *graph, |
72b913fb PP |
101 | struct bt_port *upstream_port, |
102 | struct bt_port *downstream_port) | |
784cdc68 JG |
103 | { |
104 | struct bt_connection *connection = NULL; | |
105 | ||
3f7d4d90 | 106 | BT_LIB_LOGI("Creating connection: " |
d94d92ac PP |
107 | "%![graph-]+g, %![up-port-]+p, %![down-port-]+p", |
108 | graph, upstream_port, downstream_port); | |
784cdc68 JG |
109 | connection = g_new0(struct bt_connection, 1); |
110 | if (!connection) { | |
870631a2 | 111 | BT_LIB_LOGE_APPEND_CAUSE("Failed to allocate one connection."); |
784cdc68 JG |
112 | goto end; |
113 | } | |
114 | ||
3fea54f6 | 115 | bt_object_init_shared_with_parent(&connection->base, |
d94d92ac | 116 | destroy_connection); |
3fea54f6 | 117 | bt_object_set_parent_is_owner_listener_func(&connection->base, |
d94d92ac | 118 | parent_is_owner); |
bd14d768 PP |
119 | connection->iterators = g_ptr_array_new(); |
120 | if (!connection->iterators) { | |
870631a2 | 121 | BT_LIB_LOGE_APPEND_CAUSE("Failed to allocate a GPtrArray."); |
65300d60 | 122 | BT_OBJECT_PUT_REF_AND_RESET(connection); |
bd14d768 PP |
123 | goto end; |
124 | } | |
125 | ||
784cdc68 | 126 | /* Weak references are taken, see comment in header. */ |
72b913fb PP |
127 | connection->upstream_port = upstream_port; |
128 | connection->downstream_port = downstream_port; | |
d94d92ac | 129 | BT_LIB_LOGD("Setting upstream port's connection: %!+p", upstream_port); |
72b913fb | 130 | bt_port_set_connection(upstream_port, connection); |
d94d92ac PP |
131 | BT_LIB_LOGD("Setting downstream port's connection: %!+p", |
132 | downstream_port); | |
72b913fb | 133 | bt_port_set_connection(downstream_port, connection); |
3fea54f6 | 134 | bt_object_set_parent(&connection->base, &graph->base); |
3f7d4d90 | 135 | BT_LIB_LOGI("Created connection: %!+x", connection); |
a36bfb16 | 136 | |
784cdc68 JG |
137 | end: |
138 | return connection; | |
139 | } | |
140 | ||
d94d92ac | 141 | void bt_connection_end(struct bt_connection *conn, bool try_remove_from_graph) |
72b913fb | 142 | { |
72b913fb PP |
143 | struct bt_port *downstream_port = conn->downstream_port; |
144 | struct bt_port *upstream_port = conn->upstream_port; | |
f167d3c0 | 145 | size_t i; |
72b913fb | 146 | |
3f7d4d90 | 147 | BT_LIB_LOGI("Ending connection: %!+x, try-remove-from-graph=%d", |
c42ea0af PP |
148 | conn, try_remove_from_graph); |
149 | ||
d94d92ac | 150 | /* |
d6e69534 | 151 | * Any of the following message callback functions could |
d94d92ac PP |
152 | * remove one of the connection's ports from its component. To |
153 | * make sure that at least logging in called functions works | |
154 | * with existing objects, get a local reference on both ports. | |
155 | */ | |
156 | bt_object_get_ref(downstream_port); | |
157 | bt_object_get_ref(upstream_port); | |
158 | ||
72b913fb | 159 | if (downstream_port) { |
d94d92ac PP |
160 | BT_LIB_LOGD("Disconnecting connection's downstream port: %!+p", |
161 | downstream_port); | |
72b913fb PP |
162 | bt_port_set_connection(downstream_port, NULL); |
163 | conn->downstream_port = NULL; | |
164 | } | |
165 | ||
166 | if (upstream_port) { | |
d94d92ac PP |
167 | BT_LIB_LOGD("Disconnecting connection's upstream port: %!+p", |
168 | upstream_port); | |
72b913fb PP |
169 | bt_port_set_connection(upstream_port, NULL); |
170 | conn->upstream_port = NULL; | |
171 | } | |
172 | ||
d94d92ac PP |
173 | /* |
174 | * It is safe to put the local port references now that we don't | |
175 | * need them anymore. This could indeed destroy them. | |
176 | */ | |
177 | bt_object_put_ref(downstream_port); | |
178 | bt_object_put_ref(upstream_port); | |
f167d3c0 PP |
179 | |
180 | /* | |
d0fea130 PP |
181 | * Because this connection is ended, finalize each message |
182 | * iterator created from it. | |
183 | * | |
184 | * In practice, this only happens when the connection is | |
185 | * destroyed and not all its message iterators were finalized, | |
186 | * which is on graph destruction. | |
f167d3c0 PP |
187 | */ |
188 | for (i = 0; i < conn->iterators->len; i++) { | |
9a2c8b8e | 189 | struct bt_message_iterator *iterator = |
f167d3c0 PP |
190 | g_ptr_array_index(conn->iterators, i); |
191 | ||
d6e69534 | 192 | BT_LIB_LOGD("Finalizing message iterator created by " |
d94d92ac | 193 | "this ended connection: %![iter-]+i", iterator); |
9a2c8b8e | 194 | bt_message_iterator_try_finalize( |
d94d92ac | 195 | iterator); |
f167d3c0 PP |
196 | |
197 | /* | |
198 | * Make sure this iterator does not try to remove itself | |
199 | * from this connection's iterators on destruction | |
200 | * because this connection won't exist anymore. | |
201 | */ | |
9a2c8b8e | 202 | bt_message_iterator_set_connection( |
90157d89 | 203 | iterator, NULL); |
f167d3c0 PP |
204 | } |
205 | ||
206 | g_ptr_array_set_size(conn->iterators, 0); | |
c42ea0af PP |
207 | |
208 | if (try_remove_from_graph) { | |
d94d92ac | 209 | try_remove_connection_from_graph(conn); |
c42ea0af | 210 | } |
72b913fb PP |
211 | } |
212 | ||
1353b066 | 213 | BT_EXPORT |
0d72b8c3 PP |
214 | const struct bt_port_output *bt_connection_borrow_upstream_port_const( |
215 | const struct bt_connection *connection) | |
784cdc68 | 216 | { |
d5b13b9b | 217 | BT_ASSERT_PRE_DEV_CONN_NON_NULL(connection); |
d94d92ac | 218 | return (void *) connection->upstream_port; |
784cdc68 JG |
219 | } |
220 | ||
1353b066 | 221 | BT_EXPORT |
0d72b8c3 PP |
222 | const struct bt_port_input *bt_connection_borrow_downstream_port_const( |
223 | const struct bt_connection *connection) | |
784cdc68 | 224 | { |
d5b13b9b | 225 | BT_ASSERT_PRE_DEV_CONN_NON_NULL(connection); |
d94d92ac | 226 | return (void *) connection->downstream_port; |
784cdc68 | 227 | } |
bd14d768 | 228 | |
bd14d768 | 229 | void bt_connection_remove_iterator(struct bt_connection *conn, |
9a2c8b8e | 230 | struct bt_message_iterator *iterator) |
bd14d768 PP |
231 | { |
232 | g_ptr_array_remove(conn->iterators, iterator); | |
3f7d4d90 | 233 | BT_LIB_LOGD("Removed message iterator from connection: " |
d94d92ac PP |
234 | "%![conn-]+x, %![iter-]+i", conn, iterator); |
235 | try_remove_connection_from_graph(conn); | |
bd14d768 | 236 | } |
090a4c0a | 237 | |
1353b066 | 238 | BT_EXPORT |
c5b9b441 PP |
239 | void bt_connection_get_ref(const struct bt_connection *connection) |
240 | { | |
241 | bt_object_get_ref(connection); | |
242 | } | |
243 | ||
1353b066 | 244 | BT_EXPORT |
c5b9b441 PP |
245 | void bt_connection_put_ref(const struct bt_connection *connection) |
246 | { | |
247 | bt_object_put_ref(connection); | |
248 | } |