X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=lib%2Fctf-ir%2Fpacket.c;h=d3fce47af34e1a872c653609ce9114f5aa5d7cc8;hb=7b33a0e0d8f23d90285ea7c7820a725bcbd96c6b;hp=9ec77deac18fbec382496ee2600dcbe4d4b358ee;hpb=be514b0cc5125839619739b796190951ba45bb22;p=babeltrace.git diff --git a/lib/ctf-ir/packet.c b/lib/ctf-ir/packet.c index 9ec77dea..d3fce47a 100644 --- a/lib/ctf-ir/packet.c +++ b/lib/ctf-ir/packet.c @@ -27,263 +27,462 @@ #define BT_LOG_TAG "PACKET" #include +#include #include #include #include +#include #include #include #include #include #include +#include #include #include #include +#include #include -struct bt_ctf_stream *bt_ctf_packet_get_stream(struct bt_ctf_packet *packet) +#define BT_ASSERT_PRE_PACKET_HOT(_packet) \ + BT_ASSERT_PRE_HOT((_packet), "Packet", ": %!+a", (_packet)) + +struct bt_stream *bt_packet_borrow_stream(struct bt_packet *packet) { - return packet ? bt_get(packet->stream) : NULL; + BT_ASSERT_PRE_NON_NULL(packet, "Packet"); + return packet->stream; } -struct bt_ctf_field *bt_ctf_packet_get_header( - struct bt_ctf_packet *packet) +struct bt_field *bt_packet_borrow_header_field(struct bt_packet *packet) { - return packet ? bt_get(packet->header) : NULL; + BT_ASSERT_PRE_NON_NULL(packet, "Packet"); + return packet->header_field ? packet->header_field->field : NULL; } -int bt_ctf_packet_set_header(struct bt_ctf_packet *packet, - struct bt_ctf_field *header) +struct bt_field *bt_packet_borrow_context_field(struct bt_packet *packet) { - int ret = 0; - struct bt_ctf_trace *trace = NULL; - struct bt_ctf_stream_class *stream_class = NULL; - struct bt_ctf_field_type *header_field_type = NULL; - struct bt_ctf_field_type *expected_header_field_type = NULL; + BT_ASSERT_PRE_NON_NULL(packet, "Packet"); + return packet->context_field ? packet->context_field->field : NULL; +} +BT_HIDDEN +void _bt_packet_set_is_frozen(struct bt_packet *packet, bool is_frozen) +{ if (!packet) { - BT_LOGW_STR("Invalid parameter: packet is NULL."); - ret = -1; - goto end; - } - - if (packet->frozen) { - BT_LOGW("Invalid parameter: packet is frozen: addr=%p", - packet); - ret = -1; - goto end; + return; } - stream_class = bt_ctf_stream_get_class(packet->stream); - assert(stream_class); - trace = bt_ctf_stream_class_get_trace(stream_class); - assert(trace); - expected_header_field_type = bt_ctf_trace_get_packet_header_type(trace); - - if (!header) { - if (expected_header_field_type) { - BT_LOGW("Invalid parameter: setting no packet header but packet header field type is not NULL: " - "packet-addr=%p, packet-header-ft-addr=%p", - packet, expected_header_field_type); - ret = -1; - goto end; - } + BT_LIB_LOGD("Setting packet's frozen state: %![packet-]+a, " + "is-frozen=%d", packet, is_frozen); - goto skip_validation; + if (packet->header_field) { + BT_LOGD_STR("Setting packet's header field's frozen state."); + bt_field_set_is_frozen(packet->header_field->field, + is_frozen); } - header_field_type = bt_ctf_field_get_type(header); - assert(header_field_type); - - if (bt_ctf_field_type_compare(header_field_type, - expected_header_field_type)) { - BT_LOGW("Invalid parameter: packet header's field type is different from the trace's packet header field type: " - "packet-addr=%p, packet-header-addr=%p", - packet, header); - ret = -1; - goto end; + if (packet->context_field) { + BT_LOGD_STR("Setting packet's context field's frozen state."); + bt_field_set_is_frozen(packet->context_field->field, + is_frozen); } -skip_validation: - bt_put(packet->header); - packet->header = bt_get(header); - BT_LOGV("Set packet's header field: packet-addr=%p, packet-header-addr=%p", - packet, header); - -end: - BT_PUT(trace); - BT_PUT(stream_class); - BT_PUT(header_field_type); - BT_PUT(expected_header_field_type); - - return ret; + packet->frozen = is_frozen; } -struct bt_ctf_field *bt_ctf_packet_get_context( - struct bt_ctf_packet *packet) +static inline +void reset_counter_snapshots(struct bt_packet *packet) { - return packet ? bt_get(packet->context) : NULL; + packet->discarded_event_counter_snapshot.base.avail = + BT_PROPERTY_AVAILABILITY_NOT_AVAILABLE; + packet->packet_counter_snapshot.base.avail = + BT_PROPERTY_AVAILABILITY_NOT_AVAILABLE; } -int bt_ctf_packet_set_context(struct bt_ctf_packet *packet, - struct bt_ctf_field *context) +static inline +void reset_packet(struct bt_packet *packet) { - int ret = 0; - struct bt_ctf_stream_class *stream_class = NULL; - struct bt_ctf_field_type *context_field_type = NULL; - struct bt_ctf_field_type *expected_context_field_type = NULL; + BT_ASSERT(packet); + BT_LIB_LOGD("Resetting packet: %!+a", packet); + bt_packet_set_is_frozen(packet, false); - if (!packet) { - BT_LOGW_STR("Invalid parameter: packet is NULL."); - ret = -1; - goto end; + if (packet->header_field) { + bt_field_set_is_frozen(packet->header_field->field, false); + bt_field_reset(packet->header_field->field); } - if (packet->frozen) { - BT_LOGW("Invalid parameter: packet is frozen: addr=%p", - packet); - ret = -1; - goto end; + if (packet->context_field) { + bt_field_set_is_frozen(packet->context_field->field, false); + bt_field_reset(packet->context_field->field); } - stream_class = bt_ctf_stream_get_class(packet->stream); - assert(stream_class); - expected_context_field_type = - bt_ctf_stream_class_get_packet_context_type(stream_class); - - if (!context) { - if (expected_context_field_type) { - BT_LOGW("Invalid parameter: setting no packet context but packet context field type is not NULL: " - "packet-addr=%p, packet-context-ft-addr=%p", - packet, expected_context_field_type); - ret = -1; - goto end; - } - - goto skip_validation; + if (packet->default_beginning_cv) { + bt_clock_value_reset(packet->default_beginning_cv); } - context_field_type = bt_ctf_field_get_type(context); - assert(context_field_type); - - if (bt_ctf_field_type_compare(context_field_type, - expected_context_field_type)) { - BT_LOGW("Invalid parameter: packet context's field type is different from the stream class's packet context field type: " - "packet-addr=%p, packet-context-addr=%p", - packet, context); - ret = -1; - goto end; + if (packet->default_end_cv) { + bt_clock_value_reset(packet->default_end_cv); } -skip_validation: - bt_put(packet->context); - packet->context = bt_get(context); - BT_LOGV("Set packet's context field: packet-addr=%p, packet-context-addr=%p", - packet, context); - -end: - BT_PUT(stream_class); - BT_PUT(context_field_type); - BT_PUT(expected_context_field_type); - return ret; + reset_counter_snapshots(packet); } -BT_HIDDEN -void bt_ctf_packet_freeze(struct bt_ctf_packet *packet) +static +void recycle_header_field(struct bt_field_wrapper *header_field, + struct bt_trace *trace) { - if (!packet || packet->frozen) { - return; - } - - BT_LOGD("Freezing packet: addr=%p", packet); - BT_LOGD_STR("Freezing packet's header field."); - bt_ctf_field_freeze(packet->header); - BT_LOGD_STR("Freezing packet's context field."); - bt_ctf_field_freeze(packet->context); - packet->frozen = 1; + BT_ASSERT(header_field); + BT_LIB_LOGD("Recycling packet header field: " + "addr=%p, %![trace-]+t, %![field-]+f", header_field, + trace, header_field->field); + bt_object_pool_recycle_object(&trace->packet_header_field_pool, + header_field); } static -void bt_ctf_packet_destroy(struct bt_object *obj) +void recycle_context_field(struct bt_field_wrapper *context_field, + struct bt_stream_class *stream_class) { - struct bt_ctf_packet *packet; - - packet = container_of(obj, struct bt_ctf_packet, base); - BT_LOGD("Destroying packet: addr=%p", packet); - BT_LOGD_STR("Putting packet's header field."); - bt_put(packet->header); - BT_LOGD_STR("Putting packet's context field."); - bt_put(packet->context); - BT_LOGD_STR("Putting packet's stream."); - bt_put(packet->stream); - g_free(packet); + BT_ASSERT(context_field); + BT_LIB_LOGD("Recycling packet context field: " + "addr=%p, %![sc-]+S, %![field-]+f", context_field, + stream_class, context_field->field); + bt_object_pool_recycle_object(&stream_class->packet_context_field_pool, + context_field); } -struct bt_ctf_packet *bt_ctf_packet_create( - struct bt_ctf_stream *stream) +BT_HIDDEN +void bt_packet_recycle(struct bt_packet *packet) { - struct bt_ctf_packet *packet = NULL; - struct bt_ctf_stream_class *stream_class = NULL; - struct bt_ctf_trace *trace = NULL; + struct bt_stream *stream; + + BT_ASSERT(packet); + BT_LIB_LOGD("Recycling packet: %!+a", packet); + + /* + * Those are the important ordered steps: + * + * 1. Reset the packet object (put any permanent reference it + * has, unfreeze it and its fields in developer mode, etc.), + * but do NOT put its stream's reference. This stream + * contains the pool to which we're about to recycle this + * packet object, so we must guarantee its existence thanks + * to this existing reference. + * + * 2. Move the stream reference to our `stream` + * variable so that we can set the packet's stream member + * to NULL before recycling it. We CANNOT do this after + * we put the stream reference because this bt_put() + * could destroy the stream, also destroying its + * packet pool, thus also destroying our packet object (this + * would result in an invalid write access). + * + * 3. Recycle the packet object. + * + * 4. Put our stream reference. + */ + reset_packet(packet); + stream = packet->stream; + BT_ASSERT(stream); + packet->stream = NULL; + bt_object_pool_recycle_object(&stream->packet_pool, packet); + bt_object_put_no_null_check(&stream->base); +} - if (!stream) { - BT_LOGW_STR("Invalid parameter: stream is NULL."); - goto end; +BT_HIDDEN +void bt_packet_destroy(struct bt_packet *packet) +{ + BT_LIB_LOGD("Destroying packet: %!+a", packet); + + if (packet->header_field) { + if (packet->stream) { + BT_LOGD_STR("Recycling packet's header field."); + recycle_header_field(packet->header_field, + bt_stream_class_borrow_trace_inline( + packet->stream->class)); + } else { + bt_field_wrapper_destroy(packet->header_field); + } + } + + if (packet->context_field) { + if (packet->stream) { + BT_LOGD_STR("Recycling packet's context field."); + recycle_context_field(packet->context_field, + packet->stream->class); + } else { + bt_field_wrapper_destroy(packet->context_field); + } } - BT_LOGD("Creating packet object: stream-addr=%p, " - "stream-name=\"%s\", stream-class-addr=%p, " - "stream-class-name=\"%s\", stream-class-id=%" PRId64, - stream, bt_ctf_stream_get_name(stream), - stream->stream_class, - bt_ctf_stream_class_get_name(stream->stream_class), - bt_ctf_stream_class_get_id(stream->stream_class)); + if (packet->default_beginning_cv) { + BT_LOGD_STR("Recycling beginning clock value."); + bt_clock_value_recycle(packet->default_beginning_cv); + } - if (stream->pos.fd >= 0) { - BT_LOGW_STR("Invalid parameter: stream is a CTF writer stream."); - goto end; + if (packet->default_end_cv) { + BT_LOGD_STR("Recycling end clock value."); + bt_clock_value_recycle(packet->default_end_cv); } - stream_class = bt_ctf_stream_get_class(stream); - assert(stream_class); - trace = bt_ctf_stream_class_get_trace(stream_class); - assert(trace); - packet = g_new0(struct bt_ctf_packet, 1); + BT_LOGD_STR("Putting packet's stream."); + bt_put(packet->stream); + g_free(packet); +} + +BT_HIDDEN +struct bt_packet *bt_packet_new(struct bt_stream *stream) +{ + struct bt_packet *packet = NULL; + struct bt_trace *trace = NULL; + + BT_ASSERT(stream); + BT_LIB_LOGD("Creating packet object: %![stream-]+s", stream); + packet = g_new0(struct bt_packet, 1); if (!packet) { BT_LOGE_STR("Failed to allocate one packet object."); - goto end; + goto error; } - bt_object_init(packet, bt_ctf_packet_destroy); + bt_object_init_shared(&packet->base, + (bt_object_release_func) bt_packet_recycle); packet->stream = bt_get(stream); + trace = bt_stream_class_borrow_trace_inline(stream->class); + BT_ASSERT(trace); + + if (trace->packet_header_ft) { + BT_LOGD_STR("Creating initial packet header field."); + packet->header_field = bt_field_wrapper_create( + &trace->packet_header_field_pool, + trace->packet_header_ft); + if (!packet->header_field) { + BT_LOGE_STR("Cannot create packet header field wrapper."); + goto error; + } + } - if (trace->packet_header_type) { - BT_LOGD("Creating initial packet header field: ft-addr=%p", - trace->packet_header_type); - packet->header = bt_ctf_field_create(trace->packet_header_type); - if (!packet->header) { - BT_LOGE_STR("Cannot create initial packet header field object."); - BT_PUT(packet); - goto end; + if (stream->class->packet_context_ft) { + BT_LOGD_STR("Creating initial packet context field."); + packet->context_field = bt_field_wrapper_create( + &stream->class->packet_context_field_pool, + stream->class->packet_context_ft); + if (!packet->context_field) { + BT_LOGE_STR("Cannot create packet context field wrapper."); + goto error; } } - if (stream->stream_class->packet_context_type) { - BT_LOGD("Creating initial packet context field: ft-addr=%p", - stream->stream_class->packet_context_type); - packet->context = bt_ctf_field_create( - stream->stream_class->packet_context_type); - if (!packet->context) { - BT_LOGE_STR("Cannot create initial packet header field object."); - BT_PUT(packet); - goto end; + if (stream->class->default_clock_class) { + if (stream->class->packets_have_default_beginning_cv) { + packet->default_beginning_cv = bt_clock_value_create( + stream->class->default_clock_class); + if (!packet->default_beginning_cv) { + /* bt_clock_value_create() logs errors */ + goto error; + } + } + + if (stream->class->packets_have_default_end_cv) { + packet->default_end_cv = bt_clock_value_create( + stream->class->default_clock_class); + if (!packet->default_end_cv) { + /* bt_clock_value_create() logs errors */ + goto error; + } } } - BT_LOGD("Created packet object: addr=%p", packet); + reset_counter_snapshots(packet); + BT_LIB_LOGD("Created packet object: %!+a", packet); + goto end; + +error: + BT_PUT(packet); end: - BT_PUT(trace); - BT_PUT(stream_class); + return packet; +} + +struct bt_packet *bt_packet_create(struct bt_stream *stream) +{ + struct bt_packet *packet = NULL; + BT_ASSERT_PRE_NON_NULL(stream, "Stream"); + packet = bt_object_pool_create_object(&stream->packet_pool); + if (unlikely(!packet)) { + BT_LIB_LOGE("Cannot allocate one packet from stream's packet pool: " + "%![stream-]+s", stream); + goto end; + } + + if (likely(!packet->stream)) { + packet->stream = stream; + bt_object_get_no_null_check_no_parent_check( + &packet->stream->base); + } + +end: return packet; } + +int bt_packet_move_header_field(struct bt_packet *packet, + struct bt_packet_header_field *header_field) +{ + struct bt_trace *trace; + struct bt_field_wrapper *field_wrapper = (void *) header_field; + + BT_ASSERT_PRE_NON_NULL(packet, "Packet"); + BT_ASSERT_PRE_NON_NULL(field_wrapper, "Header field"); + BT_ASSERT_PRE_PACKET_HOT(packet); + trace = bt_stream_class_borrow_trace_inline(packet->stream->class); + BT_ASSERT_PRE(trace->packet_header_ft, + "Trace has no packet header field type: %!+t", + trace); + BT_ASSERT_PRE(field_wrapper->field->type == + trace->packet_header_ft, + "Unexpected packet header field's type: " + "%![ft-]+F, %![expected-ft-]+F", field_wrapper->field->type, + trace->packet_header_ft); + + /* Recycle current header field: always exists */ + BT_ASSERT(packet->header_field); + recycle_header_field(packet->header_field, trace); + + /* Move new field */ + packet->header_field = field_wrapper; + return 0; +} + +int bt_packet_move_context_field(struct bt_packet *packet, + struct bt_packet_context_field *context_field) +{ + struct bt_stream_class *stream_class; + struct bt_field_wrapper *field_wrapper = (void *) context_field; + + BT_ASSERT_PRE_NON_NULL(packet, "Packet"); + BT_ASSERT_PRE_NON_NULL(field_wrapper, "Context field"); + BT_ASSERT_PRE_HOT(packet, "Packet", ": %!+a", packet); + stream_class = packet->stream->class; + BT_ASSERT_PRE(stream_class->packet_context_ft, + "Stream class has no packet context field type: %!+S", + stream_class); + BT_ASSERT_PRE(field_wrapper->field->type == + stream_class->packet_context_ft, + "Unexpected packet header field's type: " + "%![ft-]+F, %![expected-ft-]+F", field_wrapper->field->type, + stream_class->packet_context_ft); + + /* Recycle current context field: always exists */ + BT_ASSERT(packet->context_field); + recycle_context_field(packet->context_field, stream_class); + + /* Move new field */ + packet->context_field = field_wrapper; + return 0; +} + +int bt_packet_set_default_beginning_clock_value(struct bt_packet *packet, + uint64_t value_cycles) +{ + struct bt_stream_class *sc; + + BT_ASSERT_PRE_NON_NULL(packet, "Packet"); + BT_ASSERT_PRE_PACKET_HOT(packet); + sc = packet->stream->class; + BT_ASSERT(sc); + BT_ASSERT_PRE(sc->default_clock_class, + "Packet's stream class has no default clock class: " + "%![packet-]+a, %![sc-]+S", packet, sc); + BT_ASSERT_PRE(sc->packets_have_default_beginning_cv, + "Packet's stream class indicates that its packets have " + "no default beginning clock value: %![packet-]+a, %![sc-]+S", + packet, sc); + BT_ASSERT(packet->default_beginning_cv); + bt_clock_value_set_value_inline(packet->default_beginning_cv, value_cycles); + BT_LIB_LOGV("Set packet's default beginning clock value: " + "%![packet-]+a, value=%" PRIu64, value_cycles); + return 0; +} + +enum bt_clock_value_status bt_packet_borrow_default_beginning_clock_value( + struct bt_packet *packet, struct bt_clock_value **clock_value) +{ + BT_ASSERT_PRE_NON_NULL(packet, "Packet"); + BT_ASSERT_PRE_NON_NULL(clock_value, "Clock value (output)"); + *clock_value = packet->default_beginning_cv; + return BT_CLOCK_VALUE_STATUS_KNOWN; +} + +int bt_packet_set_default_end_clock_value(struct bt_packet *packet, + uint64_t value_cycles) +{ + struct bt_stream_class *sc; + + BT_ASSERT_PRE_NON_NULL(packet, "Packet"); + BT_ASSERT_PRE_PACKET_HOT(packet); + sc = packet->stream->class; + BT_ASSERT(sc); + BT_ASSERT_PRE(sc->default_clock_class, + "Packet's stream class has no default clock class: " + "%![packet-]+a, %![sc-]+S", packet, sc); + BT_ASSERT_PRE(sc->packets_have_default_end_cv, + "Packet's stream class indicates that its packets have " + "no default end clock value: %![packet-]+a, %![sc-]+S", + packet, sc); + BT_ASSERT(packet->default_end_cv); + bt_clock_value_set_value_inline(packet->default_end_cv, value_cycles); + BT_LIB_LOGV("Set packet's default end clock value: " + "%![packet-]+a, value=%" PRIu64, value_cycles); + return 0; +} + +enum bt_clock_value_status bt_packet_borrow_default_end_clock_value( + struct bt_packet *packet, struct bt_clock_value **clock_value) +{ + BT_ASSERT_PRE_NON_NULL(packet, "Packet"); + BT_ASSERT_PRE_NON_NULL(clock_value, "Clock value (output)"); + *clock_value = packet->default_end_cv; + return BT_CLOCK_VALUE_STATUS_KNOWN; +} + +enum bt_property_availability bt_packet_get_discarded_event_counter_snapshot( + struct bt_packet *packet, uint64_t *value) +{ + BT_ASSERT_PRE_NON_NULL(packet, "Packet"); + BT_ASSERT_PRE_NON_NULL(value, "Value (output)"); + *value = packet->discarded_event_counter_snapshot.value; + return packet->discarded_event_counter_snapshot.base.avail; +} + +int bt_packet_set_discarded_event_counter_snapshot(struct bt_packet *packet, + uint64_t value) +{ + BT_ASSERT_PRE_NON_NULL(packet, "Packet"); + BT_ASSERT_PRE_PACKET_HOT(packet); + BT_ASSERT_PRE(packet->stream->class->packets_have_discarded_event_counter_snapshot, + "Packet's stream's discarded event counter is not enabled: " + "%![packet-]+a", packet); + bt_property_uint_set(&packet->discarded_event_counter_snapshot, value); + return 0; +} + +enum bt_property_availability bt_packet_get_packet_counter_snapshot( + struct bt_packet *packet, uint64_t *value) +{ + BT_ASSERT_PRE_NON_NULL(packet, "Packet"); + BT_ASSERT_PRE_NON_NULL(value, "Value (output)"); + *value = packet->packet_counter_snapshot.value; + return packet->packet_counter_snapshot.base.avail; +} + +int bt_packet_set_packet_counter_snapshot(struct bt_packet *packet, + uint64_t value) +{ + BT_ASSERT_PRE_NON_NULL(packet, "Packet"); + BT_ASSERT_PRE_PACKET_HOT(packet); + BT_ASSERT_PRE(packet->stream->class->packets_have_packet_counter_snapshot, + "Packet's stream's packet counter is not enabled: " + "%![packet-]+a", packet); + bt_property_uint_set(&packet->packet_counter_snapshot, value); + return 0; +}