Implement UST stop command
[lttng-tools.git] / lttng-sessiond / ust-app.c
index a30b01dca37ce7515d183430921e79929d66c391..3547679f8bc8dbe1381aae36f46a54a7f3933932 100644 (file)
@@ -143,6 +143,7 @@ static void delete_ust_app(struct ust_app *app)
        struct cds_lfht_node *node;
        struct cds_lfht_iter iter;
        struct ust_app_session *ua_sess;
+       int sock;
 
        rcu_read_lock();
 
@@ -167,9 +168,8 @@ static void delete_ust_app(struct ust_app *app)
        /* Socket is already closed at this point */
 
        /* Delete ust app sessions info */
-       if (app->sock_closed) {
-               app->key.sock = -1;
-       }
+       sock = app->key.sock;
+       app->key.sock = -1;
 
        cds_lfht_for_each_entry(app->sessions, &iter, ua_sess, node) {
                hashtable_del(app->sessions, &iter);
@@ -182,9 +182,13 @@ static void delete_ust_app(struct ust_app *app)
                goto end;
        }
 
-       if (!app->sock_closed) {
-               close(app->key.sock);
-       }
+       /*
+        * Wait until we have removed the key from the sock hash table
+        * before closing this socket, otherwise an application could
+        * re-use the socket ID and race with the teardown, using the
+        * same hash table entry.
+        */
+       close(sock);
 
        DBG2("UST app pid %d deleted", app->key.pid);
        free(app);
