{
struct lttng_viewer_cmd cmd;
struct lttng_viewer_connect connect;
+ const size_t cmd_buf_len = sizeof(cmd) + sizeof(connect);
+ char cmd_buf[cmd_buf_len];
int ret;
ssize_t ret_len;
connect.minor = htobe32(LTTNG_LIVE_MINOR);
connect.type = htobe32(LTTNG_VIEWER_CLIENT_COMMAND);
- ret_len = lttng_live_send(ctx->control_sock, &cmd, sizeof(cmd));
- if (ret_len < 0) {
- perror("[error] Error sending cmd");
- goto error;
- }
- assert(ret_len == sizeof(cmd));
+ /*
+ * Merge the cmd and connection request to prevent a write-write
+ * sequence on the TCP socket. Otherwise, a delayed ACK will prevent the
+ * second write to be performed quickly in presence of Nagle's algorithm.
+ */
+ memcpy(cmd_buf, &cmd, sizeof(cmd));
+ memcpy(cmd_buf + sizeof(cmd), &connect, sizeof(connect));
- ret_len = lttng_live_send(ctx->control_sock, &connect, sizeof(connect));
+ ret_len = lttng_live_send(ctx->control_sock, cmd_buf, cmd_buf_len);
if (ret_len < 0) {
- perror("[error] Error sending version");
+ perror("[error] Error sending cmd for establishing session");
goto error;
}
- assert(ret_len == sizeof(connect));
+ assert(ret_len == cmd_buf_len);
ret_len = lttng_live_recv(ctx->control_sock, &connect, sizeof(connect));
if (ret_len == 0) {
if (!trace) {
trace = g_new0(struct lttng_live_ctf_trace, 1);
trace->ctf_trace_id = ctf_trace_id;
- trace->streams = g_ptr_array_new();
+ trace->trace_id = -1;
+ printf_verbose("Create trace ctf_trace_id %" PRIu64 "\n", ctf_trace_id);
+ BT_INIT_LIST_HEAD(&trace->stream_list);
g_hash_table_insert(stream->session->ctf_traces,
&trace->ctf_trace_id,
trace);
if (stream->metadata_flag)
trace->metadata_stream = stream;
+ assert(!stream->in_trace);
+ stream->in_trace = 1;
stream->ctf_trace = trace;
- g_ptr_array_add(trace->streams, stream);
+ bt_list_add(&stream->trace_stream_node, &trace->stream_list);
return ret;
}
struct lttng_viewer_attach_session_request rq;
struct lttng_viewer_attach_session_response rp;
struct lttng_viewer_stream stream;
+ const size_t cmd_buf_len = sizeof(cmd) + sizeof(rq);
+ char cmd_buf[cmd_buf_len];
int ret, i;
ssize_t ret_len;
// rq.seek = htobe32(LTTNG_VIEWER_SEEK_BEGINNING);
rq.seek = htobe32(LTTNG_VIEWER_SEEK_LAST);
- ret_len = lttng_live_send(ctx->control_sock, &cmd, sizeof(cmd));
- if (ret_len < 0) {
- perror("[error] Error sending cmd");
- goto error;
- }
- assert(ret_len == sizeof(cmd));
+ /*
+ * Merge the cmd and connection request to prevent a write-write
+ * sequence on the TCP socket. Otherwise, a delayed ACK will prevent the
+ * second write to be performed quickly in presence of Nagle's algorithm.
+ */
+ memcpy(cmd_buf, &cmd, sizeof(cmd));
+ memcpy(cmd_buf + sizeof(cmd), &rq, sizeof(rq));
- ret_len = lttng_live_send(ctx->control_sock, &rq, sizeof(rq));
+ ret_len = lttng_live_send(ctx->control_sock, cmd_buf, cmd_buf_len);
if (ret_len < 0) {
- perror("[error] Error sending attach request");
+ perror("[error] Error sending attach command and request");
goto error;
}
- assert(ret_len == sizeof(rq));
+ assert(ret_len == cmd_buf_len);
ret_len = lttng_live_recv(ctx->control_sock, &rp, sizeof(rp));
if (ret_len == 0) {
ret = 0;
goto end;
}
- printf_verbose("Waiting for %" PRIu64 " streams:\n",
- ctx->session->stream_count);
- ctx->session->streams = g_new0(struct lttng_live_viewer_stream,
- ctx->session->stream_count);
+ printf_verbose("Waiting for %d streams:\n",
+ be32toh(rp.streams_count));
for (i = 0; i < be32toh(rp.streams_count); i++) {
- ret_len = lttng_live_recv(ctx->control_sock, &stream, sizeof(stream));
+ struct lttng_live_viewer_stream *lvstream;
+
+ lvstream = g_new0(struct lttng_live_viewer_stream, 1);
+ ret_len = lttng_live_recv(ctx->control_sock, &stream,
+ sizeof(stream));
if (ret_len == 0) {
fprintf(stderr, "[error] Remote side has closed connection\n");
+ g_free(lvstream);
goto error;
}
if (ret_len < 0) {
perror("[error] Error receiving stream");
+ g_free(lvstream);
goto error;
}
assert(ret_len == sizeof(stream));
printf_verbose(" stream %" PRIu64 " : %s/%s\n",
be64toh(stream.id), stream.path_name,
stream.channel_name);
- ctx->session->streams[i].id = be64toh(stream.id);
- ctx->session->streams[i].session = ctx->session;
+ lvstream->id = be64toh(stream.id);
+ lvstream->session = ctx->session;
- ctx->session->streams[i].mmap_size = 0;
- ctx->session->streams[i].ctf_stream_id = -1ULL;
+ lvstream->mmap_size = 0;
+ lvstream->ctf_stream_id = -1ULL;
if (be32toh(stream.metadata_flag)) {
- ctx->session->streams[i].metadata_flag = 1;
+ lvstream->metadata_flag = 1;
}
- ret = lttng_live_ctf_trace_assign(&ctx->session->streams[i],
+ ret = lttng_live_ctf_trace_assign(lvstream,
be64toh(stream.ctf_trace_id));
if (ret < 0) {
+ g_free(lvstream);
goto error;
}
-
+ bt_list_add(&lvstream->session_stream_node,
+ &ctx->session->stream_list);
}
ret = 0;
end:
id = g_array_index(ctx->session_ids, uint64_t, i);
ret = lttng_live_get_new_streams(ctx, id);
printf_verbose("Asking for new streams returns %d\n", ret);
+ if (lttng_live_should_quit()) {
+ ret = -1;
+ goto end;
+ }
if (ret < 0) {
- if (lttng_live_should_quit()) {
- goto end;
- }
if (ret == -LTTNG_VIEWER_NEW_STREAMS_HUP) {
printf_verbose("Session %" PRIu64 " closed\n",
id);
nb_streams += ret;
}
}
- ret = nb_streams;
+ if (ctx->session_ids->len == 0) {
+ /* All sessions are closed. */
+ ret = -1;
+ } else {
+ ret = nb_streams;
+ }
end:
return ret;
struct lttng_live_viewer_stream *metadata;
char *metadata_buf = NULL;
+ if (!viewer_stream->ctf_trace->handle) {
+ printf_verbose("append_metadata: trace handle not ready yet.\n");
+ return 0;
+ }
+
printf_verbose("get_next_index: new metadata needed\n");
ret = get_new_metadata(ctx, viewer_stream, &metadata_buf);
if (ret < 0) {
struct lttng_viewer_cmd cmd;
struct lttng_viewer_get_packet rq;
struct lttng_viewer_trace_packet rp;
+ const size_t cmd_buf_len = sizeof(cmd) + sizeof(rq);
+ char cmd_buf[cmd_buf_len];
ssize_t ret_len;
int ret;
rq.offset = htobe64(offset);
rq.len = htobe32(len);
- ret_len = lttng_live_send(ctx->control_sock, &cmd, sizeof(cmd));
- if (ret_len < 0) {
- perror("[error] Error sending cmd");
- goto error;
- }
- assert(ret_len == sizeof(cmd));
+ /*
+ * Merge the cmd and connection request to prevent a write-write
+ * sequence on the TCP socket. Otherwise, a delayed ACK will prevent the
+ * second write to be performed quickly in presence of Nagle's algorithm.
+ */
+ memcpy(cmd_buf, &cmd, sizeof(cmd));
+ memcpy(cmd_buf + sizeof(cmd), &rq, sizeof(rq));
- ret_len = lttng_live_send(ctx->control_sock, &rq, sizeof(rq));
+ ret_len = lttng_live_send(ctx->control_sock, cmd_buf, cmd_buf_len);
if (ret_len < 0) {
- perror("[error] Error sending get_data_packet request");
+ perror("[error] Error sending get_data_packet cmd and request");
goto error;
}
- assert(ret_len == sizeof(rq));
+ assert(ret_len == cmd_buf_len);
ret_len = lttng_live_recv(ctx->control_sock, &rp, sizeof(rp));
if (ret_len == 0) {
struct lttng_viewer_metadata_packet rp;
char *data = NULL;
ssize_t ret_len;
+ const size_t cmd_buf_len = sizeof(cmd) + sizeof(rq);
+ char cmd_buf[cmd_buf_len];
if (lttng_live_should_quit()) {
ret = -1;
cmd.data_size = htobe64((uint64_t) sizeof(rq));
cmd.cmd_version = htobe32(0);
- ret_len = lttng_live_send(ctx->control_sock, &cmd, sizeof(cmd));
- if (ret_len < 0) {
- perror("[error] Error sending cmd");
- goto error;
- }
- assert(ret_len == sizeof(cmd));
+ /*
+ * Merge the cmd and connection request to prevent a write-write
+ * sequence on the TCP socket. Otherwise, a delayed ACK will prevent the
+ * second write to be performed quickly in presence of Nagle's algorithm.
+ */
+ memcpy(cmd_buf, &cmd, sizeof(cmd));
+ memcpy(cmd_buf + sizeof(cmd), &rq, sizeof(rq));
- ret_len = lttng_live_send(ctx->control_sock, &rq, sizeof(rq));
+ printf_verbose("get_metadata for trace_id: %d, ctf_trace_id: %" PRIu64 "\n",
+ metadata_stream->ctf_trace->trace_id,
+ metadata_stream->ctf_trace->ctf_trace_id);
+ ret_len = lttng_live_send(ctx->control_sock, cmd_buf, cmd_buf_len);
if (ret_len < 0) {
- perror("[error] Error sending get_metadata request");
+ perror("[error] Error sending get_metadata cmd and request");
goto error;
}
- assert(ret_len == sizeof(rq));
+ assert(ret_len == cmd_buf_len);
ret_len = lttng_live_recv(ctx->control_sock, &rp, sizeof(rp));
if (ret_len == 0) {
if (!len_read) {
(void) poll(NULL, 0, ACTIVE_POLL_DELAY);
}
+ if (ret < 0) {
+ break; /* Stop on error. */
+ }
} while (ret > 0 || !len_read);
if (babeltrace_close_memstream(metadata_buf, &size,
int ret;
ssize_t ret_len;
struct lttng_viewer_index *rp = &viewer_stream->current_index;
+ const size_t cmd_buf_len = sizeof(cmd) + sizeof(rq);
+ char cmd_buf[cmd_buf_len];
cmd.cmd = htobe32(LTTNG_VIEWER_GET_NEXT_INDEX);
cmd.data_size = htobe64((uint64_t) sizeof(rq));
memset(&rq, 0, sizeof(rq));
rq.stream_id = htobe64(viewer_stream->id);
+ /*
+ * Merge the cmd and connection request to prevent a write-write
+ * sequence on the TCP socket. Otherwise, a delayed ACK will prevent the
+ * second write to be performed quickly in presence of Nagle's algorithm.
+ */
+ memcpy(cmd_buf, &cmd, sizeof(cmd));
+ memcpy(cmd_buf + sizeof(cmd), &rq, sizeof(rq));
retry:
if (lttng_live_should_quit()) {
ret = -1;
goto end;
}
- ret_len = lttng_live_send(ctx->control_sock, &cmd, sizeof(cmd));
- if (ret_len < 0) {
- perror("[error] Error sending cmd");
- goto error;
- }
- assert(ret_len == sizeof(cmd));
-
- ret_len = lttng_live_send(ctx->control_sock, &rq, sizeof(rq));
+ ret_len = lttng_live_send(ctx->control_sock, &cmd_buf, cmd_buf_len);
if (ret_len < 0) {
- perror("[error] Error sending get_next_index request");
+ perror("[error] Error sending get_next_index cmd and request");
goto error;
}
- assert(ret_len == sizeof(rq));
+ assert(ret_len == cmd_buf_len);
ret_len = lttng_live_recv(ctx->control_sock, rp, sizeof(*rp));
if (ret_len == 0) {
switch (be32toh(rp->status)) {
case LTTNG_VIEWER_INDEX_INACTIVE:
printf_verbose("get_next_index: inactive\n");
+
+ if (index->ts_cycles.timestamp_end ==
+ be64toh(rp->timestamp_end)) {
+ /* Already seen this timestamp. */
+ (void) poll(NULL, 0, ACTIVE_POLL_DELAY);
+ }
+
memset(index, 0, sizeof(struct packet_index));
index->ts_cycles.timestamp_end = be64toh(rp->timestamp_end);
*stream_id = be64toh(rp->stream_id);
viewer_stream->id = -1ULL;
index->offset = EOF;
ctx->session->stream_count--;
+ viewer_stream->in_trace = 0;
+ bt_list_del(&viewer_stream->trace_stream_node);
+ bt_list_del(&viewer_stream->session_stream_node);
+ g_free(viewer_stream);
+ *stream_id = be64toh(rp->stream_id);
break;
case LTTNG_VIEWER_INDEX_ERR:
fprintf(stderr, "[error] get_next_index: error\n");
ret = handle_seek_position(index, whence, viewer_stream, pos,
file_stream);
if (ret != 0) {
- return;
+ ret = -BT_PACKET_SEEK_ERROR;
+ goto end;
}
retry:
if (!lttng_live_should_quit()) {
fprintf(stderr, "[error] get_next_index failed\n");
}
- return;
+ ret = -BT_PACKET_SEEK_ERROR;
+ goto end;
}
printf_verbose("Index received : packet_size : %" PRIu64
", offset %" PRIu64 ", content_size %" PRIu64
file_stream->parent.stream_id = stream_id;
viewer_stream->ctf_stream_id = stream_id;
- return;
+ ret = 0;
+ goto end;
}
pos->packet_size = cur_index->packet_size;
}
if (cur_index->content_size == 0) {
+ /* Beacon packet index */
if (file_stream->parent.stream_class) {
file_stream->parent.cycles_timestamp =
cur_index->ts_cycles.timestamp_end;
file_stream->parent.real_timestamp = ctf_get_real_timestamp(
&file_stream->parent,
cur_index->ts_cycles.timestamp_end);
+
+ /*
+ * Duplicate the data from the previous index, because
+ * the one we just received is only a beacon with no
+ * relevant information except the timestamp_end. We
+ * don't need to keep this timestamp_end because we already
+ * updated the file_stream timestamps, so we only need
+ * to keep the last real index data as prev_index. That
+ * way, we keep the original prev timestamps and
+ * discarded events counter. This is the same behaviour
+ * as if we were reading a local trace, we would not
+ * have fake indexes between real indexes.
+ */
+ memcpy(cur_index, prev_index, sizeof(struct packet_index));
}
} else {
+ /* Real packet index */
if (file_stream->parent.stream_class) {
/* Convert the timestamps and append to the real_index. */
cur_index->ts_real.timestamp_begin = ctf_get_real_timestamp(
ctf_update_current_packet_index(&file_stream->parent,
prev_index, cur_index);
+ /*
+ * We need to check if we are in trace read or called
+ * from packet indexing. In this last case, the
+ * collection is not there, so we cannot print the
+ * timestamps.
+ */
+ if ((&file_stream->parent)->stream_class->trace->parent.collection) {
+ ctf_print_discarded_lost(stderr, &file_stream->parent);
+ }
+
file_stream->parent.cycles_timestamp =
cur_index->ts_cycles.timestamp_begin;
file_stream->parent.real_timestamp =
pos->offset = EOF;
if (!lttng_live_should_quit()) {
fprintf(stderr, "[error] get_data_packet failed\n");
+ ret = -BT_PACKET_SEEK_ERROR;
+ } else {
+ ret = 0;
}
- return;
+ goto end;
}
viewer_stream->data_pending = 0;
read_packet_header(pos, file_stream);
-
+ ret = 0;
end:
- return;
+ bt_packet_seek_set_error(ret);
}
int lttng_live_create_viewer_session(struct lttng_live_ctx *ctx)
struct bt_context *bt_ctx = user_data;
struct lttng_live_ctf_trace *trace = value;
int ret;
+ struct lttng_live_viewer_stream *lvstream, *tmp;
- ret = bt_context_remove_trace(bt_ctx, trace->trace_id);
- if (ret < 0)
- fprintf(stderr, "[error] removing trace from context\n");
+ /*
+ * We don't have ownership of the live viewer stream, just
+ * remove them from our list.
+ */
+ bt_list_for_each_entry_safe(lvstream, tmp, &trace->stream_list,
+ trace_stream_node) {
+ lvstream->in_trace = 0;
+ bt_list_del(&lvstream->trace_stream_node);
+ }
+ if (trace->in_use && trace->trace_id >= 0) {
+ ret = bt_context_remove_trace(bt_ctx, trace->trace_id);
+ if (ret < 0)
+ fprintf(stderr, "[error] removing trace from context\n");
+ }
/* remove the key/value pair from the HT. */
return 1;
int add_one_trace(struct lttng_live_ctx *ctx,
struct lttng_live_ctf_trace *trace)
{
- int i, ret;
+ int ret;
struct bt_context *bt_ctx = ctx->bt_ctx;
struct lttng_live_viewer_stream *stream;
struct bt_mmap_stream *new_mmap_stream;
struct bt_trace_descriptor *td;
struct bt_trace_handle *handle;
+ printf_verbose("Add one trace ctf_trace_id: %" PRIu64
+ " (metadata_stream: %p)\n",
+ trace->ctf_trace_id, trace->metadata_stream);
/*
* We don't know how many streams we will receive for a trace, so
* once we are done receiving the traces, we add all the traces
* If a trace is already in the context, we just skip this function.
*/
if (trace->in_use) {
+ printf_verbose("Trace already in use\n");
ret = 0;
goto end;
}
+ /*
+ * add_one_trace can be called recursively if during the
+ * bt_context_add_trace call we need to fetch new streams, so we need to
+ * prevent a recursive call to process our current trace.
+ */
+ trace->in_use = 1;
BT_INIT_LIST_HEAD(&mmap_list.head);
- for (i = 0; i < trace->streams->len; i++) {
- stream = g_ptr_array_index(trace->streams, i);
-
+ bt_list_for_each_entry(stream, &trace->stream_list, trace_stream_node) {
if (!stream->metadata_flag) {
new_mmap_stream = zmalloc(sizeof(struct bt_mmap_stream));
new_mmap_stream->priv = (void *) stream;
goto end_free;
}
+ printf_verbose("Metadata stream found\n");
trace->metadata_fp = babeltrace_fmemopen(metadata_buf,
stream->metadata_len, "rb");
if (!trace->metadata_fp) {
}
trace->trace_id = ret;
- trace->in_use = 1;
+ printf_verbose("Trace now in use, id = %d\n", trace->trace_id);
goto end;
return ret;
}
+/*
+ * Make sure all the traces we know have a metadata stream or loop on
+ * ask_new_streams until it is done. This must be called before we call
+ * add_one_trace.
+ *
+ * Return 0 when all known traces have a metadata stream, a negative value
+ * on error.
+ */
+static
+int check_traces_metadata(struct lttng_live_ctx *ctx)
+{
+ int ret;
+ struct lttng_live_ctf_trace *trace;
+ GHashTableIter it;
+ gpointer key;
+ gpointer value;
+
+retry:
+ g_hash_table_iter_init(&it, ctx->session->ctf_traces);
+ while (g_hash_table_iter_next(&it, &key, &value)) {
+ trace = (struct lttng_live_ctf_trace *) value;
+ printf_verbose("Check trace %" PRIu64 " metadata\n", trace->ctf_trace_id);
+ while (!trace->metadata_stream) {
+ printf_verbose("Waiting for metadata stream\n");
+ if (lttng_live_should_quit()) {
+ ret = 0;
+ goto end;
+ }
+ ret = ask_new_streams(ctx);
+ if (ret < 0) {
+ goto end;
+ } else if (ret == 0) {
+ (void) poll(NULL, 0, ACTIVE_POLL_DELAY);
+ } else {
+ /*
+ * If ask_new_stream got streams from a trace we did not know
+ * about until now, we have to reinitialize the iterator.
+ */
+ goto retry;
+ }
+ }
+ }
+
+ ret = 0;
+
+end:
+ printf_verbose("End check traces metadata\n");
+ return ret;
+}
+
static
int add_traces(struct lttng_live_ctx *ctx)
{
GHashTableIter it;
gpointer key;
gpointer value;
+ unsigned int nr_traces;
+
+ printf_verbose("Begin add traces\n");
+
+retry:
+ nr_traces = g_hash_table_size(ctx->session->ctf_traces);
+
+ ret = check_traces_metadata(ctx);
+ if (ret < 0) {
+ goto end;
+ }
g_hash_table_iter_init(&it, ctx->session->ctf_traces);
while (g_hash_table_iter_next(&it, &key, &value)) {
if (ret < 0) {
goto end;
}
+ /*
+ * If a new trace got added while we were adding the trace, the
+ * iterator is invalid and we have to restart.
+ */
+ if (g_hash_table_size(ctx->session->ctf_traces) != nr_traces) {
+ printf_verbose("New trace(s) added during add_one_trace()\n");
+ goto retry;
+ }
}
ret = 0;
end:
+ printf_verbose("End add traces\n");
return ret;
}
int ret, i, nb_streams = 0;
ssize_t ret_len;
uint32_t stream_count;
+ const size_t cmd_buf_len = sizeof(cmd) + sizeof(rq);
+ char cmd_buf[cmd_buf_len];
if (lttng_live_should_quit()) {
ret = -1;
memset(&rq, 0, sizeof(rq));
rq.session_id = htobe64(id);
- ret_len = lttng_live_send(ctx->control_sock, &cmd, sizeof(cmd));
- if (ret_len < 0) {
- perror("[error] Error sending cmd");
- goto error;
- }
- assert(ret_len == sizeof(cmd));
+ /*
+ * Merge the cmd and connection request to prevent a write-write
+ * sequence on the TCP socket. Otherwise, a delayed ACK will prevent the
+ * second write to be performed quickly in presence of Nagle's algorithm.
+ */
+ memcpy(cmd_buf, &cmd, sizeof(cmd));
+ memcpy(cmd_buf + sizeof(cmd), &rq, sizeof(rq));
- ret_len = lttng_live_send(ctx->control_sock, &rq, sizeof(rq));
+ ret_len = lttng_live_send(ctx->control_sock, cmd_buf, cmd_buf_len);
if (ret_len < 0) {
- perror("[error] Error sending get_new_streams request");
+ perror("[error] Error sending get_new_streams cmd and request");
goto error;
}
- assert(ret_len == sizeof(rq));
+ assert(ret_len == cmd_buf_len);
ret_len = lttng_live_recv(ctx->control_sock, &rp, sizeof(rp));
if (ret_len == 0) {
ret = 0;
goto end;
}
- printf_verbose("Waiting for %" PRIu64 " streams:\n",
- ctx->session->stream_count);
- ctx->session->streams = g_new0(struct lttng_live_viewer_stream,
- ctx->session->stream_count);
+ printf_verbose("Waiting for %d streams:\n", stream_count);
+
for (i = 0; i < stream_count; i++) {
- ret_len = lttng_live_recv(ctx->control_sock, &stream, sizeof(stream));
+ struct lttng_live_viewer_stream *lvstream;
+
+ lvstream = g_new0(struct lttng_live_viewer_stream, 1);
+ ret_len = lttng_live_recv(ctx->control_sock, &stream,
+ sizeof(stream));
if (ret_len == 0) {
fprintf(stderr, "[error] Remote side has closed connection\n");
+ g_free(lvstream);
goto error;
}
if (ret_len < 0) {
perror("[error] Error receiving stream");
+ g_free(lvstream);
goto error;
}
assert(ret_len == sizeof(stream));
printf_verbose(" stream %" PRIu64 " : %s/%s\n",
be64toh(stream.id), stream.path_name,
stream.channel_name);
- ctx->session->streams[i].id = be64toh(stream.id);
- ctx->session->streams[i].session = ctx->session;
+ lvstream->id = be64toh(stream.id);
+ lvstream->session = ctx->session;
- ctx->session->streams[i].mmap_size = 0;
- ctx->session->streams[i].ctf_stream_id = -1ULL;
+ lvstream->mmap_size = 0;
+ lvstream->ctf_stream_id = -1ULL;
if (be32toh(stream.metadata_flag)) {
- ctx->session->streams[i].metadata_flag = 1;
+ lvstream->metadata_flag = 1;
}
- ret = lttng_live_ctf_trace_assign(&ctx->session->streams[i],
+ ret = lttng_live_ctf_trace_assign(lvstream,
be64toh(stream.ctf_trace_id));
if (ret < 0) {
+ g_free(lvstream);
goto error;
}
nb_streams++;
-
+ bt_list_add(&lvstream->session_stream_node,
+ &ctx->session->stream_list);
}
ret = nb_streams;
end:
fmt_write = bt_lookup_format(g_quark_from_static_string("text"));
if (!fmt_write) {
fprintf(stderr, "[error] ctf-text error\n");
- goto end;
+ goto end_free;
}
td_write = fmt_write->open_trace(NULL, O_RDWR, NULL, NULL);
}
ret = ask_new_streams(ctx);
if (ret < 0) {
+ ret = 0;
goto end_free;
}
if (!ctx->session->stream_count) {
if (!iter) {
if (lttng_live_should_quit()) {
ret = 0;
- goto end;
+ goto end_free;
}
fprintf(stderr, "[error] Iterator creation error\n");
- goto end;
+ goto end_free;
}
for (;;) {
if (lttng_live_should_quit()) {
}
end_free:
+ g_hash_table_foreach_remove(ctx->session->ctf_traces,
+ del_traces, ctx->bt_ctx);
bt_context_put(ctx->bt_ctx);
end:
if (lttng_live_should_quit()) {