+ /*
+ * Visit all the packet context fields, followed by all the
+ * fields of all the events, in order, updating our current
+ * clock value as we visit.
+ *
+ * While visiting the packet context fields, do not consider
+ * `timestamp_begin` and `timestamp_end` because this function's
+ * purpose is to set them anyway. Also do not consider
+ * `packet_size`, `content_size`, `events_discarded`, and
+ * `packet_seq_num` if they are not set because those are
+ * autopopulating fields.
+ */
+ len = bt_field_type_structure_get_field_count(
+ stream->packet_context->type);
+ BT_ASSERT(len >= 0);
+
+ for (i = 0; i < len; i++) {
+ const char *member_name;
+ struct bt_field *member_field;
+
+ ret = bt_field_type_structure_get_field_by_index(
+ stream->packet_context->type, &member_name, NULL, i);
+ BT_ASSERT(ret == 0);
+
+ if (strcmp(member_name, "timestamp_begin") == 0 ||
+ strcmp(member_name, "timestamp_end") == 0) {
+ continue;
+ }
+
+ member_field = bt_field_structure_get_field_by_index(
+ stream->packet_context, i);
+ BT_ASSERT(member_field);
+
+ if (strcmp(member_name, "packet_size") == 0 &&
+ !bt_field_is_set_recursive(member_field)) {
+ bt_put(member_field);
+ continue;
+ }
+
+ if (strcmp(member_name, "content_size") == 0 &&
+ !bt_field_is_set_recursive(member_field)) {
+ bt_put(member_field);
+ continue;
+ }
+
+ if (strcmp(member_name, "events_discarded") == 0 &&
+ !bt_field_is_set_recursive(member_field)) {
+ bt_put(member_field);
+ continue;
+ }
+
+ if (strcmp(member_name, "packet_seq_num") == 0 &&
+ !bt_field_is_set_recursive(member_field)) {
+ bt_put(member_field);
+ continue;
+ }
+
+ ret = visit_field_update_clock_value(member_field,
+ &cur_clock_value);
+ bt_put(member_field);
+ if (ret) {
+ BT_LOGW("Cannot automatically update clock value "
+ "in stream's packet context: "
+ "stream-addr=%p, stream-name=\"%s\", "
+ "field-name=\"%s\"",
+ stream, bt_stream_get_name(stream),
+ member_name);
+ goto end;
+ }
+ }
+
+ for (i = 0; i < stream->events->len; i++) {
+ struct bt_event *event = g_ptr_array_index(stream->events, i);
+
+ BT_ASSERT(event);
+ ret = visit_event_update_clock_value(event, &cur_clock_value);
+ if (ret) {
+ BT_LOGW("Cannot automatically update clock value "
+ "in stream's packet context: "
+ "stream-addr=%p, stream-name=\"%s\", "
+ "index=%" PRIu64 ", event-addr=%p, "
+ "event-class-id=%" PRId64 ", "
+ "event-class-name=\"%s\"",
+ stream, bt_stream_get_name(stream),
+ i, event,
+ bt_event_class_get_id(event->event_class),
+ bt_event_class_get_name(event->event_class));
+ goto end;
+ }
+ }
+
+ /*
+ * Everything is visited, thus the current clock value
+ * corresponds to the ending timestamp. Validate this value
+ * against the provided value of `timestamp_end`, if any,
+ * otherwise set it.
+ */
+ if (ts_end_field && bt_field_is_set_recursive(ts_end_field)) {
+ ret = bt_field_unsigned_integer_get_value(ts_end_field, &val);
+ BT_ASSERT(ret == 0);
+
+ if (val < cur_clock_value) {
+ BT_LOGW("Packet's final timestamp is less than "
+ "computed packet's final timestamp: "
+ "stream-addr=%p, stream-name=\"%s\", "
+ "cur-packet-ts-end=%" PRIu64 ", "
+ "computed-packet-ts-end=%" PRIu64,
+ stream, bt_stream_get_name(stream),
+ val, cur_clock_value);
+ ret = -1;
+ goto end;
+ }
+
+ stream->last_ts_end = val;
+ }
+
+ if (ts_end_field && !bt_field_is_set_recursive(ts_end_field)) {
+ ret = set_integer_field_value(ts_end_field, cur_clock_value);
+ BT_ASSERT(ret == 0);
+ stream->last_ts_end = cur_clock_value;
+ }
+
+ if (!ts_end_field) {
+ stream->last_ts_end = cur_clock_value;
+ }
+
+ /* Set `timestamp_begin` field to initial clock value */
+ if (ts_begin_field && !bt_field_is_set_recursive(ts_begin_field)) {
+ ret = set_integer_field_value(ts_begin_field, init_clock_value);
+ BT_ASSERT(ret == 0);
+ }