@@ -503,17 +507,37 @@ static void shadow_copy_channel(struct ust_app_channel *ua_chan,
  * Copy data between a UST app session and a regular LTT session.
  */
 static void shadow_copy_session(struct ust_app_session *ua_sess,
-               struct ltt_ust_session *usess)
+               struct ltt_ust_session *usess,
+               struct ust_app *app)
 {
        struct cds_lfht_node *ua_chan_node;
        struct cds_lfht_iter iter;
        struct ltt_ust_channel *uchan;
        struct ust_app_channel *ua_chan;
+       time_t rawtime;
+       struct tm *timeinfo;
+       char datetime[16];
+       int ret;
+
+       /* Get date and time for unique app path */
+       time(&rawtime);
+       timeinfo = localtime(&rawtime);
+       strftime(datetime, sizeof(datetime), "%Y%m%d-%H%M%S", timeinfo);
 
        DBG2("Shadow copy of session handle %d", ua_sess->handle);
 
        ua_sess->uid = usess->uid;
 
+       ret = snprintf(ua_sess->path, PATH_MAX,
+                       "%s/%s-%d-%s",
+                       usess->pathname, app->name, app->key.pid,
+                       datetime);
+       if (ret < 0) {
+               PERROR("asprintf UST shadow copy session");
+               /* TODO: We cannot return an error from here.. */
+               assert(0);
+       }
+
        /* TODO: support all UST domain */
 
        /* Iterate over all channels in global domain. */
@@ -585,7 +609,7 @@ static struct ust_app_session *create_ust_app_session(
                        /* Only malloc can failed so something is really wrong */
                        goto error;
                }
-               shadow_copy_session(ua_sess, usess);
+               shadow_copy_session(ua_sess, usess, app);
        }
 
        if (ua_sess->handle == -1) {
@@ -727,21 +751,14 @@ static int create_ust_app_metadata(struct ust_app_session *ua_sess,
                        goto error;
                }
 
-               ret = snprintf(ua_sess->metadata->pathname, PATH_MAX, "%s/%s-%d",
-                               pathname, app->name, app->key.pid);
-               if (ret < 0) {
-                       PERROR("asprintf UST create stream");
-                       goto error;
-               }
-
-               ret = mkdir(ua_sess->metadata->pathname, S_IRWXU | S_IRWXG);
+               ret = mkdir(ua_sess->path, S_IRWXU | S_IRWXG);
                if (ret < 0) {
                        PERROR("mkdir UST metadata");
                        goto error;
                }
 
-               ret = snprintf(ua_sess->metadata->pathname, PATH_MAX, "%s/%s-%d/metadata",
-                               pathname, app->name, app->key.pid);
+               ret = snprintf(ua_sess->metadata->pathname, PATH_MAX,
+                               "%s/metadata", ua_sess->path);
                if (ret < 0) {
                        PERROR("asprintf UST create stream");
                        goto error;
@@ -868,10 +885,6 @@ void ust_app_unregister(int sock)
                goto error;
        }
 
-       /* We got called because the socket was closed on the remote end. */
-       close(sock);
-       /* Using a flag because we still need "sock" as a key. */
-       lta->sock_closed = 1;
        hashtable_del(ust_app_ht, &iter);
        call_rcu(&node->head, delete_ust_app_rcu);
 error:
@@ -970,8 +983,6 @@ void ust_app_clean_list(void)
 
        cds_lfht_for_each(ust_app_ht, &iter, node) {
                app = caa_container_of(node, struct ust_app, node);
-               close(app->key.sock);
-               app->sock_closed = 1;
 
                ret = hashtable_del(ust_app_ht, &iter);
                if (!ret) {
@@ -1111,6 +1122,10 @@ int ust_app_start_trace(struct ltt_ust_session *usess, struct ust_app *app)
                goto error_rcu_unlock;
        }
 
+       /* upon restart, we skip the setup, already done */
+       if (ua_sess->started)
+               goto skip_setup;
+
        ret = create_ust_app_metadata(ua_sess, usess->pathname, app);
        if (ret < 0) {
                goto error_rcu_unlock;
@@ -1137,9 +1152,9 @@ int ust_app_start_trace(struct ltt_ust_session *usess, struct ust_app *app)
 
                        /* Order is important */
                        cds_list_add_tail(&ustream->list, &ua_chan->streams.head);
-                       ret = snprintf(ustream->pathname, PATH_MAX, "%s/%s-%d/%s_%u",
-                                       usess->pathname, app->name, app->key.pid,
-                                       ua_chan->name, ua_chan->streams.count++);
+                       ret = snprintf(ustream->pathname, PATH_MAX, "%s/%s_%u",
+                                       ua_sess->path, ua_chan->name,
+                                       ua_chan->streams.count++);
                        if (ret < 0) {
                                PERROR("asprintf UST create stream");
                                continue;
@@ -1154,7 +1169,9 @@ int ust_app_start_trace(struct ltt_ust_session *usess, struct ust_app *app)
        if (ret < 0) {
                goto error_rcu_unlock;
        }
+       ua_sess->started = 1;
 
+skip_setup:
        /* This start the UST tracing */
        ret = ustctl_start_session(app->key.sock, ua_sess->handle);
        if (ret < 0) {
@@ -1174,6 +1191,59 @@ error_rcu_unlock:
        return -1;
 }
 
+/*
+ * Stop tracing for a specific UST session and app.
+ */
+int ust_app_stop_trace(struct ltt_ust_session *usess, struct ust_app *app)
+{
+       int ret = 0;
+       struct ust_app_session *ua_sess;
+
+       DBG("Stopping tracing for ust app pid %d", app->key.pid);
+
+       rcu_read_lock();
+
+       ua_sess = lookup_session_by_app(usess, app);
+       if (ua_sess == NULL) {
+               /* Only malloc can failed so something is really wrong */
+               goto error_rcu_unlock;
+       }
+
+#if 0  /* only useful when periodical flush will be supported */
+       /* need to keep a handle on shm in session for this. */
+       /* Flush all buffers before stopping */
+       ret = ustctl_flush_buffer(usess->sock, usess->metadata->obj);
+       if (ret < 0) {
+               ERR("UST metadata flush failed");
+       }
+
+       cds_list_for_each_entry(ustchan, &usess->channels.head, list) {
+               ret = ustctl_flush_buffer(usess->sock, ustchan->obj);
+               if (ret < 0) {
+                       ERR("UST flush buffer error");
+               }
+       }
+#endif
+
+       /* This inhibits UST tracing */
+       ret = ustctl_stop_session(app->key.sock, ua_sess->handle);
+       if (ret < 0) {
+               ERR("Error stopping tracing for app pid: %d", app->key.pid);
+               goto error_rcu_unlock;
+       }
+
+       rcu_read_unlock();
+
+       /* Quiescent wait after stopping trace */
+       ustctl_wait_quiescent(app->key.sock);
+
+       return 0;
+
+error_rcu_unlock:
+       rcu_read_unlock();
+       return -1;
+}
+
 /*
  * Start tracing for the UST session.
  */
@@ -1200,6 +1270,32 @@ int ust_app_start_trace_all(struct ltt_ust_session *usess)
        return 0;
 }
 
+/*
+ * Start tracing for the UST session.
+ */
+int ust_app_stop_trace_all(struct ltt_ust_session *usess)
+{
+       int ret = 0;
+       struct cds_lfht_iter iter;
+       struct ust_app *app;
+
+       DBG("Stopping all UST traces");
+
+       rcu_read_lock();
+
+       cds_lfht_for_each_entry(ust_app_ht, &iter, app, node) {
+               ret = ust_app_stop_trace(usess, app);
+               if (ret < 0) {
+                       /* Continue to next apps even on error */
+                       continue;
+               }
+       }
+
+       rcu_read_unlock();
+
+       return 0;
+}
+
 /*
  * Add channels/events from UST global domain to registered apps at sock.
  */
This page took 0.028754 seconds and 5 git commands to generate.