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