#include <babeltrace/ctf-ir/stream.h>
#include <babeltrace/ctf-ir/stream-internal.h>
#include <babeltrace/ctf-ir/stream-class-internal.h>
+#include <babeltrace/ctf-ir/trace.h>
#include <babeltrace/ctf-ir/trace-internal.h>
#include <babeltrace/ctf-writer/writer-internal.h>
+#include <babeltrace/graph/component-internal.h>
#include <babeltrace/ref.h>
#include <babeltrace/ctf-writer/functor-internal.h>
-#include <babeltrace/compiler.h>
-#include <babeltrace/align.h>
+#include <babeltrace/compiler-internal.h>
+#include <babeltrace/align-internal.h>
#include <inttypes.h>
static
uuid_element, (int64_t) trace->uuid[i]);
} else {
ret = bt_ctf_field_unsigned_integer_set_value(
- uuid_element,
- (uint64_t) trace->uuid[i]);
+ uuid_element, (uint64_t) trace->uuid[i]);
}
bt_put(uuid_element);
if (ret) {
return ret;
}
+static
+void component_destroy_listener(struct bt_component *component, void *data)
+{
+ struct bt_ctf_stream *stream = data;
+
+ g_hash_table_remove(stream->comp_cur_port, component);
+}
+
struct bt_ctf_stream *bt_ctf_stream_create(
struct bt_ctf_stream_class *stream_class,
const char *name)
goto error;
}
+ if (bt_ctf_trace_is_static(trace)) {
+ /*
+ * A static trace has the property that all its stream
+ * classes, clock classes, and streams are definitive:
+ * no more can be added, and each object is also frozen.
+ */
+ goto error;
+ }
+
stream = g_new0(struct bt_ctf_stream, 1);
if (!stream) {
goto error;
stream->stream_class = stream_class;
stream->pos.fd = -1;
+ stream->destroy_listeners = g_array_new(FALSE, TRUE,
+ sizeof(struct bt_ctf_stream_destroy_listener));
+ if (!stream->destroy_listeners) {
+ goto error;
+ }
+
if (name) {
stream->name = g_string_new(name);
if (!stream->name) {
if (ret) {
goto error;
}
+
+ stream->comp_cur_port = g_hash_table_new(g_direct_hash,
+ g_direct_equal);
+ if (!stream->comp_cur_port) {
+ goto error;
+ }
}
/* Add this stream to the trace's streams */
}
new_count = previous_count + event_count;
+ assert(new_count >= previous_count);
if (field_signed) {
ret = bt_ctf_field_signed_integer_set_value(
events_discarded_field, (int64_t) new_count);
struct bt_ctf_stream_pos packet_context_pos;
struct bt_ctf_trace *trace;
enum bt_ctf_byte_order native_byte_order;
- bool empty_packet;
+ bt_bool empty_packet;
uint64_t packet_size_bits;
struct {
- bool timestamp_begin;
- bool timestamp_end;
- bool content_size;
- bool packet_size;
+ bt_bool timestamp_begin;
+ bt_bool timestamp_end;
+ bt_bool content_size;
+ bt_bool packet_size;
} auto_set_fields = { 0 };
if (!stream || stream->pos.fd < 0) {
trace = bt_ctf_stream_class_borrow_trace(stream->stream_class);
assert(trace);
- native_byte_order = bt_ctf_trace_get_byte_order(trace);
+ native_byte_order = bt_ctf_trace_get_native_byte_order(trace);
empty_packet = (stream->events->len == 0);
/* mmap the next packet */
void bt_ctf_stream_destroy(struct bt_object *obj)
{
struct bt_ctf_stream *stream;
+ int i;
stream = container_of(obj, struct bt_ctf_stream, base);
+
+ /* Call destroy listeners in reverse registration order */
+ for (i = stream->destroy_listeners->len - 1; i >= 0; i--) {
+ struct bt_ctf_stream_destroy_listener *listener =
+ &g_array_index(stream->destroy_listeners,
+ struct bt_ctf_stream_destroy_listener, i);
+
+ listener->func(stream, listener->data);
+ }
+
(void) bt_ctf_stream_pos_fini(&stream->pos);
if (stream->pos.fd >= 0) {
int ret;
g_string_free(stream->name, TRUE);
}
+ if (stream->comp_cur_port) {
+ GHashTableIter ht_iter;
+ gpointer comp_gptr, port_gptr;
+
+ /*
+ * Since we're destroying the stream, remove the destroy
+ * listeners that it registered for each component in
+ * its component-port mapping hash table. Otherwise they
+ * would be called and the stream would be accessed once
+ * it's freed or another stream would be accessed.
+ */
+ g_hash_table_iter_init(&ht_iter, stream->comp_cur_port);
+
+ while (g_hash_table_iter_next(&ht_iter, &comp_gptr, &port_gptr)) {
+ assert(comp_gptr);
+ bt_component_remove_destroy_listener((void *) comp_gptr,
+ component_destroy_listener, stream);
+ }
+
+ g_hash_table_destroy(stream->comp_cur_port);
+ }
+
+ if (stream->destroy_listeners) {
+ g_array_free(stream->destroy_listeners, TRUE);
+ }
+
bt_put(stream->packet_header);
bt_put(stream->packet_context);
g_free(stream);
static
int _set_structure_field_integer(struct bt_ctf_field *structure, char *name,
- uint64_t value, bool force)
+ uint64_t value, bt_bool force)
{
int ret = 0;
struct bt_ctf_field_type *field_type = NULL;
int set_structure_field_integer(struct bt_ctf_field *structure, char *name,
uint64_t value)
{
- return _set_structure_field_integer(structure, name, value, true);
+ return _set_structure_field_integer(structure, name, value, BT_TRUE);
}
/*
int try_set_structure_field_integer(struct bt_ctf_field *structure, char *name,
uint64_t value)
{
- return _set_structure_field_integer(structure, name, value, false);
+ return _set_structure_field_integer(structure, name, value, BT_FALSE);
}
const char *bt_ctf_stream_get_name(struct bt_ctf_stream *stream)
end:
return ret;
}
+
+BT_HIDDEN
+void bt_ctf_stream_map_component_to_port(struct bt_ctf_stream *stream,
+ struct bt_component *comp,
+ struct bt_port *port)
+{
+ assert(stream);
+ assert(comp);
+ assert(port);
+ assert(stream->comp_cur_port);
+
+ /*
+ * Do not take a reference to the component here because we
+ * don't want the component to exist as long as this stream
+ * exists. Instead, keep a weak reference, but add a destroy
+ * listener so that we remove this hash table entry when we know
+ * the component is destroyed.
+ */
+ bt_component_add_destroy_listener(comp, component_destroy_listener,
+ stream);
+ g_hash_table_insert(stream->comp_cur_port, comp, port);
+}
+
+BT_HIDDEN
+struct bt_port *bt_ctf_stream_port_for_component(struct bt_ctf_stream *stream,
+ struct bt_component *comp)
+{
+ assert(stream);
+ assert(comp);
+ assert(stream->comp_cur_port);
+ return g_hash_table_lookup(stream->comp_cur_port, comp);
+}
+
+BT_HIDDEN
+void bt_ctf_stream_add_destroy_listener(struct bt_ctf_stream *stream,
+ bt_ctf_stream_destroy_listener_func func, void *data)
+{
+ struct bt_ctf_stream_destroy_listener listener;
+
+ assert(stream);
+ assert(func);
+ listener.func = func;
+ listener.data = data;
+ g_array_append_val(stream->destroy_listeners, listener);
+}
+
+BT_HIDDEN
+void bt_ctf_stream_remove_destroy_listener(struct bt_ctf_stream *stream,
+ bt_ctf_stream_destroy_listener_func func, void *data)
+{
+ size_t i;
+
+ assert(stream);
+ assert(func);
+
+ for (i = 0; i < stream->destroy_listeners->len; i++) {
+ struct bt_ctf_stream_destroy_listener *listener =
+ &g_array_index(stream->destroy_listeners,
+ struct bt_ctf_stream_destroy_listener, i);
+
+ if (listener->func == func && listener->data == data) {
+ g_array_remove_index(stream->destroy_listeners, i);
+ i--;
+ }
+ }
+}