lib: make values API const-correct
[babeltrace.git] / lib / graph / iterator.c
CommitLineData
47e5a032 1/*
47e5a032 2 * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
3230ee6b 3 * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
47e5a032
JG
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
5af447e5
PP
24#define BT_LOG_TAG "NOTIF-ITER"
25#include <babeltrace/lib-logging-internal.h>
26
3d9990ac 27#include <babeltrace/compiler-internal.h>
8138bfe1 28#include <babeltrace/object.h>
108b91d0 29#include <babeltrace/trace-ir/fields.h>
108b91d0
PP
30#include <babeltrace/trace-ir/event-internal.h>
31#include <babeltrace/trace-ir/packet-internal.h>
32#include <babeltrace/trace-ir/stream-internal.h>
73d5c1ad 33#include <babeltrace/graph/connection.h>
bd14d768 34#include <babeltrace/graph/connection-internal.h>
b2e0c907 35#include <babeltrace/graph/component.h>
9e550e5f 36#include <babeltrace/graph/component-internal.h>
b2e0c907
PP
37#include <babeltrace/graph/component-source-internal.h>
38#include <babeltrace/graph/component-class-internal.h>
c3ac0193
PP
39#include <babeltrace/graph/component-class-sink-colander-internal.h>
40#include <babeltrace/graph/component-sink.h>
fa054faf 41#include <babeltrace/graph/notification.h>
b2e0c907
PP
42#include <babeltrace/graph/notification-iterator.h>
43#include <babeltrace/graph/notification-iterator-internal.h>
834e9996
PP
44#include <babeltrace/graph/self-component-port-input-notification-iterator.h>
45#include <babeltrace/graph/port-output-notification-iterator.h>
e7fa96c3 46#include <babeltrace/graph/notification-internal.h>
3230ee6b
PP
47#include <babeltrace/graph/notification-event.h>
48#include <babeltrace/graph/notification-event-internal.h>
49#include <babeltrace/graph/notification-packet.h>
50#include <babeltrace/graph/notification-packet-internal.h>
51#include <babeltrace/graph/notification-stream.h>
52#include <babeltrace/graph/notification-stream-internal.h>
53#include <babeltrace/graph/port.h>
8d750b42 54#include <babeltrace/graph/private-graph.h>
c3ac0193 55#include <babeltrace/graph/graph-internal.h>
c55a9f58 56#include <babeltrace/types.h>
8b45963b 57#include <babeltrace/assert-internal.h>
6ff151ad 58#include <babeltrace/assert-pre-internal.h>
fa054faf 59#include <stdint.h>
b04a393b 60#include <inttypes.h>
0fbb9a9f 61#include <stdlib.h>
3230ee6b 62
3fd7b79d
PP
63/*
64 * TODO: Use graph's state (number of active iterators, etc.) and
65 * possibly system specifications to make a better guess than this.
66 */
67#define NOTIF_BATCH_SIZE 15
68
3230ee6b 69struct stream_state {
839d52a5
PP
70 struct bt_stream *stream; /* owned by this */
71 struct bt_packet *cur_packet; /* owned by this */
6ff151ad 72 uint64_t expected_notif_seq_num;
c55a9f58 73 bt_bool is_ended;
3230ee6b
PP
74};
75
22e3b27d 76BT_ASSERT_PRE_FUNC
3230ee6b
PP
77static
78void destroy_stream_state(struct stream_state *stream_state)
79{
80 if (!stream_state) {
81 return;
82 }
83
5af447e5
PP
84 BT_LOGV("Destroying stream state: stream-state-addr=%p", stream_state);
85 BT_LOGV_STR("Putting stream state's current packet.");
834e9996 86 BT_OBJECT_PUT_REF_AND_RESET(stream_state->cur_packet);
5af447e5 87 BT_LOGV_STR("Putting stream state's stream.");
834e9996 88 BT_OBJECT_PUT_REF_AND_RESET(stream_state->stream);
3230ee6b
PP
89 g_free(stream_state);
90}
91
22e3b27d 92BT_ASSERT_PRE_FUNC
3230ee6b 93static
839d52a5 94struct stream_state *create_stream_state(struct bt_stream *stream)
3230ee6b
PP
95{
96 struct stream_state *stream_state = g_new0(struct stream_state, 1);
97
98 if (!stream_state) {
5af447e5 99 BT_LOGE_STR("Failed to allocate one stream state.");
3230ee6b
PP
100 goto end;
101 }
102
103 /*
6ff151ad 104 * We keep a reference to the stream until we know it's ended.
3230ee6b 105 */
4b70020d
PP
106 stream_state->stream = stream;
107 bt_object_get_no_null_check(stream_state->stream);
834e9996 108 BT_LIB_LOGV("Created stream state: %![stream-]+s, "
5af447e5 109 "stream-state-addr=%p",
834e9996 110 stream, stream_state);
3230ee6b
PP
111
112end:
113 return stream_state;
114}
47e5a032 115
c3ac0193
PP
116static
117void destroy_base_notification_iterator(struct bt_object *obj)
118{
3fd7b79d
PP
119 struct bt_notification_iterator *iterator = (void *) obj;
120
121 BT_ASSERT(iterator);
122
123 if (iterator->notifs) {
124 g_ptr_array_free(iterator->notifs, TRUE);
834e9996 125 iterator->notifs = NULL;
3fd7b79d
PP
126 }
127
128 g_free(iterator);
c3ac0193
PP
129}
130
47e5a032 131static
834e9996 132void bt_self_component_port_input_notification_iterator_destroy(struct bt_object *obj)
47e5a032 133{
834e9996 134 struct bt_self_component_port_input_notification_iterator *iterator;
8738a040 135
8b45963b 136 BT_ASSERT(obj);
d3eb6e8f 137
bd14d768
PP
138 /*
139 * The notification iterator's reference count is 0 if we're
140 * here. Increment it to avoid a double-destroy (possibly
141 * infinitely recursive). This could happen for example if the
834e9996
PP
142 * notification iterator's finalization function does
143 * bt_object_get_ref() (or anything that causes
144 * bt_object_get_ref() to be called) on itself (ref. count goes
145 * from 0 to 1), and then bt_object_put_ref(): the reference
146 * count would go from 1 to 0 again and this function would be
147 * called again.
bd14d768 148 */
1d7bf349 149 obj->ref_count++;
94a96686 150 iterator = (void *) obj;
834e9996
PP
151 BT_LIB_LOGD("Destroying self component input port notification iterator object: "
152 "%!+i", iterator);
153 bt_self_component_port_input_notification_iterator_finalize(iterator);
d3eb6e8f 154
3230ee6b
PP
155 if (iterator->stream_states) {
156 /*
157 * Remove our destroy listener from each stream which
158 * has a state in this iterator. Otherwise the destroy
159 * listener would be called with an invalid/other
160 * notification iterator object.
161 */
3230ee6b 162 g_hash_table_destroy(iterator->stream_states);
834e9996 163 iterator->stream_states = NULL;
3230ee6b
PP
164 }
165
bd14d768
PP
166 if (iterator->connection) {
167 /*
168 * Remove ourself from the originating connection so
169 * that it does not try to finalize a dangling pointer
170 * later.
171 */
172 bt_connection_remove_iterator(iterator->connection, iterator);
834e9996 173 iterator->connection = NULL;
bd14d768
PP
174 }
175
c3ac0193 176 destroy_base_notification_iterator(obj);
47e5a032
JG
177}
178
bd14d768 179BT_HIDDEN
834e9996
PP
180void bt_self_component_port_input_notification_iterator_finalize(
181 struct bt_self_component_port_input_notification_iterator *iterator)
bd14d768 182{
834e9996
PP
183 typedef void (*method_t)(void *);
184
bd14d768 185 struct bt_component_class *comp_class = NULL;
834e9996 186 method_t method = NULL;
bd14d768 187
8b45963b 188 BT_ASSERT(iterator);
bd14d768
PP
189
190 switch (iterator->state) {
834e9996 191 case BT_SELF_COMPONENT_PORT_INPUT_NOTIFICATION_ITERATOR_STATE_NON_INITIALIZED:
dba1e5d8 192 /* Skip user finalization if user initialization failed */
834e9996
PP
193 BT_LIB_LOGD("Not finalizing non-initialized notification iterator: "
194 "%!+i", iterator);
dba1e5d8 195 return;
834e9996
PP
196 case BT_SELF_COMPONENT_PORT_INPUT_NOTIFICATION_ITERATOR_STATE_FINALIZED:
197 case BT_SELF_COMPONENT_PORT_INPUT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED:
bd14d768 198 /* Already finalized */
834e9996
PP
199 BT_LIB_LOGD("Not finalizing notification iterator: already finalized: "
200 "%!+i", iterator);
bd14d768
PP
201 return;
202 default:
203 break;
204 }
205
834e9996 206 BT_LIB_LOGD("Finalizing notification iterator: %!+i", iterator);
5af447e5 207
834e9996
PP
208 if (iterator->state == BT_SELF_COMPONENT_PORT_INPUT_NOTIFICATION_ITERATOR_STATE_ENDED) {
209 BT_LIB_LOGD("Updating notification iterator's state: "
210 "new-state=BT_SELF_COMPONENT_PORT_INPUT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED");
211 iterator->state = BT_SELF_COMPONENT_PORT_INPUT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED;
df14f8af 212 } else {
834e9996
PP
213 BT_LIB_LOGD("Updating notification iterator's state: "
214 "new-state=BT_SELF_COMPONENT_PORT_INPUT_NOTIFICATION_ITERATOR_STATE_FINALIZED");
215 iterator->state = BT_SELF_COMPONENT_PORT_INPUT_NOTIFICATION_ITERATOR_STATE_FINALIZED;
df14f8af
MD
216 }
217
8b45963b 218 BT_ASSERT(iterator->upstream_component);
bd14d768
PP
219 comp_class = iterator->upstream_component->class;
220
221 /* Call user-defined destroy method */
222 switch (comp_class->type) {
223 case BT_COMPONENT_CLASS_TYPE_SOURCE:
224 {
834e9996
PP
225 struct bt_component_class_source *src_comp_cls =
226 (void *) comp_class;
bd14d768 227
834e9996 228 method = (method_t) src_comp_cls->methods.notif_iter_finalize;
bd14d768
PP
229 break;
230 }
231 case BT_COMPONENT_CLASS_TYPE_FILTER:
232 {
834e9996
PP
233 struct bt_component_class_filter *flt_comp_cls =
234 (void *) comp_class;
bd14d768 235
834e9996 236 method = (method_t) flt_comp_cls->methods.notif_iter_finalize;
bd14d768
PP
237 break;
238 }
239 default:
240 /* Unreachable */
0fbb9a9f 241 abort();
bd14d768
PP
242 }
243
834e9996
PP
244 if (method) {
245 BT_LIB_LOGD("Calling user's finalization method: %!+i",
5af447e5 246 iterator);
834e9996 247 method(iterator);
bd14d768
PP
248 }
249
bd14d768
PP
250 iterator->upstream_component = NULL;
251 iterator->upstream_port = NULL;
834e9996 252 BT_LIB_LOGD("Finalized notification iterator: %!+i", iterator);
bd14d768
PP
253}
254
255BT_HIDDEN
834e9996
PP
256void bt_self_component_port_input_notification_iterator_set_connection(
257 struct bt_self_component_port_input_notification_iterator *iterator,
bd14d768
PP
258 struct bt_connection *connection)
259{
8b45963b 260 BT_ASSERT(iterator);
bd14d768 261 iterator->connection = connection;
834e9996
PP
262 BT_LIB_LOGV("Set notification iterator's connection: "
263 "%![iter-]+i, %![conn-]+x", iterator, connection);
bd14d768
PP
264}
265
fe7265b5 266static
3fd7b79d 267int init_notification_iterator(struct bt_notification_iterator *iterator,
fe7265b5
PP
268 enum bt_notification_iterator_type type,
269 bt_object_release_func destroy)
270{
3fd7b79d
PP
271 int ret = 0;
272
1d7bf349 273 bt_object_init_shared(&iterator->base, destroy);
fe7265b5 274 iterator->type = type;
3fd7b79d
PP
275 iterator->notifs = g_ptr_array_new();
276 if (!iterator->notifs) {
277 BT_LOGE_STR("Failed to allocate a GPtrArray.");
278 ret = -1;
279 goto end;
280 }
281
282 g_ptr_array_set_size(iterator->notifs, NOTIF_BATCH_SIZE);
283
284end:
285 return ret;
fe7265b5
PP
286}
287
834e9996
PP
288static
289struct bt_self_component_port_input_notification_iterator *
290bt_self_component_port_input_notification_iterator_create_initial(
3230ee6b 291 struct bt_component *upstream_comp,
834e9996 292 struct bt_port *upstream_port)
47e5a032 293{
3fd7b79d 294 int ret;
834e9996 295 struct bt_self_component_port_input_notification_iterator *iterator = NULL;
47e5a032 296
8b45963b
PP
297 BT_ASSERT(upstream_comp);
298 BT_ASSERT(upstream_port);
8b45963b 299 BT_ASSERT(bt_port_is_connected(upstream_port));
834e9996
PP
300 BT_LIB_LOGD("Creating initial notification iterator on self component input port: "
301 "%![up-comp-]+c, %![up-port-]+p", upstream_comp, upstream_port);
302 BT_ASSERT(bt_component_get_class_type(upstream_comp) ==
303 BT_COMPONENT_CLASS_TYPE_SOURCE ||
304 bt_component_get_class_type(upstream_comp) ==
305 BT_COMPONENT_CLASS_TYPE_FILTER);
306 iterator = g_new0(
307 struct bt_self_component_port_input_notification_iterator, 1);
47e5a032 308 if (!iterator) {
834e9996
PP
309 BT_LOGE_STR("Failed to allocate one self component input port "
310 "notification iterator.");
73d5c1ad 311 goto end;
47e5a032
JG
312 }
313
3fd7b79d 314 ret = init_notification_iterator((void *) iterator,
834e9996
PP
315 BT_NOTIFICATION_ITERATOR_TYPE_SELF_COMPONENT_PORT_INPUT,
316 bt_self_component_port_input_notification_iterator_destroy);
3fd7b79d
PP
317 if (ret) {
318 /* init_notification_iterator() logs errors */
834e9996 319 BT_OBJECT_PUT_REF_AND_RESET(iterator);
3fd7b79d
PP
320 goto end;
321 }
3230ee6b
PP
322
323 iterator->stream_states = g_hash_table_new_full(g_direct_hash,
324 g_direct_equal, NULL, (GDestroyNotify) destroy_stream_state);
325 if (!iterator->stream_states) {
5af447e5 326 BT_LOGE_STR("Failed to allocate a GHashTable.");
834e9996 327 BT_OBJECT_PUT_REF_AND_RESET(iterator);
73d5c1ad 328 goto end;
3230ee6b
PP
329 }
330
bd14d768
PP
331 iterator->upstream_component = upstream_comp;
332 iterator->upstream_port = upstream_port;
834e9996 333 iterator->connection = iterator->upstream_port->connection;
f7c3ac09 334 iterator->graph = bt_component_borrow_graph(upstream_comp);
834e9996
PP
335 iterator->state = BT_SELF_COMPONENT_PORT_INPUT_NOTIFICATION_ITERATOR_STATE_NON_INITIALIZED;
336 BT_LIB_LOGD("Created initial notification iterator on self component input port: "
337 "%![up-port-]+p, %![up-comp-]+c, %![iter-]+i",
338 upstream_port, upstream_comp, iterator);
3230ee6b 339
47e5a032 340end:
834e9996 341 return iterator;
47e5a032
JG
342}
343
834e9996
PP
344struct bt_self_component_port_input_notification_iterator *
345bt_self_component_port_input_notification_iterator_create(
346 struct bt_self_component_port_input *self_port)
ea8d3e58 347{
834e9996
PP
348 typedef enum bt_self_notification_iterator_status (*init_method_t)(
349 void *, void *, void *);
350
351 init_method_t init_method = NULL;
352 struct bt_self_component_port_input_notification_iterator *iterator =
353 NULL;
354 struct bt_port *port = (void *) self_port;
355 struct bt_port *upstream_port;
356 struct bt_component *comp;
357 struct bt_component *upstream_comp;
358 struct bt_component_class *upstream_comp_cls;
359
360 BT_ASSERT_PRE_NON_NULL(port, "Port");
361 comp = bt_port_borrow_component(port);
362 BT_ASSERT_PRE(bt_port_is_connected(port),
363 "Port is not connected: %![port-]+p", port);
364 BT_ASSERT_PRE(comp, "Port is not part of a component: %![port-]+p",
365 port);
366 BT_ASSERT_PRE(!bt_component_graph_is_canceled(comp),
367 "Port's component's graph is canceled: "
368 "%![port-]+p, %![comp-]+c", port, comp);
369 BT_ASSERT(port->connection);
370 upstream_port = port->connection->upstream_port;
371 BT_ASSERT(upstream_port);
372 upstream_comp = bt_port_borrow_component(upstream_port);
373 BT_ASSERT(upstream_comp);
374 upstream_comp_cls = upstream_comp->class;
375 BT_ASSERT(upstream_comp->class->type ==
376 BT_COMPONENT_CLASS_TYPE_SOURCE ||
377 upstream_comp->class->type ==
378 BT_COMPONENT_CLASS_TYPE_FILTER);
379 iterator = bt_self_component_port_input_notification_iterator_create_initial(
380 upstream_comp, upstream_port);
381 if (!iterator) {
382 BT_LOGW_STR("Cannot create self component input port "
383 "notification iterator.");
384 goto end;
385 }
890882ef 386
834e9996
PP
387 switch (upstream_comp_cls->type) {
388 case BT_COMPONENT_CLASS_TYPE_SOURCE:
389 {
390 struct bt_component_class_source *src_comp_cls =
391 (void *) upstream_comp_cls;
392
393 init_method =
394 (init_method_t) src_comp_cls->methods.notif_iter_init;
395 break;
396 }
397 case BT_COMPONENT_CLASS_TYPE_FILTER:
398 {
399 struct bt_component_class_filter *flt_comp_cls =
400 (void *) upstream_comp_cls;
401
402 init_method =
403 (init_method_t) flt_comp_cls->methods.notif_iter_init;
404 break;
405 }
406 default:
407 /* Unreachable */
408 abort();
409 }
410
411 if (init_method) {
412 int iter_status;
413
414 BT_LIB_LOGD("Calling user's initialization method: %!+i", iterator);
415 iter_status = init_method(iterator, upstream_comp,
416 upstream_port);
417 BT_LOGD("User method returned: status=%s",
418 bt_notification_iterator_status_string(iter_status));
419 if (iter_status != BT_NOTIFICATION_ITERATOR_STATUS_OK) {
420 BT_LOGW_STR("Initialization method failed.");
421 goto end;
422 }
423 }
424
425 iterator->state = BT_SELF_COMPONENT_PORT_INPUT_NOTIFICATION_ITERATOR_STATE_ACTIVE;
426 g_ptr_array_add(port->connection->iterators, iterator);
427 BT_LIB_LOGD("Created notification iterator on self component input port: "
428 "%![up-port-]+p, %![up-comp-]+c, %![iter-]+i",
429 upstream_port, upstream_comp, iterator);
430
431end:
432 return iterator;
ea8d3e58
JG
433}
434
834e9996
PP
435void *bt_self_notification_iterator_get_data(
436 struct bt_self_notification_iterator *self_iterator)
ea8d3e58 437{
834e9996
PP
438 struct bt_self_component_port_input_notification_iterator *iterator =
439 (void *) self_iterator;
ea8d3e58 440
6ff151ad 441 BT_ASSERT_PRE_NON_NULL(iterator, "Notification iterator");
834e9996 442 return iterator->user_data;
8738a040 443}
413bc2c4 444
834e9996
PP
445void bt_self_notification_iterator_set_data(
446 struct bt_self_notification_iterator *self_iterator, void *data)
f7c3ac09 447{
834e9996
PP
448 struct bt_self_component_port_input_notification_iterator *iterator =
449 (void *) self_iterator;
f7c3ac09
PP
450
451 BT_ASSERT_PRE_NON_NULL(iterator, "Notification iterator");
834e9996
PP
452 iterator->user_data = data;
453 BT_LIB_LOGV("Set notification iterator's user data: "
454 "%!+i, user-data-addr=%p", iterator, data);
f7c3ac09
PP
455}
456
6ff151ad
PP
457BT_ASSERT_PRE_FUNC
458static inline
459void bt_notification_borrow_packet_stream(struct bt_notification *notif,
460 struct bt_stream **stream, struct bt_packet **packet)
fa054faf 461{
6ff151ad 462 BT_ASSERT(notif);
fa054faf 463
6ff151ad 464 switch (notif->type) {
fa054faf 465 case BT_NOTIFICATION_TYPE_EVENT:
6ff151ad
PP
466 *packet = bt_event_borrow_packet(
467 bt_notification_event_borrow_event(notif));
468 *stream = bt_packet_borrow_stream(*packet);
fa054faf
PP
469 break;
470 case BT_NOTIFICATION_TYPE_STREAM_BEGIN:
6ff151ad 471 *stream = bt_notification_stream_begin_borrow_stream(notif);
fa054faf
PP
472 break;
473 case BT_NOTIFICATION_TYPE_STREAM_END:
6ff151ad 474 *stream = bt_notification_stream_end_borrow_stream(notif);
fa054faf
PP
475 break;
476 case BT_NOTIFICATION_TYPE_PACKET_BEGIN:
6ff151ad
PP
477 *packet = bt_notification_packet_begin_borrow_packet(notif);
478 *stream = bt_packet_borrow_stream(*packet);
fa054faf
PP
479 break;
480 case BT_NOTIFICATION_TYPE_PACKET_END:
6ff151ad
PP
481 *packet = bt_notification_packet_end_borrow_packet(notif);
482 *stream = bt_packet_borrow_stream(*packet);
b04a393b 483 break;
fa054faf 484 default:
6ff151ad 485 break;
fa054faf 486 }
fa054faf
PP
487}
488
6ff151ad
PP
489BT_ASSERT_PRE_FUNC
490static inline
491bool validate_notification(
834e9996 492 struct bt_self_component_port_input_notification_iterator *iterator,
6ff151ad 493 struct bt_notification *notif)
3230ee6b 494{
6ff151ad 495 bool is_valid = true;
3230ee6b 496 struct stream_state *stream_state;
6ff151ad
PP
497 struct bt_stream *stream = NULL;
498 struct bt_packet *packet = NULL;
499
500 BT_ASSERT(notif);
501 bt_notification_borrow_packet_stream(notif, &stream, &packet);
502
503 if (!stream) {
504 /* we don't care about notifications not attached to streams */
505 goto end;
506 }
3230ee6b 507
6ff151ad
PP
508 stream_state = g_hash_table_lookup(iterator->stream_states, stream);
509 if (!stream_state) {
3230ee6b 510 /*
6ff151ad
PP
511 * No stream state for this stream: this notification
512 * MUST be a BT_NOTIFICATION_TYPE_STREAM_BEGIN notification
513 * and its sequence number must be 0.
3230ee6b 514 */
6ff151ad
PP
515 if (notif->type != BT_NOTIFICATION_TYPE_STREAM_BEGIN) {
516 BT_ASSERT_PRE_MSG("Unexpected notification: missing a "
517 "BT_NOTIFICATION_TYPE_STREAM_BEGIN "
518 "notification prior to this notification: "
519 "%![stream-]+s", stream);
520 is_valid = false;
3230ee6b
PP
521 goto end;
522 }
523
6ff151ad
PP
524 if (notif->seq_num == -1ULL) {
525 notif->seq_num = 0;
3230ee6b
PP
526 }
527
6ff151ad
PP
528 if (notif->seq_num != 0) {
529 BT_ASSERT_PRE_MSG("Unexpected notification sequence "
530 "number for this notification iterator: "
531 "this is the first notification for this "
532 "stream, expecting sequence number 0: "
533 "seq-num=%" PRIu64 ", %![stream-]+s",
534 notif->seq_num, stream);
535 is_valid = false;
3230ee6b 536 goto end;
3230ee6b 537 }
3230ee6b 538
6ff151ad
PP
539 stream_state = create_stream_state(stream);
540 if (!stream_state) {
541 abort();
542 }
fa054faf 543
6ff151ad
PP
544 g_hash_table_insert(iterator->stream_states, stream,
545 stream_state);
546 stream_state->expected_notif_seq_num++;
547 goto end;
fa054faf
PP
548 }
549
6ff151ad
PP
550 if (stream_state->is_ended) {
551 /*
552 * There's a new notification which has a reference to a
553 * stream which, from this iterator's point of view, is
554 * ended ("end of stream" notification was returned).
555 * This is bad: the API guarantees that it can never
556 * happen.
557 */
558 BT_ASSERT_PRE_MSG("Stream is already ended: %![stream-]+s",
559 stream);
560 is_valid = false;
fa054faf
PP
561 goto end;
562 }
563
6ff151ad
PP
564 if (notif->seq_num == -1ULL) {
565 notif->seq_num = stream_state->expected_notif_seq_num;
3230ee6b
PP
566 }
567
6ff151ad
PP
568 if (notif->seq_num != -1ULL &&
569 notif->seq_num != stream_state->expected_notif_seq_num) {
570 BT_ASSERT_PRE_MSG("Unexpected notification sequence number: "
571 "seq-num=%" PRIu64 ", "
572 "expected-seq-num=%" PRIu64 ", %![stream-]+s",
573 notif->seq_num, stream_state->expected_notif_seq_num,
574 stream);
575 is_valid = false;
fa054faf
PP
576 goto end;
577 }
578
6ff151ad
PP
579 switch (notif->type) {
580 case BT_NOTIFICATION_TYPE_STREAM_BEGIN:
581 BT_ASSERT_PRE_MSG("Unexpected BT_NOTIFICATION_TYPE_STREAM_BEGIN "
582 "notification at this point: notif-seq-num=%" PRIu64 ", "
583 "%![stream-]+s", notif->seq_num, stream);
584 is_valid = false;
585 goto end;
586 case BT_NOTIFICATION_TYPE_STREAM_END:
587 if (stream_state->cur_packet) {
588 BT_ASSERT_PRE_MSG("Unexpected BT_NOTIFICATION_TYPE_STREAM_END "
589 "notification: missing a "
590 "BT_NOTIFICATION_TYPE_PACKET_END notification "
591 "prior to this notification: "
592 "notif-seq-num=%" PRIu64 ", "
593 "%![stream-]+s", notif->seq_num, stream);
594 is_valid = false;
595 goto end;
596 }
597 stream_state->expected_notif_seq_num++;
598 stream_state->is_ended = true;
599 goto end;
600 case BT_NOTIFICATION_TYPE_PACKET_BEGIN:
601 if (stream_state->cur_packet) {
602 BT_ASSERT_PRE_MSG("Unexpected BT_NOTIFICATION_TYPE_PACKET_BEGIN "
603 "notification at this point: missing a "
604 "BT_NOTIFICATION_TYPE_PACKET_END notification "
605 "prior to this notification: "
606 "notif-seq-num=%" PRIu64 ", %![stream-]+s, "
607 "%![packet-]+a", notif->seq_num, stream,
608 packet);
609 is_valid = false;
610 goto end;
611 }
612 stream_state->expected_notif_seq_num++;
4b70020d
PP
613 stream_state->cur_packet = packet;
614 bt_object_get_no_null_check(stream_state->cur_packet);
6ff151ad
PP
615 goto end;
616 case BT_NOTIFICATION_TYPE_PACKET_END:
617 if (!stream_state->cur_packet) {
618 BT_ASSERT_PRE_MSG("Unexpected BT_NOTIFICATION_TYPE_PACKET_END "
619 "notification at this point: missing a "
620 "BT_NOTIFICATION_TYPE_PACKET_BEGIN notification "
621 "prior to this notification: "
622 "notif-seq-num=%" PRIu64 ", %![stream-]+s, "
623 "%![packet-]+a", notif->seq_num, stream,
624 packet);
625 is_valid = false;
626 goto end;
627 }
628 stream_state->expected_notif_seq_num++;
8138bfe1 629 BT_OBJECT_PUT_REF_AND_RESET(stream_state->cur_packet);
6ff151ad
PP
630 goto end;
631 case BT_NOTIFICATION_TYPE_EVENT:
632 if (packet != stream_state->cur_packet) {
633 BT_ASSERT_PRE_MSG("Unexpected packet for "
634 "BT_NOTIFICATION_TYPE_EVENT notification: "
635 "notif-seq-num=%" PRIu64 ", %![stream-]+s, "
636 "%![notif-packet-]+a, %![expected-packet-]+a",
637 notif->seq_num, stream,
638 stream_state->cur_packet, packet);
639 is_valid = false;
640 goto end;
641 }
642 stream_state->expected_notif_seq_num++;
643 goto end;
644 default:
645 break;
3230ee6b
PP
646 }
647
3230ee6b 648end:
6ff151ad 649 return is_valid;
3230ee6b
PP
650}
651
3fd7b79d
PP
652BT_ASSERT_PRE_FUNC
653static inline
654bool validate_notifications(
834e9996 655 struct bt_self_component_port_input_notification_iterator *iterator,
3fd7b79d
PP
656 uint64_t count)
657{
658 bool ret = true;
659 bt_notification_array notifs = (void *) iterator->base.notifs->pdata;
660 uint64_t i;
661
662 for (i = 0; i < count; i++) {
663 ret = validate_notification(iterator, notifs[i]);
664 if (!ret) {
665 break;
666 }
667 }
668
669 return ret;
670}
671
6ff151ad
PP
672BT_ASSERT_PRE_FUNC
673static inline bool priv_conn_notif_iter_can_end(
834e9996 674 struct bt_self_component_port_input_notification_iterator *iterator)
3230ee6b 675{
6ff151ad
PP
676 GHashTableIter iter;
677 gpointer stream_key, state_value;
678 bool ret = true;
3230ee6b 679
6ff151ad
PP
680 /*
681 * Verify that this iterator received a
682 * BT_NOTIFICATION_TYPE_STREAM_END notification for each stream
683 * which has a state.
684 */
3230ee6b 685
6ff151ad 686 g_hash_table_iter_init(&iter, iterator->stream_states);
3230ee6b 687
6ff151ad
PP
688 while (g_hash_table_iter_next(&iter, &stream_key, &state_value)) {
689 struct stream_state *stream_state = (void *) state_value;
3230ee6b 690
6ff151ad
PP
691 BT_ASSERT(stream_state);
692 BT_ASSERT(stream_key);
fa054faf 693
6ff151ad
PP
694 if (!stream_state->is_ended) {
695 BT_ASSERT_PRE_MSG("Ending notification iterator, "
696 "but stream is not ended: "
697 "%![stream-]s", stream_key);
698 ret = false;
699 goto end;
700 }
3230ee6b
PP
701 }
702
3230ee6b 703end:
3230ee6b
PP
704 return ret;
705}
706
6ff151ad 707enum bt_notification_iterator_status
834e9996
PP
708bt_self_component_port_input_notification_iterator_next(
709 struct bt_self_component_port_input_notification_iterator *iterator,
710 bt_notification_array *notifs, uint64_t *user_count)
3230ee6b 711{
834e9996
PP
712 typedef enum bt_self_notification_iterator_status (*method_t)(
713 void *, bt_notification_array, uint64_t, uint64_t *);
714
715 method_t method = NULL;
716 struct bt_component_class *comp_cls;
717 int status = BT_NOTIFICATION_ITERATOR_STATUS_OK;
718
719 BT_ASSERT_PRE_NON_NULL(iterator, "Notification iterator");
720 BT_ASSERT_PRE_NON_NULL(notifs, "Notification array (output)");
721 BT_ASSERT_PRE_NON_NULL(user_count, "Notification count (output)");
6ff151ad 722 BT_ASSERT_PRE(iterator->state ==
834e9996 723 BT_SELF_COMPONENT_PORT_INPUT_NOTIFICATION_ITERATOR_STATE_ACTIVE,
6ff151ad
PP
724 "Notification iterator's \"next\" called, but "
725 "iterator is in the wrong state: %!+i", iterator);
726 BT_ASSERT(iterator->upstream_component);
727 BT_ASSERT(iterator->upstream_component->class);
834e9996
PP
728 BT_LIB_LOGD("Getting next self component input port "
729 "notification iterator's notifications: %!+i", iterator);
730 comp_cls = iterator->upstream_component->class;
d3eb6e8f 731
3230ee6b 732 /* Pick the appropriate "next" method */
834e9996 733 switch (comp_cls->type) {
d3eb6e8f
PP
734 case BT_COMPONENT_CLASS_TYPE_SOURCE:
735 {
834e9996
PP
736 struct bt_component_class_source *src_comp_cls =
737 (void *) comp_cls;
d3eb6e8f 738
834e9996 739 method = (method_t) src_comp_cls->methods.notif_iter_next;
d3eb6e8f
PP
740 break;
741 }
742 case BT_COMPONENT_CLASS_TYPE_FILTER:
743 {
834e9996
PP
744 struct bt_component_class_filter *flt_comp_cls =
745 (void *) comp_cls;
d3eb6e8f 746
834e9996 747 method = (method_t) flt_comp_cls->methods.notif_iter_next;
d3eb6e8f
PP
748 break;
749 }
750 default:
0fbb9a9f 751 abort();
d3eb6e8f
PP
752 }
753
3230ee6b 754 /*
834e9996 755 * Call the user's "next" method to get the next notifications
fa054faf 756 * and status.
3230ee6b 757 */
834e9996 758 BT_ASSERT(method);
6ff151ad 759 BT_LOGD_STR("Calling user's \"next\" method.");
834e9996
PP
760 status = method(iterator,
761 (void *) iterator->base.notifs->pdata,
3fd7b79d 762 NOTIF_BATCH_SIZE, user_count);
6ff151ad 763 BT_LOGD("User method returned: status=%s",
3fd7b79d
PP
764 bt_notification_iterator_status_string(status));
765 if (status < 0) {
6ff151ad 766 BT_LOGW_STR("User method failed.");
6ff151ad
PP
767 goto end;
768 }
3230ee6b 769
834e9996
PP
770 if (iterator->state == BT_SELF_COMPONENT_PORT_INPUT_NOTIFICATION_ITERATOR_STATE_FINALIZED ||
771 iterator->state == BT_SELF_COMPONENT_PORT_INPUT_NOTIFICATION_ITERATOR_STATE_FINALIZED_AND_ENDED) {
6ff151ad
PP
772 /*
773 * The user's "next" method, somehow, cancelled its own
774 * notification iterator. This can happen, for example,
775 * when the user's method removes the port on which
776 * there's the connection from which the iterator was
777 * created. In this case, said connection is ended, and
778 * all its notification iterators are finalized.
779 *
8138bfe1 780 * Only bt_object_put_ref() the returned notification if
834e9996
PP
781 * the status is BT_NOTIFICATION_ITERATOR_STATUS_OK
782 * because otherwise this field could be garbage.
6ff151ad 783 */
3fd7b79d
PP
784 if (status == BT_NOTIFICATION_ITERATOR_STATUS_OK) {
785 uint64_t i;
786 bt_notification_array notifs =
834e9996 787 (void *) iterator->base.notifs->pdata;
3fd7b79d
PP
788
789 for (i = 0; i < *user_count; i++) {
8138bfe1 790 bt_object_put_ref(notifs[i]);
3fd7b79d 791 }
3230ee6b
PP
792 }
793
6ff151ad
PP
794 status = BT_NOTIFICATION_ITERATOR_STATUS_CANCELED;
795 goto end;
796 }
8cf27cc5 797
3fd7b79d
PP
798 switch (status) {
799 case BT_NOTIFICATION_ITERATOR_STATUS_OK:
800 BT_ASSERT_PRE(validate_notifications(iterator, *user_count),
801 "Notifications are invalid at this point: "
802 "%![notif-iter-]+i, count=%" PRIu64,
803 iterator, *user_count);
834e9996 804 *notifs = (void *) iterator->base.notifs->pdata;
3fd7b79d
PP
805 break;
806 case BT_NOTIFICATION_ITERATOR_STATUS_AGAIN:
3fd7b79d 807 goto end;
6ff151ad
PP
808 case BT_NOTIFICATION_ITERATOR_STATUS_END:
809 BT_ASSERT_PRE(priv_conn_notif_iter_can_end(iterator),
810 "Notification iterator cannot end at this point: "
811 "%!+i", iterator);
812 BT_ASSERT(iterator->state ==
834e9996
PP
813 BT_SELF_COMPONENT_PORT_INPUT_NOTIFICATION_ITERATOR_STATE_ACTIVE);
814 iterator->state = BT_SELF_COMPONENT_PORT_INPUT_NOTIFICATION_ITERATOR_STATE_ENDED;
6ff151ad
PP
815 BT_LOGD("Set new status: status=%s",
816 bt_notification_iterator_status_string(status));
817 goto end;
6ff151ad
PP
818 default:
819 /* Unknown non-error status */
820 abort();
41a2b7ae
PP
821 }
822
823end:
3230ee6b
PP
824 return status;
825}
826
827enum bt_notification_iterator_status
834e9996
PP
828bt_port_output_notification_iterator_next(
829 struct bt_port_output_notification_iterator *iterator,
3fd7b79d
PP
830 bt_notification_array *notifs_to_user,
831 uint64_t *count_to_user)
3230ee6b
PP
832{
833 enum bt_notification_iterator_status status;
94a96686 834 enum bt_graph_status graph_status;
3230ee6b 835
6ff151ad 836 BT_ASSERT_PRE_NON_NULL(iterator, "Notification iterator");
834e9996
PP
837 BT_ASSERT_PRE_NON_NULL(notifs_to_user, "Notification array (output)");
838 BT_ASSERT_PRE_NON_NULL(count_to_user, "Notification count (output)");
839 BT_LIB_LOGD("Getting next output port notification iterator's notifications: "
94a96686 840 "%!+i", iterator);
3fd7b79d 841
834e9996
PP
842 graph_status = bt_graph_consume_sink_no_check(iterator->graph,
843 iterator->colander);
94a96686
PP
844 switch (graph_status) {
845 case BT_GRAPH_STATUS_CANCELED:
94a96686 846 case BT_GRAPH_STATUS_AGAIN:
94a96686 847 case BT_GRAPH_STATUS_END:
94a96686 848 case BT_GRAPH_STATUS_NOMEM:
834e9996 849 status = (int) graph_status;
94a96686
PP
850 break;
851 case BT_GRAPH_STATUS_OK:
94a96686 852 status = BT_NOTIFICATION_ITERATOR_STATUS_OK;
3fd7b79d
PP
853
854 /*
855 * On success, the colander sink moves the notifications
856 * to this iterator's array and sets this iterator's
857 * notification count: move them to the user.
858 */
834e9996
PP
859 *notifs_to_user = (void *) iterator->base.notifs->pdata;
860 *count_to_user = iterator->count;
fe7265b5 861 break;
fe7265b5 862 default:
94a96686
PP
863 /* Other errors */
864 status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
fe7265b5 865 }
3230ee6b 866
3230ee6b 867 return status;
53d45b87
JG
868}
869
834e9996
PP
870struct bt_component *bt_self_component_port_input_notification_iterator_borrow_component(
871 struct bt_self_component_port_input_notification_iterator *iterator)
872{
873 BT_ASSERT_PRE_NON_NULL(iterator, "Notification iterator");
874 return iterator->upstream_component;
875}
876
877struct bt_self_component *bt_self_notification_iterator_borrow_component(
878 struct bt_self_notification_iterator *self_iterator)
413bc2c4 879{
834e9996
PP
880 struct bt_self_component_port_input_notification_iterator *iterator =
881 (void *) self_iterator;
fe7265b5 882
6ff151ad 883 BT_ASSERT_PRE_NON_NULL(iterator, "Notification iterator");
834e9996 884 return (void *) iterator->upstream_component;
413bc2c4
JG
885}
886
834e9996
PP
887struct bt_self_port_output *bt_self_notification_iterator_borrow_port(
888 struct bt_self_notification_iterator *self_iterator)
91457551 889{
834e9996
PP
890 struct bt_self_component_port_input_notification_iterator *iterator =
891 (void *) self_iterator;
892
893 BT_ASSERT_PRE_NON_NULL(iterator, "Notification iterator");
894 return (void *) iterator->upstream_port;
91457551 895}
c3ac0193
PP
896
897static
834e9996 898void bt_port_output_notification_iterator_destroy(struct bt_object *obj)
c3ac0193 899{
834e9996 900 struct bt_port_output_notification_iterator *iterator = (void *) obj;
c3ac0193 901
834e9996 902 BT_LIB_LOGD("Destroying output port notification iterator object: %!+i",
c3ac0193
PP
903 iterator);
904 BT_LOGD_STR("Putting graph.");
834e9996 905 BT_OBJECT_PUT_REF_AND_RESET(iterator->graph);
c3ac0193 906 BT_LOGD_STR("Putting colander sink component.");
834e9996 907 BT_OBJECT_PUT_REF_AND_RESET(iterator->colander);
c3ac0193
PP
908 destroy_base_notification_iterator(obj);
909}
910
834e9996
PP
911struct bt_port_output_notification_iterator *
912bt_port_output_notification_iterator_create(
913 struct bt_private_graph *priv_graph,
a9de0e7a 914 struct bt_port_output *output_port)
c3ac0193 915{
834e9996
PP
916 struct bt_port_output_notification_iterator *iterator = NULL;
917 struct bt_component_class_sink *colander_comp_cls = NULL;
c3ac0193 918 struct bt_component *output_port_comp = NULL;
834e9996
PP
919 struct bt_component_sink *colander_comp;
920 struct bt_graph *graph = (void *) priv_graph;
c3ac0193 921 enum bt_graph_status graph_status;
834e9996 922 struct bt_port_input *colander_in_port = NULL;
c3ac0193 923 struct bt_component_class_sink_colander_data colander_data;
3fd7b79d 924 int ret;
c3ac0193 925
834e9996 926 BT_ASSERT_PRE_NON_NULL(graph, "Graph");
6ff151ad 927 BT_ASSERT_PRE_NON_NULL(output_port, "Output port");
834e9996 928 output_port_comp = bt_port_borrow_component((void *) output_port);
6ff151ad
PP
929 BT_ASSERT_PRE(output_port_comp,
930 "Output port has no component: %!+p", output_port);
834e9996
PP
931 BT_ASSERT_PRE(bt_component_borrow_graph(output_port_comp) ==
932 (void *) graph,
933 "Output port is not part of graph: %![graph-]+g, %![port-]+p",
934 graph, output_port);
c3ac0193
PP
935
936 /* Create notification iterator */
834e9996
PP
937 BT_LIB_LOGD("Creating notification iterator on output port: "
938 "%![port-]+p, %![comp-]+c", output_port, output_port_comp);
939 iterator = g_new0(struct bt_port_output_notification_iterator, 1);
c3ac0193
PP
940 if (!iterator) {
941 BT_LOGE_STR("Failed to allocate one output port notification iterator.");
942 goto error;
943 }
944
3fd7b79d 945 ret = init_notification_iterator((void *) iterator,
834e9996
PP
946 BT_NOTIFICATION_ITERATOR_TYPE_PORT_OUTPUT,
947 bt_port_output_notification_iterator_destroy);
3fd7b79d
PP
948 if (ret) {
949 /* init_notification_iterator() logs errors */
8138bfe1 950 BT_OBJECT_PUT_REF_AND_RESET(iterator);
3fd7b79d
PP
951 goto end;
952 }
c3ac0193
PP
953
954 /* Create colander component */
955 colander_comp_cls = bt_component_class_sink_colander_get();
956 if (!colander_comp_cls) {
957 BT_LOGW("Cannot get colander sink component class.");
958 goto error;
959 }
960
4b70020d
PP
961 iterator->graph = graph;
962 bt_object_get_no_null_check(iterator->graph);
3fd7b79d
PP
963 colander_data.notifs = (void *) iterator->base.notifs->pdata;
964 colander_data.count_addr = &iterator->count;
a9de0e7a
PP
965
966 /* Hope that nobody uses this very unique name */
834e9996
PP
967 graph_status =
968 bt_private_graph_add_sink_component_with_init_method_data(
a9de0e7a
PP
969 (void *) graph, colander_comp_cls,
970 "colander-36ac3409-b1a8-4d60-ab1f-4fdf341a8fb1",
834e9996 971 NULL, &colander_data, &iterator->colander);
c3ac0193 972 if (graph_status != BT_GRAPH_STATUS_OK) {
834e9996
PP
973 BT_LIB_LOGW("Cannot add colander sink component to graph: "
974 "%1[graph-]+g, status=%s", graph,
c3ac0193
PP
975 bt_graph_status_string(graph_status));
976 goto error;
977 }
978
979 /*
980 * Connect provided output port to the colander component's
981 * input port.
982 */
834e9996 983 colander_in_port = bt_component_sink_borrow_input_port_by_index(
c3ac0193 984 iterator->colander, 0);
8b45963b 985 BT_ASSERT(colander_in_port);
834e9996 986 graph_status = bt_private_graph_connect_ports(priv_graph,
c3ac0193
PP
987 output_port, colander_in_port, NULL);
988 if (graph_status != BT_GRAPH_STATUS_OK) {
834e9996
PP
989 BT_LIB_LOGW("Cannot add colander sink component to graph: "
990 "%![graph-]+g, %![comp-]+c, status=%s", graph,
991 iterator->colander,
c3ac0193
PP
992 bt_graph_status_string(graph_status));
993 goto error;
994 }
995
996 /*
997 * At this point everything went fine. Make the graph
998 * nonconsumable forever so that only this notification iterator
999 * can consume (thanks to bt_graph_consume_sink_no_check()).
1000 * This avoids leaking the notification created by the colander
94a96686
PP
1001 * sink and moved to the notification iterator's notification
1002 * member.
c3ac0193 1003 */
834e9996 1004 bt_graph_set_can_consume(iterator->graph, false);
c3ac0193
PP
1005 goto end;
1006
1007error:
1008 if (iterator && iterator->graph && iterator->colander) {
1009 int ret;
1010
1011 /* Remove created colander component from graph if any */
1012 colander_comp = iterator->colander;
8138bfe1 1013 BT_OBJECT_PUT_REF_AND_RESET(iterator->colander);
c3ac0193
PP
1014
1015 /*
1016 * At this point the colander component's reference
1017 * count is 0 because iterator->colander was the only
1018 * owner. We also know that it is not connected because
1019 * this is the last operation before this function
1020 * succeeds.
1021 *
1022 * Since we honor the preconditions here,
1023 * bt_graph_remove_unconnected_component() always
1024 * succeeds.
1025 */
1026 ret = bt_graph_remove_unconnected_component(iterator->graph,
834e9996 1027 (void *) colander_comp);
8b45963b 1028 BT_ASSERT(ret == 0);
c3ac0193
PP
1029 }
1030
8138bfe1 1031 BT_OBJECT_PUT_REF_AND_RESET(iterator);
c3ac0193
PP
1032
1033end:
8138bfe1 1034 bt_object_put_ref(colander_comp_cls);
c3ac0193
PP
1035 return (void *) iterator;
1036}
This page took 0.09566 seconds and 4 git commands to generate.