UST periodical metadata flush
[lttng-tools.git] / src / bin / lttng-sessiond / ust-app.c
index 9250433ab1573b4d3534caf677e0bf817fe0c658..fdcad1c304ab0c717fb3f619b812de6d17433b31 100644 (file)
@@ -27,6 +27,7 @@
 #include <unistd.h>
 #include <urcu/compiler.h>
 #include <lttng/ust-error.h>
+#include <signal.h>
 
 #include <common/common.h>
 #include <common/sessiond-comm/sessiond-comm.h>
@@ -58,6 +59,19 @@ static inline unsigned long get_next_session_id(void)
        return uatomic_add_return(&next_session_id, 1);
 }
 
+static void copy_channel_attr_to_ustctl(
+               struct ustctl_consumer_channel_attr *attr,
+               struct lttng_ust_channel_attr *uattr)
+{
+       /* Copy event attributes since the layout is different. */
+       attr->subbuf_size = uattr->subbuf_size;
+       attr->num_subbuf = uattr->num_subbuf;
+       attr->overwrite = uattr->overwrite;
+       attr->switch_timer_interval = uattr->switch_timer_interval;
+       attr->read_timer_interval = uattr->read_timer_interval;
+       attr->output = uattr->output;
+}
+
 /*
  * Match function for the hash table lookup.
  *
@@ -354,18 +368,84 @@ void delete_ust_app_channel(int sock, struct ust_app_channel *ua_chan,
        free(ua_chan);
 }
 
+/*
+ * Push metadata to consumer socket. The socket lock MUST be acquired.
+ *
+ * On success, return the len of metadata pushed or else a negative value.
+ */
+ssize_t ust_app_push_metadata(struct ust_registry_session *registry,
+               struct consumer_socket *socket, int send_zero_data)
+{
+       int ret;
+       char *metadata_str = NULL;
+       size_t len, offset;
+       ssize_t ret_val;
+
+       assert(registry);
+       assert(socket);
+       /* Should never be 0 which is the initial state. */
+       assert(registry->metadata_key);
+
+       pthread_mutex_lock(&registry->lock);
+
+       offset = registry->metadata_len_sent;
+       len = registry->metadata_len - registry->metadata_len_sent;
+       if (len == 0) {
+               DBG3("No metadata to push for metadata key %" PRIu64,
+                               registry->metadata_key);
+               ret_val = len;
+               if (send_zero_data) {
+                       DBG("No metadata to push");
+                       goto push_data;
+               }
+               goto end;
+       }
+
+       /* Allocate only what we have to send. */
+       metadata_str = zmalloc(len);
+       if (!metadata_str) {
+               PERROR("zmalloc ust app metadata string");
+               ret_val = -ENOMEM;
+               goto error;
+       }
+       /* Copy what we haven't send out. */
+       memcpy(metadata_str, registry->metadata + offset, len);
+       registry->metadata_len_sent += len;
+
+push_data:
+       pthread_mutex_unlock(&registry->lock);
+       ret = consumer_push_metadata(socket, registry->metadata_key,
+                       metadata_str, len, offset);
+       if (ret < 0) {
+               ret_val = ret;
+               goto error_push;
+       }
+
+       free(metadata_str);
+       return len;
+
+end:
+error:
+       pthread_mutex_unlock(&registry->lock);
+error_push:
+       free(metadata_str);
+       return ret_val;
+}
+
 /*
  * For a given application and session, push metadata to consumer. The session
  * lock MUST be acquired here before calling this.
+ * Either sock or consumer is required : if sock is NULL, the default
+ * socket to send the metadata is retrieved from consumer, if sock
+ * is not NULL we use it to send the metadata.
  *
  * Return 0 on success else a negative error.
  */
 static int push_metadata(struct ust_registry_session *registry,
                struct consumer_output *consumer)
 {
-       int ret;
-       char *metadata_str = NULL;
-       size_t len, offset;
+       int ret_val;
+       ssize_t ret;
        struct consumer_socket *socket;
 
        assert(registry);
@@ -378,7 +458,7 @@ static int push_metadata(struct ust_registry_session *registry,
         * no start has been done previously.
         */
        if (!registry->metadata_key) {
-               ret = 0;
+               ret_val = 0;
                goto error_rcu_unlock;
        }
 
@@ -386,7 +466,7 @@ static int push_metadata(struct ust_registry_session *registry,
        socket = consumer_find_socket_by_bitness(registry->bits_per_long,
                        consumer);
        if (!socket) {
-               ret = -1;
+               ret_val = -1;
                goto error_rcu_unlock;
        }
 
@@ -401,54 +481,19 @@ static int push_metadata(struct ust_registry_session *registry,
         * ability to reorder the metadata it receives.
         */
        pthread_mutex_lock(socket->lock);
-       pthread_mutex_lock(&registry->lock);
-
-       offset = registry->metadata_len_sent;
-       len = registry->metadata_len - registry->metadata_len_sent;
-       if (len == 0) {
-               DBG3("No metadata to push for metadata key %" PRIu64,
-                               registry->metadata_key);
-               ret = 0;
-               goto error_reg_unlock;
-       }
-       assert(len > 0);
-
-       /* Allocate only what we have to send. */
-       metadata_str = zmalloc(len);
-       if (!metadata_str) {
-               PERROR("zmalloc ust app metadata string");
-               ret = -ENOMEM;
-               goto error_reg_unlock;
-       }
-       /* Copy what we haven't send out. */
-       memcpy(metadata_str, registry->metadata + offset, len);
-
-       pthread_mutex_unlock(&registry->lock);
-
-       ret = consumer_push_metadata(socket, registry->metadata_key,
-                       metadata_str, len, offset);
+       ret = ust_app_push_metadata(registry, socket, 0);
+       pthread_mutex_unlock(socket->lock);
        if (ret < 0) {
-               pthread_mutex_unlock(socket->lock);
+               ret_val = ret;
                goto error_rcu_unlock;
        }
 
-       /* Update len sent of the registry. */
-       pthread_mutex_lock(&registry->lock);
-       registry->metadata_len_sent += len;
-       pthread_mutex_unlock(&registry->lock);
-       pthread_mutex_unlock(socket->lock);
-
        rcu_read_unlock();
-       free(metadata_str);
        return 0;
 
-error_reg_unlock:
-       pthread_mutex_unlock(&registry->lock);
-       pthread_mutex_unlock(socket->lock);
 error_rcu_unlock:
        rcu_read_unlock();
-       free(metadata_str);
-       return ret;
+       return ret_val;
 }
 
 /*
@@ -2410,7 +2455,8 @@ error:
  * Called with UST app session lock held and RCU read side lock.
  */
 static int create_ust_app_metadata(struct ust_app_session *ua_sess,
-               struct ust_app *app, struct consumer_output *consumer)
+               struct ust_app *app, struct consumer_output *consumer,
+               struct ustctl_consumer_channel_attr *attr)
 {
        int ret = 0;
        struct ust_app_channel *metadata;
@@ -2438,14 +2484,20 @@ static int create_ust_app_metadata(struct ust_app_session *ua_sess,
                goto error;
        }
 
-       /* Set default attributes for metadata. */
-       metadata->attr.overwrite = DEFAULT_CHANNEL_OVERWRITE;
-       metadata->attr.subbuf_size = default_get_metadata_subbuf_size();
-       metadata->attr.num_subbuf = DEFAULT_METADATA_SUBBUF_NUM;
-       metadata->attr.switch_timer_interval = DEFAULT_UST_CHANNEL_SWITCH_TIMER;
-       metadata->attr.read_timer_interval = DEFAULT_UST_CHANNEL_READ_TIMER;
-       metadata->attr.output = LTTNG_UST_MMAP;
-       metadata->attr.type = LTTNG_UST_CHAN_METADATA;
+       if (!attr) {
+               /* Set default attributes for metadata. */
+               metadata->attr.overwrite = DEFAULT_CHANNEL_OVERWRITE;
+               metadata->attr.subbuf_size = default_get_metadata_subbuf_size();
+               metadata->attr.num_subbuf = DEFAULT_METADATA_SUBBUF_NUM;
+               metadata->attr.switch_timer_interval = DEFAULT_UST_CHANNEL_SWITCH_TIMER;
+               metadata->attr.read_timer_interval = DEFAULT_UST_CHANNEL_READ_TIMER;
+               metadata->attr.output = LTTNG_UST_MMAP;
+               metadata->attr.type = LTTNG_UST_CHAN_METADATA;
+       } else {
+               memcpy(&metadata->attr, attr, sizeof(metadata->attr));
+               metadata->attr.output = LTTNG_UST_MMAP;
+               metadata->attr.type = LTTNG_UST_CHAN_METADATA;
+       }
 
        /* Get the right consumer socket for the application. */
        socket = consumer_find_socket_by_bitness(app->bits_per_long, consumer);
@@ -2461,6 +2513,14 @@ static int create_ust_app_metadata(struct ust_app_session *ua_sess,
                goto error;
        }
 
+       /*
+        * Keep metadata key so we can identify it on the consumer side. Assign it
+        * to the registry *before* we ask the consumer so we avoid the race of the
+        * consumer requesting the metadata and the ask_channel call on our side
+        * did not returned yet.
+        */
+       registry->metadata_key = metadata->key;
+
        /*
         * Ask the metadata channel creation to the consumer. The metadata object
         * will be created by the consumer and kept their. However, the stream is
@@ -2494,9 +2554,6 @@ static int create_ust_app_metadata(struct ust_app_session *ua_sess,
                goto error_consumer;
        }
 
-       /* Keep metadata key so we can identify it on the consumer side. */
-       registry->metadata_key = metadata->key;
-
        DBG2("UST metadata with key %" PRIu64 " created for app pid %d",
                        metadata->key, app->pid);
 
@@ -3320,9 +3377,17 @@ int ust_app_create_channel_glb(struct ltt_ust_session *usess,
                assert(ua_sess);
 
                pthread_mutex_lock(&ua_sess->lock);
-               /* Create channel onto application. We don't need the chan ref. */
-               ret = create_ust_app_channel(ua_sess, uchan, app,
-                               LTTNG_UST_CHAN_PER_CPU, usess, NULL);
+               if (!strncmp(uchan->name, DEFAULT_METADATA_NAME,
+                                       sizeof(uchan->name))) {
+                       struct ustctl_consumer_channel_attr attr;
+                       copy_channel_attr_to_ustctl(&attr, &uchan->attr);
+                       ret = create_ust_app_metadata(ua_sess, app, usess->consumer,
+                                       &attr);
+               } else {
+                       /* Create channel onto application. We don't need the chan ref. */
+                       ret = create_ust_app_channel(ua_sess, uchan, app,
+                                       LTTNG_UST_CHAN_PER_CPU, usess, NULL);
+               }
                pthread_mutex_unlock(&ua_sess->lock);
                if (ret < 0) {
                        if (ret == -ENOMEM) {
@@ -3517,8 +3582,11 @@ int ust_app_start_trace(struct ltt_ust_session *usess, struct ust_app *app)
                }
        }
 
-       /* Create the metadata for the application. */
-       ret = create_ust_app_metadata(ua_sess, app, usess->consumer);
+       /*
+        * Create the metadata for the application. This returns gracefully if a
+        * metadata was already set for the session.
+        */
+       ret = create_ust_app_metadata(ua_sess, app, usess->consumer, NULL);
        if (ret < 0) {
                goto error_unlock;
        }
@@ -3865,14 +3933,31 @@ void ust_app_global_update(struct ltt_ust_session *usess, int sock)
         */
        cds_lfht_for_each_entry(ua_sess->channels->ht, &iter.iter, ua_chan,
                        node.node) {
-               ret = do_create_channel(app, usess, ua_sess, ua_chan);
-               if (ret < 0) {
-                       /*
-                        * Stop everything. On error, the application failed, no more file
-                        * descriptor are available or ENOMEM so stopping here is the only
-                        * thing we can do for now.
-                        */
-                       goto error_unlock;
+               /*
+                * For a metadata channel, handle it differently.
+                */
+               if (!strncmp(ua_chan->name, DEFAULT_METADATA_NAME,
+                                       sizeof(ua_chan->name))) {
+                       ret = create_ust_app_metadata(ua_sess, app, usess->consumer,
+                                       &ua_chan->attr);
+                       if (ret < 0) {
+                               goto error_unlock;
+                       }
+                       /* Remove it from the hash table and continue!. */
+                       ret = lttng_ht_del(ua_sess->channels, &iter);
+                       assert(!ret);
+                       delete_ust_app_channel(-1, ua_chan, app);
+                       continue;
+               } else {
+                       ret = do_create_channel(app, usess, ua_sess, ua_chan);
+                       if (ret < 0) {
+                               /*
+                                * Stop everything. On error, the application failed, no more
+                                * file descriptor are available or ENOMEM so stopping here is
+                                * the only thing we can do for now.
+                                */
+                               goto error_unlock;
+                       }
                }
 
                cds_lfht_for_each_entry(ua_chan->ctx->ht, &iter_ctx.iter, ua_ctx,
This page took 0.027144 seconds and 4 git commands to generate.