#include <urcu/list.h>
#include <signal.h>
+#include <bin/lttng-consumerd/health-consumerd.h>
#include <common/common.h>
#include <common/sessiond-comm/sessiond-comm.h>
#include <common/relayd/relayd.h>
#include <common/compat/fcntl.h>
+#include <common/compat/endian.h>
#include <common/consumer-metadata-cache.h>
#include <common/consumer-stream.h>
#include <common/consumer-timer.h>
cds_list_for_each_entry_safe(stream, stmp, &channel->streams.head,
send_node) {
+
+ health_code_update();
+
cds_list_del(&stream->send_node);
ustctl_destroy_stream(stream->ustream);
free(stream);
int wait_fd;
int ust_metadata_pipe[2];
+ health_code_update();
+
if (channel->type == CONSUMER_CHANNEL_TYPE_METADATA && channel->monitor) {
ret = utils_create_pipe_cloexec_nonblock(ust_metadata_pipe);
if (ret < 0) {
struct lttng_consumer_channel *channel,
struct lttng_consumer_local_data *ctx, int *relayd_error)
{
- int ret, ret_code = LTTNG_OK;
+ int ret, ret_code = LTTCOMM_CONSUMERD_SUCCESS;
struct lttng_consumer_stream *stream;
+ uint64_t net_seq_idx = -1ULL;
assert(channel);
assert(ctx);
if (channel->relayd_id != (uint64_t) -1ULL) {
cds_list_for_each_entry(stream, &channel->streams.head, send_node) {
+
+ health_code_update();
+
/* Try to send the stream to the relayd if one is available. */
ret = consumer_send_relayd_stream(stream, stream->chan->pathname);
if (ret < 0) {
}
ret_code = LTTNG_ERR_RELAYD_CONNECT_FAIL;
}
+ if (net_seq_idx == -1ULL) {
+ net_seq_idx = stream->net_seq_idx;
+ }
}
}
/* Inform sessiond that we are about to send channel and streams. */
ret = consumer_send_status_msg(sock, ret_code);
- if (ret < 0 || ret_code != LTTNG_OK) {
+ if (ret < 0 || ret_code != LTTCOMM_CONSUMERD_SUCCESS) {
/*
* Either the session daemon is not responding or the relayd died so we
* stop now.
/* The channel was sent successfully to the sessiond at this point. */
cds_list_for_each_entry(stream, &channel->streams.head, send_node) {
+
+ health_code_update();
+
/* Send stream to session daemon. */
ret = send_sessiond_stream(sock, stream);
if (ret < 0) {
return 0;
error:
- if (ret_code != LTTNG_OK) {
+ if (ret_code != LTTCOMM_CONSUMERD_SUCCESS) {
ret = -1;
}
return ret;
/* Send streams to the corresponding thread. */
cds_list_for_each_entry_safe(stream, stmp, &channel->streams.head,
send_node) {
+
+ health_code_update();
+
/* Sending the stream to the thread. */
ret = send_stream_to_thread(stream, ctx);
if (ret < 0) {
cds_lfht_for_each_entry_duplicate(ht->ht,
ht->hash_fct(&channel->key, lttng_ht_seed), ht->match_fct,
&channel->key, &iter.iter, stream, node_channel_id.node) {
+
+ health_code_update();
+
ustctl_flush_buffer(stream->ustream, 1);
}
error:
rcu_read_unlock();
return ret;
}
-/*
- * Close metadata stream wakeup_fd using the given key to retrieve the channel.
- * RCU read side lock MUST be acquired before calling this function.
- *
- * NOTE: This function does NOT take any channel nor stream lock.
- *
- * Return 0 on success else LTTng error code.
- */
-static int _close_metadata(struct lttng_consumer_channel *channel)
-{
- int ret = LTTNG_OK;
-
- assert(channel);
- assert(channel->type == CONSUMER_CHANNEL_TYPE_METADATA);
-
- if (channel->switch_timer_enabled == 1) {
- DBG("Deleting timer on metadata channel");
- consumer_timer_switch_stop(channel);
- }
-
- if (channel->metadata_stream) {
- ret = ustctl_stream_close_wakeup_fd(channel->metadata_stream->ustream);
- if (ret < 0) {
- ERR("UST consumer unable to close fd of metadata (ret: %d)", ret);
- ret = LTTCOMM_CONSUMERD_ERROR_METADATA;
- }
-
- if (channel->monitor) {
- /* Close the read-side in consumer_del_metadata_stream */
- ret = close(channel->metadata_stream->ust_metadata_poll_pipe[1]);
- if (ret < 0) {
- PERROR("Close UST metadata write-side poll pipe");
- ret = LTTCOMM_CONSUMERD_ERROR_METADATA;
- }
- }
- }
-
- return ret;
-}
/*
* Close metadata stream wakeup_fd using the given key to retrieve the channel.
goto error_unlock;
}
- ret = _close_metadata(channel);
+ lttng_ustconsumer_close_metadata(channel);
error_unlock:
pthread_mutex_unlock(&channel->lock);
ret = LTTCOMM_CONSUMERD_ERROR_METADATA;
goto error;
}
+ ret = consumer_send_relayd_streams_sent(
+ metadata->metadata_stream->net_seq_idx);
+ if (ret < 0) {
+ ret = LTTCOMM_CONSUMERD_RELAYD_FAIL;
+ goto error;
+ }
}
ret = send_streams_to_thread(metadata, ctx);
* the stream is still in the local stream list of the channel. This call
* will make sure to clean that list.
*/
- cds_list_del(&metadata->metadata_stream->send_node);
consumer_stream_destroy(metadata->metadata_stream, NULL);
+ cds_list_del(&metadata->metadata_stream->send_node);
+ metadata->metadata_stream = NULL;
error_no_stream:
end:
return ret;
}
assert(!metadata_channel->monitor);
+ health_code_update();
+
/*
* Ask the sessiond if we have new metadata waiting and update the
* consumer metadata cache.
goto error;
}
+ health_code_update();
+
/*
* The metadata stream is NOT created in no monitor mode when the channel
* is created on a sessiond ask channel command.
}
do {
+ health_code_update();
+
ret = lttng_consumer_read_subbuffer(metadata_stream, ctx);
if (ret < 0) {
goto error_stream;
* Clean up the stream completly because the next snapshot will use a new
* metadata stream.
*/
- cds_list_del(&metadata_stream->send_node);
consumer_stream_destroy(metadata_stream, NULL);
+ cds_list_del(&metadata_stream->send_node);
metadata_channel->metadata_stream = NULL;
error:
DBG("UST consumer snapshot channel %" PRIu64, key);
cds_list_for_each_entry(stream, &channel->streams.head, send_node) {
+
+ health_code_update();
+
/* Lock stream because we are about to change its state. */
pthread_mutex_lock(&stream->lock);
stream->net_seq_idx = relayd_id;
DBG("UST consumer snapshot stream %s/%s (%" PRIu64 ")", path,
stream->name, stream->key);
}
+ if (relayd_id != -1ULL) {
+ ret = consumer_send_relayd_streams_sent(relayd_id);
+ if (ret < 0) {
+ goto error_unlock;
+ }
+ }
ustctl_flush_buffer(stream->ustream, 1);
ssize_t read_len;
unsigned long len, padded_len;
+ health_code_update();
+
DBG("UST consumer taking snapshot at pos %lu", consumed_pos);
ret = ustctl_get_subbuf(stream->ustream, &consumed_pos);
uint64_t len, struct lttng_consumer_channel *channel,
int timer, int wait)
{
- int ret, ret_code = LTTNG_OK;
+ int ret, ret_code = LTTCOMM_CONSUMERD_SUCCESS;
char *metadata_str;
DBG("UST consumer push metadata key %" PRIu64 " of len %" PRIu64, key, len);
goto end;
}
+ health_code_update();
+
/* Receive metadata string. */
ret = lttcomm_recv_unix_sock(sock, metadata_str, len);
if (ret < 0) {
goto end_free;
}
+ health_code_update();
+
pthread_mutex_lock(&channel->metadata_cache->lock);
ret = consumer_metadata_cache_write(channel, offset, len, metadata_str);
if (ret < 0) {
}
while (consumer_metadata_cache_flushed(channel, offset + len, timer)) {
DBG("Waiting for metadata to be flushed");
+
+ health_code_update();
+
usleep(DEFAULT_METADATA_AVAILABILITY_WAIT_TIME);
}
int sock, struct pollfd *consumer_sockpoll)
{
ssize_t ret;
- enum lttng_error_code ret_code = LTTNG_OK;
+ enum lttcomm_return_code ret_code = LTTCOMM_CONSUMERD_SUCCESS;
struct lttcomm_consumer_msg msg;
struct lttng_consumer_channel *channel = NULL;
+ health_code_update();
+
ret = lttcomm_recv_unix_sock(sock, &msg, sizeof(msg));
if (ret != sizeof(msg)) {
DBG("Consumer received unexpected message size %zd (expects %zu)",
}
return ret;
}
- if (msg.cmd_type == LTTNG_CONSUMER_STOP) {
- /*
- * Notify the session daemon that the command is completed.
- *
- * On transport layer error, the function call will print an error
- * message so handling the returned code is a bit useless since we
- * return an error code anyway.
- */
- (void) consumer_send_status_msg(sock, ret_code);
- return -ENOENT;
- }
+
+ health_code_update();
+
+ /* deprecated */
+ assert(msg.cmd_type != LTTNG_CONSUMER_STOP);
+
+ health_code_update();
/* relayd needs RCU read-side lock */
rcu_read_lock();
attr.switch_timer_interval = msg.u.ask_channel.switch_timer_interval;
attr.read_timer_interval = msg.u.ask_channel.read_timer_interval;
attr.chan_id = msg.u.ask_channel.chan_id;
- attr.output = msg.u.ask_channel.output;
memcpy(attr.uuid, msg.u.ask_channel.uuid, sizeof(attr.uuid));
+ /* Match channel buffer type to the UST abi. */
+ switch (msg.u.ask_channel.output) {
+ case LTTNG_EVENT_MMAP:
+ default:
+ attr.output = LTTNG_UST_MMAP;
+ break;
+ }
+
/* Translate and save channel type. */
switch (msg.u.ask_channel.type) {
case LTTNG_UST_CHAN_PER_CPU:
goto error_fatal;
};
+ health_code_update();
+
ret = ask_channel(ctx, sock, channel, &attr);
if (ret < 0) {
goto end_channel_error;
msg.u.ask_channel.live_timer_interval);
}
+ health_code_update();
+
/*
* Add the channel to the internal state AFTER all streams were created
* and successfully sent to session daemon. This way, all streams must
goto end_channel_error;
}
+ health_code_update();
+
/*
* Channel and streams are now created. Inform the session daemon that
* everything went well and should wait to receive the channel and
goto end_msg_sessiond;
}
+ health_code_update();
+
/* Send everything to sessiond. */
ret = send_sessiond_channel(sock, channel, ctx, &relayd_err);
if (ret < 0) {
goto error_fatal;
}
+ health_code_update();
+
/*
* In no monitor mode, the streams ownership is kept inside the channel
* so don't send them to the data thread.
channel = consumer_find_channel(key);
if (!channel) {
- ERR("UST consumer push metadata %" PRIu64 " not found", key);
- ret_code = LTTNG_ERR_UST_CHAN_NOT_FOUND;
+ /*
+ * This is possible if the metadata creation on the consumer side
+ * is in flight vis-a-vis a concurrent push metadata from the
+ * session daemon. Simply return that the channel failed and the
+ * session daemon will handle that message correctly considering
+ * that this race is acceptable thus the DBG() statement here.
+ */
+ DBG("UST consumer push metadata %" PRIu64 " not found", key);
+ ret_code = LTTCOMM_CONSUMERD_CHANNEL_FAIL;
goto end_msg_sessiond;
}
+ health_code_update();
+
/* Tell session daemon we are ready to receive the metadata. */
- ret = consumer_send_status_msg(sock, LTTNG_OK);
+ ret = consumer_send_status_msg(sock, LTTCOMM_CONSUMERD_SUCCESS);
if (ret < 0) {
/* Somehow, the session daemon is not responding anymore. */
goto error_fatal;
}
+ health_code_update();
+
/* Wait for more data. */
- if (lttng_consumer_poll_socket(consumer_sockpoll) < 0) {
+ health_poll_entry();
+ ret = lttng_consumer_poll_socket(consumer_sockpoll);
+ health_poll_exit();
+ if (ret) {
goto error_fatal;
}
+ health_code_update();
+
ret = lttng_ustconsumer_recv_metadata(sock, key, offset,
len, channel, 0, 1);
if (ret < 0) {
}
}
+ health_code_update();
ret = consumer_send_status_msg(sock, ret_code);
if (ret < 0) {
/* Somehow, the session daemon is not responding anymore. */
goto end_nosignal;
}
+ health_code_update();
break;
}
default:
end_nosignal:
rcu_read_unlock();
+ health_code_update();
+
/*
* Return 1 to indicate success since the 0 value can be a socket
* shutdown during the recv() or send() call.
goto error_fatal;
}
rcu_read_unlock();
+
+ health_code_update();
+
return 1;
end_channel_error:
if (channel) {
goto error_fatal;
}
rcu_read_unlock();
+
+ health_code_update();
+
return 1;
error_fatal:
rcu_read_unlock();
ustctl_destroy_stream(stream->ustream);
}
+int lttng_ustconsumer_get_wakeup_fd(struct lttng_consumer_stream *stream)
+{
+ assert(stream);
+ assert(stream->ustream);
+
+ return ustctl_stream_get_wakeup_fd(stream->ustream);
+}
+
+int lttng_ustconsumer_close_wakeup_fd(struct lttng_consumer_stream *stream)
+{
+ assert(stream);
+ assert(stream->ustream);
+
+ return ustctl_stream_close_wakeup_fd(stream->ustream);
+}
+
/*
* Populate index values of a UST stream. Values are set in big endian order.
*
* Return 0 on success or else a negative value.
*/
-static int get_index_values(struct lttng_packet_index *index,
+static int get_index_values(struct ctf_packet_index *index,
struct ustctl_consumer_stream *ustream)
{
int ret;
return ret;
}
+/*
+ * Return 0 on success else a negative value.
+ */
+static int notify_if_more_data(struct lttng_consumer_stream *stream,
+ struct lttng_consumer_local_data *ctx)
+{
+ int ret;
+ struct ustctl_consumer_stream *ustream;
+
+ assert(stream);
+ assert(ctx);
+
+ ustream = stream->ustream;
+
+ /*
+ * First, we are going to check if there is a new subbuffer available
+ * before reading the stream wait_fd.
+ */
+ /* Get the next subbuffer */
+ ret = ustctl_get_next_subbuf(ustream);
+ if (ret) {
+ /* No more data found, flag the stream. */
+ stream->has_data = 0;
+ ret = 0;
+ goto end;
+ }
+
+ ret = ustctl_put_next_subbuf(ustream);
+ assert(!ret);
+
+ /* This stream still has data. Flag it and wake up the data thread. */
+ stream->has_data = 1;
+
+ if (stream->monitor && !stream->hangup_flush_done && !ctx->has_wakeup) {
+ ssize_t writelen;
+
+ writelen = lttng_pipe_write(ctx->consumer_wakeup_pipe, "!", 1);
+ if (writelen < 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
+ ret = writelen;
+ goto end;
+ }
+
+ /* The wake up pipe has been notified. */
+ ctx->has_wakeup = 1;
+ }
+ ret = 0;
+
+end:
+ return ret;
+}
+
/*
* Read subbuffer from the given stream.
*
unsigned long len, subbuf_size, padding;
int err, write_index = 1;
long ret = 0;
- char dummy;
struct ustctl_consumer_stream *ustream;
- struct lttng_packet_index index;
+ struct ctf_packet_index index;
assert(stream);
assert(stream->ustream);
/* Ease our life for what's next. */
ustream = stream->ustream;
- /* We can consume the 1 byte written into the wait_fd by UST */
- if (stream->monitor && !stream->hangup_flush_done) {
+ /*
+ * We can consume the 1 byte written into the wait_fd by UST. Don't trigger
+ * error if we cannot read this one byte (read returns 0), or if the error
+ * is EAGAIN or EWOULDBLOCK.
+ *
+ * This is only done when the stream is monitored by a thread, before the
+ * flush is done after a hangup and if the stream is not flagged with data
+ * since there might be nothing to consume in the wait fd but still have
+ * data available flagged by the consumer wake up pipe.
+ */
+ if (stream->monitor && !stream->hangup_flush_done && !stream->has_data) {
+ char dummy;
ssize_t readlen;
- do {
- readlen = read(stream->wait_fd, &dummy, 1);
- } while (readlen == -1 && errno == EINTR);
- if (readlen == -1 && errno != EAGAIN && errno != EWOULDBLOCK) {
+ readlen = lttng_read(stream->wait_fd, &dummy, 1);
+ if (readlen < 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
ret = readlen;
goto end;
}
err = ustctl_put_next_subbuf(ustream);
assert(err == 0);
+ /*
+ * This will consumer the byte on the wait_fd if and only if there is not
+ * next subbuffer to be acquired.
+ */
+ if (!stream->metadata_flag) {
+ ret = notify_if_more_data(stream, ctx);
+ if (ret < 0) {
+ goto end;
+ }
+ }
+
/* Write index if needed. */
if (!write_index) {
goto end;
return ret;
}
+/*
+ * Stop a given metadata channel timer if enabled and close the wait fd which
+ * is the poll pipe of the metadata stream.
+ *
+ * This MUST be called with the metadata channel acquired.
+ */
+void lttng_ustconsumer_close_metadata(struct lttng_consumer_channel *metadata)
+{
+ int ret;
+
+ assert(metadata);
+ assert(metadata->type == CONSUMER_CHANNEL_TYPE_METADATA);
+
+ DBG("Closing metadata channel key %" PRIu64, metadata->key);
+
+ if (metadata->switch_timer_enabled == 1) {
+ consumer_timer_switch_stop(metadata);
+ }
+
+ if (!metadata->metadata_stream) {
+ goto end;
+ }
+
+ /*
+ * Closing write side so the thread monitoring the stream wakes up if any
+ * and clean the metadata stream.
+ */
+ if (metadata->metadata_stream->ust_metadata_poll_pipe[1] >= 0) {
+ ret = close(metadata->metadata_stream->ust_metadata_poll_pipe[1]);
+ if (ret < 0) {
+ PERROR("closing metadata pipe write side");
+ }
+ metadata->metadata_stream->ust_metadata_poll_pipe[1] = -1;
+ }
+
+end:
+ return;
+}
+
/*
* Close every metadata stream wait fd of the metadata hash table. This
* function MUST be used very carefully so not to run into a race between the
* producer so calling this is safe because we are assured that no state change
* can occur in the metadata thread for the streams in the hash table.
*/
-void lttng_ustconsumer_close_metadata(struct lttng_ht *metadata_ht)
+void lttng_ustconsumer_close_all_metadata(struct lttng_ht *metadata_ht)
{
struct lttng_ht_iter iter;
struct lttng_consumer_stream *stream;
rcu_read_lock();
cds_lfht_for_each_entry(metadata_ht->ht, &iter.iter, stream,
node.node) {
+
+ health_code_update();
+
pthread_mutex_lock(&stream->chan->lock);
- /*
- * Whatever returned value, we must continue to try to close everything
- * so ignore it.
- */
- (void) _close_metadata(stream->chan);
- DBG("Metadata wait fd %d and poll pipe fd %d closed", stream->wait_fd,
- stream->ust_metadata_poll_pipe[1]);
+ lttng_ustconsumer_close_metadata(stream->chan);
pthread_mutex_unlock(&stream->chan->lock);
}
{
struct lttcomm_metadata_request_msg request;
struct lttcomm_consumer_msg msg;
- enum lttng_error_code ret_code = LTTNG_OK;
+ enum lttcomm_return_code ret_code = LTTCOMM_CONSUMERD_SUCCESS;
uint64_t len, key, offset;
int ret;
assert(channel);
assert(channel->metadata_cache);
+ memset(&request, 0, sizeof(request));
+
/* send the metadata request to sessiond */
switch (consumer_data.type) {
case LTTNG_CONSUMER64_UST:
request.key);
pthread_mutex_lock(&ctx->metadata_socket_lock);
+
+ health_code_update();
+
ret = lttcomm_send_unix_sock(ctx->consumer_metadata_socket, &request,
sizeof(request));
if (ret < 0) {
goto end;
}
+ health_code_update();
+
/* Receive the metadata from sessiond */
ret = lttcomm_recv_unix_sock(ctx->consumer_metadata_socket, &msg,
sizeof(msg));
goto end;
}
+ health_code_update();
+
if (msg.cmd_type == LTTNG_ERR_UND) {
/* No registry found */
(void) consumer_send_status_msg(ctx->consumer_metadata_socket,
DBG("No new metadata to receive for key %" PRIu64, key);
}
+ health_code_update();
+
/* Tell session daemon we are ready to receive the metadata. */
ret = consumer_send_status_msg(ctx->consumer_metadata_socket,
- LTTNG_OK);
+ LTTCOMM_CONSUMERD_SUCCESS);
if (ret < 0 || len == 0) {
/*
* Somehow, the session daemon is not responding anymore or there is
goto end;
}
- ret_code = lttng_ustconsumer_recv_metadata(ctx->consumer_metadata_socket,
+ health_code_update();
+
+ ret = lttng_ustconsumer_recv_metadata(ctx->consumer_metadata_socket,
key, offset, len, channel, timer, wait);
- if (ret_code >= 0) {
+ if (ret >= 0) {
/*
* Only send the status msg if the sessiond is alive meaning a positive
* ret code.
*/
- (void) consumer_send_status_msg(ctx->consumer_metadata_socket, ret_code);
+ (void) consumer_send_status_msg(ctx->consumer_metadata_socket, ret);
}
ret = 0;
end:
+ health_code_update();
+
pthread_mutex_unlock(&ctx->metadata_socket_lock);
return ret;
}