* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#define _GNU_SOURCE
#define _LGPL_SOURCE
#include <assert.h>
#include <stdio.h>
output->enabled = 1;
output->type = type;
output->net_seq_index = (uint64_t) -1ULL;
+ urcu_ref_init(&output->ref);
output->socks = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
*
* Should *NOT* be called with RCU read-side lock held.
*/
-void consumer_destroy_output(struct consumer_output *obj)
+static void consumer_release_output(struct urcu_ref *ref)
{
- if (obj == NULL) {
- return;
- }
+ struct consumer_output *obj =
+ caa_container_of(ref, struct consumer_output, ref);
consumer_destroy_output_sockets(obj);
free(obj);
}
+/*
+ * Get the consumer_output object.
+ */
+void consumer_output_get(struct consumer_output *obj)
+{
+ urcu_ref_get(&obj->ref);
+}
+
+/*
+ * Put the consumer_output object.
+ *
+ * Should *NOT* be called with RCU read-side lock held.
+ */
+void consumer_output_put(struct consumer_output *obj)
+{
+ if (!obj) {
+ return;
+ }
+ urcu_ref_put(&obj->ref, consumer_release_output);
+}
+
/*
* Copy consumer output and returned the newly allocated copy.
*
struct consumer_output *consumer_copy_output(struct consumer_output *obj)
{
int ret;
- struct lttng_ht *tmp_ht_ptr;
struct consumer_output *output;
assert(obj);
output = consumer_create_output(obj->type);
if (output == NULL) {
- goto error;
+ goto end;
}
- /* Avoid losing the HT reference after the memcpy() */
- tmp_ht_ptr = output->socks;
-
- memcpy(output, obj, sizeof(struct consumer_output));
-
- /* Putting back the HT pointer and start copying socket(s). */
- output->socks = tmp_ht_ptr;
-
+ output->enabled = obj->enabled;
+ output->net_seq_index = obj->net_seq_index;
+ memcpy(output->subdir, obj->subdir, PATH_MAX);
+ output->snapshot = obj->snapshot;
+ output->relay_major_version = obj->relay_major_version;
+ output->relay_minor_version = obj->relay_minor_version;
+ memcpy(&output->dst, &obj->dst, sizeof(output->dst));
ret = consumer_copy_sockets(output, obj);
if (ret < 0) {
- goto malloc_error;
+ goto error_put;
}
-
-error:
+end:
return output;
-malloc_error:
- consumer_destroy_output(output);
+error_put:
+ consumer_output_put(output);
return NULL;
}
uint64_t tracefile_count,
uint64_t session_id_per_pid,
unsigned int monitor,
- uint32_t ust_app_uid)
+ uint32_t ust_app_uid,
+ const char *root_shm_path,
+ const char *shm_path)
{
assert(msg);
strncpy(msg->u.ask_channel.name, name, sizeof(msg->u.ask_channel.name));
msg->u.ask_channel.name[sizeof(msg->u.ask_channel.name) - 1] = '\0';
+
+ if (root_shm_path) {
+ strncpy(msg->u.ask_channel.root_shm_path, root_shm_path,
+ sizeof(msg->u.ask_channel.root_shm_path));
+ msg->u.ask_channel.root_shm_path[sizeof(msg->u.ask_channel.root_shm_path) - 1] = '\0';
+ }
+ if (shm_path) {
+ strncpy(msg->u.ask_channel.shm_path, shm_path,
+ sizeof(msg->u.ask_channel.shm_path));
+ msg->u.ask_channel.shm_path[sizeof(msg->u.ask_channel.shm_path) - 1] = '\0';
+ }
}
/*
}
/*
- * Ask the consumer if the data is ready to read (NOT pending) for the specific
- * session id.
- *
- * This function has a different behavior with the consumer i.e. that it waits
- * for a reply from the consumer if yes or no the data is pending.
+ * Ask the consumer if the data is pending for the specific session id.
+ * Returns 1 if data is pending, 0 otherwise, or < 0 on error.
*/
int consumer_is_data_pending(uint64_t session_id,
struct consumer_output *consumer)
ret = run_as_mkdir_recursive(msg.u.snapshot_channel.pathname,
S_IRWXU | S_IRWXG, uid, gid);
if (ret < 0) {
- if (ret != -EEXIST) {
+ if (errno != EEXIST) {
ERR("Trace directory creation error");
goto error;
}
health_code_update();
return ret;
}
+
+/*
+ * Ask the consumer the number of discarded events for a channel.
+ */
+int consumer_get_discarded_events(uint64_t session_id, uint64_t channel_key,
+ struct consumer_output *consumer, uint64_t *discarded)
+{
+ int ret;
+ struct consumer_socket *socket;
+ struct lttng_ht_iter iter;
+ struct lttcomm_consumer_msg msg;
+
+ assert(consumer);
+
+ DBG3("Consumer discarded events id %" PRIu64, session_id);
+
+ memset(&msg, 0, sizeof(msg));
+ msg.cmd_type = LTTNG_CONSUMER_DISCARDED_EVENTS;
+ msg.u.discarded_events.session_id = session_id;
+ msg.u.discarded_events.channel_key = channel_key;
+
+ *discarded = 0;
+
+ /* Send command for each consumer */
+ rcu_read_lock();
+ cds_lfht_for_each_entry(consumer->socks->ht, &iter.iter, socket,
+ node.node) {
+ uint64_t consumer_discarded = 0;
+ pthread_mutex_lock(socket->lock);
+ ret = consumer_socket_send(socket, &msg, sizeof(msg));
+ if (ret < 0) {
+ pthread_mutex_unlock(socket->lock);
+ goto end;
+ }
+
+ /*
+ * No need for a recv reply status because the answer to the
+ * command is the reply status message.
+ */
+ ret = consumer_socket_recv(socket, &consumer_discarded,
+ sizeof(consumer_discarded));
+ if (ret < 0) {
+ ERR("get discarded events");
+ pthread_mutex_unlock(socket->lock);
+ goto end;
+ }
+ pthread_mutex_unlock(socket->lock);
+ *discarded += consumer_discarded;
+ }
+ ret = 0;
+ DBG("Consumer discarded %" PRIu64 " events in session id %" PRIu64,
+ *discarded, session_id);
+
+end:
+ rcu_read_unlock();
+ return ret;
+}
+
+/*
+ * Ask the consumer the number of lost packets for a channel.
+ */
+int consumer_get_lost_packets(uint64_t session_id, uint64_t channel_key,
+ struct consumer_output *consumer, uint64_t *lost)
+{
+ int ret;
+ struct consumer_socket *socket;
+ struct lttng_ht_iter iter;
+ struct lttcomm_consumer_msg msg;
+
+ assert(consumer);
+
+ DBG3("Consumer lost packets id %" PRIu64, session_id);
+
+ memset(&msg, 0, sizeof(msg));
+ msg.cmd_type = LTTNG_CONSUMER_LOST_PACKETS;
+ msg.u.lost_packets.session_id = session_id;
+ msg.u.lost_packets.channel_key = channel_key;
+
+ *lost = 0;
+
+ /* Send command for each consumer */
+ rcu_read_lock();
+ cds_lfht_for_each_entry(consumer->socks->ht, &iter.iter, socket,
+ node.node) {
+ uint64_t consumer_lost = 0;
+ pthread_mutex_lock(socket->lock);
+ ret = consumer_socket_send(socket, &msg, sizeof(msg));
+ if (ret < 0) {
+ pthread_mutex_unlock(socket->lock);
+ goto end;
+ }
+
+ /*
+ * No need for a recv reply status because the answer to the
+ * command is the reply status message.
+ */
+ ret = consumer_socket_recv(socket, &consumer_lost,
+ sizeof(consumer_lost));
+ if (ret < 0) {
+ ERR("get lost packets");
+ pthread_mutex_unlock(socket->lock);
+ goto end;
+ }
+ pthread_mutex_unlock(socket->lock);
+ *lost += consumer_lost;
+ }
+ ret = 0;
+ DBG("Consumer lost %" PRIu64 " packets in session id %" PRIu64,
+ *lost, session_id);
+
+end:
+ rcu_read_unlock();
+ return ret;
+}