Fix: wait for the completion of implicit session rotations
authorJérémie Galarneau <jeremie.galarneau@efficios.com>
Tue, 18 Jun 2019 18:05:46 +0000 (14:05 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Thu, 25 Jul 2019 19:51:46 +0000 (15:51 -0400)
A session that has been rotated within its lifetime will be
rotated during its destruction to rename the last trace chunk.

Currently, the liblttng-ctl library's session destruction function
only waits for the data pending to indicate that all data has
been consumed. This used to be sufficient, but it is now necessary
to wait for the implicit session rotation to complete.

The "wait" variant of the session destruction function will wait
for any implicit session rotation to compete. A new
lttng_destruction_handle class is introduced to allow a client to
wait for the destruction of a session and obtain the location of
the last trace archive produced by the implicit session rotation.

Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
19 files changed:
include/Makefile.am
include/lttng/destruction-handle.h [new file with mode: 0644]
include/lttng/lttng-error.h
include/lttng/rotate-internal.h
include/lttng/session.h
src/bin/lttng-sessiond/client.c
src/bin/lttng-sessiond/cmd.c
src/bin/lttng-sessiond/cmd.h
src/bin/lttng-sessiond/main.c
src/bin/lttng-sessiond/session.c
src/bin/lttng-sessiond/session.h
src/bin/lttng/commands/destroy.c
src/common/defaults.h
src/common/error.c
src/common/sessiond-comm/sessiond-comm.h
src/lib/lttng-ctl/Makefile.am
src/lib/lttng-ctl/destruction-handle.c [new file with mode: 0644]
src/lib/lttng-ctl/lttng-ctl-helper.h
src/lib/lttng-ctl/lttng-ctl.c

index 7f27cc82fe407d0742c567054d42e7617ffcbb53..c86a1c5e09c0341c062033cfd39c86107915c9e0 100644 (file)
@@ -84,7 +84,8 @@ lttnginclude_HEADERS = \
        lttng/rotation.h \
        lttng/location.h \
        lttng/userspace-probe.h \
        lttng/rotation.h \
        lttng/location.h \
        lttng/userspace-probe.h \
-       lttng/session-descriptor.h
+       lttng/session-descriptor.h \
+       lttng/destruction-handle.h
 
 lttngactioninclude_HEADERS= \
        lttng/action/action.h \
 
 lttngactioninclude_HEADERS= \
        lttng/action/action.h \
diff --git a/include/lttng/destruction-handle.h b/include/lttng/destruction-handle.h
new file mode 100644 (file)
index 0000000..3447314
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2019 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_DESTRUCTION_HANDLE_H
+#define LTTNG_DESTRUCTION_HANDLE_H
+
+#include <lttng/rotation.h>
+#include <lttng/lttng-error.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct lttng_destruction_handle;
+
+enum lttng_destruction_handle_status {
+       LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR = -2,
+       LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID = -1,
+       LTTNG_DESTRUCTION_HANDLE_STATUS_OK = 0,
+       LTTNG_DESTRUCTION_HANDLE_STATUS_COMPLETED = 1,
+       LTTNG_DESTRUCTION_HANDLE_STATUS_TIMEOUT = 2,
+};
+
+extern void lttng_destruction_handle_destroy(
+               struct lttng_destruction_handle *handle);
+
+extern enum lttng_destruction_handle_status
+lttng_destruction_handle_wait_for_completion(
+               struct lttng_destruction_handle *handle, int timeout_ms);
+
+extern enum lttng_destruction_handle_status
+lttng_destruction_handle_get_result(
+               const struct lttng_destruction_handle *handle,
+               enum lttng_error_code *result);
+
+extern enum lttng_destruction_handle_status
+lttng_destruction_handle_get_rotation_state(
+               const struct lttng_destruction_handle *handle,
+               enum lttng_rotation_state *rotation_state);
+
+extern enum lttng_destruction_handle_status
+lttng_destruction_handle_get_archive_location(
+               const struct lttng_destruction_handle *handle,
+               const struct lttng_trace_archive_location **location);
+
+#endif /* LTTNG_DESTRUCTION_HANDLE_H */
index efbd06625512f5e24aee0a31d016b8283fd571c9..d6e72df98dcb2d11c5eb950e7fc9d5d906129f2d 100644 (file)
@@ -172,6 +172,7 @@ enum lttng_error_code {
        LTTNG_ERR_CREATE_TRACE_CHUNK_FAIL_CONSUMER     = 149, /* trace chunk creation failure on consumer */
        LTTNG_ERR_CLOSE_TRACE_CHUNK_FAIL_CONSUMER      = 150, /* trace chunk close failure on consumer */
        LTTNG_ERR_TRACE_CHUNK_EXISTS_FAIL_CONSUMER     = 151, /* failed to query consumer for trace chunk existence */
        LTTNG_ERR_CREATE_TRACE_CHUNK_FAIL_CONSUMER     = 149, /* trace chunk creation failure on consumer */
        LTTNG_ERR_CLOSE_TRACE_CHUNK_FAIL_CONSUMER      = 150, /* trace chunk close failure on consumer */
        LTTNG_ERR_TRACE_CHUNK_EXISTS_FAIL_CONSUMER     = 151, /* failed to query consumer for trace chunk existence */
+       LTTNG_ERR_INVALID_PROTOCOL                     = 152, /* a protocol error occurred */
 
        /* MUST be last element */
        LTTNG_ERR_NR,                           /* Last element */
 
        /* MUST be last element */
        LTTNG_ERR_NR,                           /* Last element */
index c441780791b7f74907b643d7854e16749188953a..17a08dd4fa7ee9475ff8c30179118c13bb9bb59c 100644 (file)
@@ -89,7 +89,9 @@ struct lttng_rotate_session_return {
 struct lttng_rotation_get_info_return {
        /* Represents values defined in enum lttng_rotation_state. */
        int32_t status;
 struct lttng_rotation_get_info_return {
        /* Represents values defined in enum lttng_rotation_state. */
        int32_t status;
-       /* Represents values defined in enum lttng_rotation_state. */
+       /*
+        * Represents values defined in enum lttng_trace_archive_location_type.
+        */
        int8_t location_type;
        union {
                struct {
        int8_t location_type;
        union {
                struct {
index 6c54d7e4f5e55fc5fe4dde03ff8a4812e5411a97..8ba8179136f09931ed66e21247fa3124d69e408f 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2014 - David Goulet <dgoulet@efficios.com>
 /*
  * Copyright (C) 2014 - David Goulet <dgoulet@efficios.com>
+ * Copyright (C) 2019 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License, version 2.1 only,
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License, version 2.1 only,
@@ -23,6 +24,7 @@ extern "C" {
 #endif
 
 struct lttng_session_descriptor;
 #endif
 
 struct lttng_session_descriptor;
+struct lttng_destruction_handle;
 
 /*
  * Basic session information.
 
 /*
  * Basic session information.
@@ -128,10 +130,25 @@ extern int lttng_create_session_live(const char *name, const char *url,
  *
  * The name can't be NULL here.
  *
  *
  * The name can't be NULL here.
  *
- * Return 0 on success else a negative LTTng error code.
+ * Returns LTTNG_OK on success, else a negative LTTng error code.
  */
 extern int lttng_destroy_session(const char *name);
 
  */
 extern int lttng_destroy_session(const char *name);
 
+/*
+ * Destroy a tracing session.
+ *
+ * Performs the same function as lttng_destroy_session(), but provides
+ * an lttng_destruction_handle which can be used to wait for the completion
+ * of the session's destruction. The lttng_destroy_handle can also be used
+ * obtain the status and archive location of any implicit session
+ * rotation that may have occured during the session's destruction.
+ *
+ * Returns LTTNG_OK on success. The returned handle is owned by the caller
+ * and must be free'd using lttng_destruction_handle_destroy().
+ */
+extern enum lttng_error_code lttng_destroy_session_ext(const char *session_name,
+               struct lttng_destruction_handle **handle);
+
 /*
  * Behaves exactly like lttng_destroy_session but does not wait for data
  * availability.
 /*
  * Behaves exactly like lttng_destroy_session but does not wait for data
  * availability.
index 4565a18c31efe55f70e94293cd03d6962d574af4..aea667cd116d2fea0132bffec7782b065fc71536 100644 (file)
@@ -706,10 +706,12 @@ static int send_unix_sock(int sock, void *buf, size_t len)
  * Return any error encountered or 0 for success.
  *
  * "sock" is only used for special-case var. len data.
  * Return any error encountered or 0 for success.
  *
  * "sock" is only used for special-case var. len data.
+ * A command may assume the ownership of the socket, in which case its value
+ * should be set to -1.
  *
  * Should *NOT* be called with RCU read-side lock held.
  */
  *
  * Should *NOT* be called with RCU read-side lock held.
  */
-static int process_client_msg(struct command_ctx *cmd_ctx, int sock,
+static int process_client_msg(struct command_ctx *cmd_ctx, int *sock,
                int *sock_error)
 {
        int ret = LTTNG_OK;
                int *sock_error)
 {
        int ret = LTTNG_OK;
@@ -1108,13 +1110,13 @@ skip_domain:
                        cmd_ctx->lsm->u.context.ctx.u.app_ctx.ctx_name =
                                        context_name;
 
                        cmd_ctx->lsm->u.context.ctx.u.app_ctx.ctx_name =
                                        context_name;
 
-                       ret = lttcomm_recv_unix_sock(sock, provider_name,
+                       ret = lttcomm_recv_unix_sock(*sock, provider_name,
                                        provider_name_len);
                        if (ret < 0) {
                                goto error_add_context;
                        }
 
                                        provider_name_len);
                        if (ret < 0) {
                                goto error_add_context;
                        }
 
-                       ret = lttcomm_recv_unix_sock(sock, context_name,
+                       ret = lttcomm_recv_unix_sock(*sock, context_name,
                                        context_name_len);
                        if (ret < 0) {
                                goto error_add_context;
                                        context_name_len);
                        if (ret < 0) {
                                goto error_add_context;
@@ -1167,7 +1169,7 @@ error_add_context:
 
                        DBG("Discarding disable event command payload of size %zu", count);
                        while (count) {
 
                        DBG("Discarding disable event command payload of size %zu", count);
                        while (count) {
-                               ret = lttcomm_recv_unix_sock(sock, data,
+                               ret = lttcomm_recv_unix_sock(*sock, data,
                                        count > sizeof(data) ? sizeof(data) : count);
                                if (ret < 0) {
                                        goto error;
                                        count > sizeof(data) ? sizeof(data) : count);
                                if (ret < 0) {
                                        goto error;
@@ -1225,7 +1227,7 @@ error_add_context:
 
                        DBG("Receiving var len exclusion event list from client ...");
                        exclusion->count = count;
 
                        DBG("Receiving var len exclusion event list from client ...");
                        exclusion->count = count;
-                       ret = lttcomm_recv_unix_sock(sock, exclusion->names,
+                       ret = lttcomm_recv_unix_sock(*sock, exclusion->names,
                                        count * LTTNG_SYMBOL_NAME_LEN);
                        if (ret <= 0) {
                                DBG("Nothing recv() from client var len data... continuing");
                                        count * LTTNG_SYMBOL_NAME_LEN);
                        if (ret <= 0) {
                                DBG("Nothing recv() from client var len data... continuing");
@@ -1256,7 +1258,7 @@ error_add_context:
 
                        /* Receive var. len. data */
                        DBG("Receiving var len filter's expression from client ...");
 
                        /* Receive var. len. data */
                        DBG("Receiving var len filter's expression from client ...");
-                       ret = lttcomm_recv_unix_sock(sock, filter_expression,
+                       ret = lttcomm_recv_unix_sock(*sock, filter_expression,
                                expression_len);
                        if (ret <= 0) {
                                DBG("Nothing recv() from client var len data... continuing");
                                expression_len);
                        if (ret <= 0) {
                                DBG("Nothing recv() from client var len data... continuing");
@@ -1289,7 +1291,7 @@ error_add_context:
 
                        /* Receive var. len. data */
                        DBG("Receiving var len filter's bytecode from client ...");
 
                        /* Receive var. len. data */
                        DBG("Receiving var len filter's bytecode from client ...");
-                       ret = lttcomm_recv_unix_sock(sock, bytecode, bytecode_len);
+                       ret = lttcomm_recv_unix_sock(*sock, bytecode, bytecode_len);
                        if (ret <= 0) {
                                DBG("Nothing recv() from client var len data... continuing");
                                *sock_error = 1;
                        if (ret <= 0) {
                                DBG("Nothing recv() from client var len data... continuing");
                                *sock_error = 1;
@@ -1323,7 +1325,7 @@ error_add_context:
 
                if (cmd_ctx->lsm->u.enable.userspace_probe_location_len > 0) {
                        /* Expect a userspace probe description. */
 
                if (cmd_ctx->lsm->u.enable.userspace_probe_location_len > 0) {
                        /* Expect a userspace probe description. */
-                       ret = receive_userspace_probe(cmd_ctx, sock, sock_error, ev);
+                       ret = receive_userspace_probe(cmd_ctx, *sock, sock_error, ev);
                        if (ret) {
                                free(filter_expression);
                                free(bytecode);
                        if (ret) {
                                free(filter_expression);
                                free(bytecode);
@@ -1476,7 +1478,7 @@ error_add_context:
 
                /* Receive variable len data */
                DBG("Receiving %zu URI(s) from client ...", nb_uri);
 
                /* Receive variable len data */
                DBG("Receiving %zu URI(s) from client ...", nb_uri);
-               ret = lttcomm_recv_unix_sock(sock, uris, len);
+               ret = lttcomm_recv_unix_sock(*sock, uris, len);
                if (ret <= 0) {
                        DBG("No URIs received from client... continuing");
                        *sock_error = 1;
                if (ret <= 0) {
                        DBG("No URIs received from client... continuing");
                        *sock_error = 1;
@@ -1521,7 +1523,8 @@ error_add_context:
        case LTTNG_DESTROY_SESSION:
        {
                ret = cmd_destroy_session(cmd_ctx->session,
        case LTTNG_DESTROY_SESSION:
        {
                ret = cmd_destroy_session(cmd_ctx->session,
-                               notification_thread_handle);
+                               notification_thread_handle,
+                               sock);
                break;
        }
        case LTTNG_LIST_DOMAINS:
                break;
        }
        case LTTNG_LIST_DOMAINS:
@@ -1760,7 +1763,7 @@ error_add_context:
                struct lttng_session_descriptor *return_descriptor = NULL;
 
                lttng_dynamic_buffer_init(&payload);
                struct lttng_session_descriptor *return_descriptor = NULL;
 
                lttng_dynamic_buffer_init(&payload);
-               ret = cmd_create_session(cmd_ctx, sock, &return_descriptor);
+               ret = cmd_create_session(cmd_ctx, *sock, &return_descriptor);
                if (ret != LTTNG_OK) {
                        goto error;
                }
                if (ret != LTTNG_OK) {
                        goto error;
                }
@@ -1809,13 +1812,13 @@ error_add_context:
        }
        case LTTNG_REGISTER_TRIGGER:
        {
        }
        case LTTNG_REGISTER_TRIGGER:
        {
-               ret = cmd_register_trigger(cmd_ctx, sock,
+               ret = cmd_register_trigger(cmd_ctx, *sock,
                                notification_thread_handle);
                break;
        }
        case LTTNG_UNREGISTER_TRIGGER:
        {
                                notification_thread_handle);
                break;
        }
        case LTTNG_UNREGISTER_TRIGGER:
        {
-               ret = cmd_unregister_trigger(cmd_ctx, sock,
+               ret = cmd_unregister_trigger(cmd_ctx, *sock,
                                notification_thread_handle);
                break;
        }
                                notification_thread_handle);
                break;
        }
@@ -1934,6 +1937,7 @@ setup_error:
        if (cmd_ctx->session) {
                session_unlock(cmd_ctx->session);
                session_put(cmd_ctx->session);
        if (cmd_ctx->session) {
                session_unlock(cmd_ctx->session);
                session_put(cmd_ctx->session);
+               cmd_ctx->session = NULL;
        }
        if (need_tracing_session) {
                session_unlock_list();
        }
        if (need_tracing_session) {
                session_unlock_list();
@@ -2178,14 +2182,16 @@ static void *thread_manage_clients(void *data)
                 * informations for the client. The command context struct contains
                 * everything this function may needs.
                 */
                 * informations for the client. The command context struct contains
                 * everything this function may needs.
                 */
-               ret = process_client_msg(cmd_ctx, sock, &sock_error);
+               ret = process_client_msg(cmd_ctx, &sock, &sock_error);
                rcu_thread_offline();
                if (ret < 0) {
                rcu_thread_offline();
                if (ret < 0) {
-                       ret = close(sock);
-                       if (ret) {
-                               PERROR("close");
-                       }
-                       sock = -1;
+                       if (sock >= 0) {
+                               ret = close(sock);
+                               if (ret) {
+                                       PERROR("close");
+                               }
+                        }
+                        sock = -1;
                        /*
                         * TODO: Inform client somehow of the fatal error. At
                         * this point, ret < 0 means that a zmalloc failed
                        /*
                         * TODO: Inform client somehow of the fatal error. At
                         * this point, ret < 0 means that a zmalloc failed
@@ -2211,21 +2217,24 @@ static void *thread_manage_clients(void *data)
 
                health_code_update();
 
 
                health_code_update();
 
-               DBG("Sending response (size: %d, retcode: %s (%d))",
-                               cmd_ctx->lttng_msg_size,
-                               lttng_strerror(-cmd_ctx->llm->ret_code),
-                               cmd_ctx->llm->ret_code);
-               ret = send_unix_sock(sock, cmd_ctx->llm, cmd_ctx->lttng_msg_size);
-               if (ret < 0) {
-                       ERR("Failed to send data back to client");
-               }
+               if (sock >= 0) {
+                       DBG("Sending response (size: %d, retcode: %s (%d))",
+                                       cmd_ctx->lttng_msg_size,
+                                       lttng_strerror(-cmd_ctx->llm->ret_code),
+                                       cmd_ctx->llm->ret_code);
+                       ret = send_unix_sock(sock, cmd_ctx->llm,
+                                       cmd_ctx->lttng_msg_size);
+                       if (ret < 0) {
+                               ERR("Failed to send data back to client");
+                       }
 
 
-               /* End of transmission */
-               ret = close(sock);
-               if (ret) {
-                       PERROR("close");
-               }
-               sock = -1;
+                       /* End of transmission */
+                       ret = close(sock);
+                       if (ret) {
+                               PERROR("close");
+                       }
+                }
+                sock = -1;
 
                clean_command_ctx(&cmd_ctx);
 
 
                clean_command_ctx(&cmd_ctx);
 
index b5bde4a9db637ba25d1246c55b2e8bdfcf595c0f..84d6fd9b389f7ada44caacbb5f7d3fd1ccb1589e 100644 (file)
@@ -34,6 +34,7 @@
 #include <common/dynamic-buffer.h>
 #include <common/buffer-view.h>
 #include <common/trace-chunk.h>
 #include <common/dynamic-buffer.h>
 #include <common/buffer-view.h>
 #include <common/trace-chunk.h>
+#include <lttng/location-internal.h>
 #include <lttng/trigger/trigger-internal.h>
 #include <lttng/condition/condition.h>
 #include <lttng/action/action.h>
 #include <lttng/trigger/trigger-internal.h>
 #include <lttng/condition/condition.h>
 #include <lttng/action/action.h>
 /* Sleep for 100ms between each check for the shm path's deletion. */
 #define SESSION_DESTROY_SHM_PATH_CHECK_DELAY_US 100000
 
 /* Sleep for 100ms between each check for the shm path's deletion. */
 #define SESSION_DESTROY_SHM_PATH_CHECK_DELAY_US 100000
 
+struct cmd_destroy_session_reply_context {
+       int reply_sock_fd;
+       bool implicit_rotation_on_destroy;
+};
+
 static enum lttng_error_code wait_on_path(void *path);
 
 /*
 static enum lttng_error_code wait_on_path(void *path);
 
 /*
@@ -3003,20 +3009,127 @@ error:
        return ret_code;
 }
 
        return ret_code;
 }
 
+static
+void cmd_destroy_session_reply(const struct ltt_session *session,
+               void *_reply_context)
+{
+       int ret;
+       ssize_t comm_ret;
+       const struct cmd_destroy_session_reply_context *reply_context =
+                       _reply_context;
+       struct lttng_dynamic_buffer payload;
+       struct lttcomm_session_destroy_command_header cmd_header;
+       struct lttng_trace_archive_location *location = NULL;
+       struct lttcomm_lttng_msg llm = {
+               .cmd_type = LTTNG_DESTROY_SESSION,
+               .ret_code = LTTNG_OK,
+               .pid = UINT32_MAX,
+               .cmd_header_size =
+                       sizeof(struct lttcomm_session_destroy_command_header),
+               .data_size = 0,
+       };
+       size_t payload_size_before_location;
+
+       lttng_dynamic_buffer_init(&payload);
+
+       ret = lttng_dynamic_buffer_append(&payload, &llm, sizeof(llm));
+        if (ret) {
+               ERR("Failed to append session destruction message");
+               goto error;
+        }
+
+       cmd_header.rotation_state =
+                       (int32_t) (reply_context->implicit_rotation_on_destroy ?
+                               session->rotation_state :
+                               LTTNG_ROTATION_STATE_NO_ROTATION);
+       ret = lttng_dynamic_buffer_append(&payload, &cmd_header,
+                       sizeof(cmd_header));
+       if (ret) {
+               ERR("Failed to append session destruction command header");
+               goto error;
+       }
+
+       if (!reply_context->implicit_rotation_on_destroy) {
+               DBG("No implicit rotation performed during the destruction of session \"%s\", sending reply",
+                               session->name);
+               goto send_reply;
+       }
+       if (session->rotation_state != LTTNG_ROTATION_STATE_COMPLETED) {
+               DBG("Rotation state of session \"%s\" is not \"completed\", sending session destruction reply",
+                               session->name);
+               goto send_reply;
+       }
+
+       location = session_get_trace_archive_location(session);
+       if (!location) {
+               ERR("Failed to get the location of the trace archive produced during the destruction of session \"%s\"",
+                               session->name);
+               goto error;
+       }
+
+       payload_size_before_location = payload.size;
+       comm_ret = lttng_trace_archive_location_serialize(location,
+                       &payload);
+       if (comm_ret < 0) {
+               ERR("Failed to serialize the location of the trace archive produced during the destruction of session \"%s\"",
+                               session->name);
+               goto error;
+       }
+       /* Update the message to indicate the location's length. */
+       ((struct lttcomm_lttng_msg *) payload.data)->data_size =
+                       payload.size - payload_size_before_location;
+send_reply:
+       comm_ret = lttcomm_send_unix_sock(reply_context->reply_sock_fd,
+                       payload.data, payload.size);
+       if (comm_ret != (ssize_t) payload.size) {
+               ERR("Failed to send result of the destruction of session \"%s\" to client",
+                               session->name);
+       }
+error:
+       ret = close(reply_context->reply_sock_fd);
+       if (ret) {
+               PERROR("Failed to close client socket in deferred session destroy reply");
+       }
+       lttng_dynamic_buffer_reset(&payload);
+       free(_reply_context);
+}
+
 /*
  * Command LTTNG_DESTROY_SESSION processed by the client thread.
  *
  * Called with session lock held.
  */
 int cmd_destroy_session(struct ltt_session *session,
 /*
  * Command LTTNG_DESTROY_SESSION processed by the client thread.
  *
  * Called with session lock held.
  */
 int cmd_destroy_session(struct ltt_session *session,
-               struct notification_thread_handle *notification_thread_handle)
+               struct notification_thread_handle *notification_thread_handle,
+               int *sock_fd)
 {
        int ret;
 {
        int ret;
+       struct cmd_destroy_session_reply_context *reply_context = NULL;
+
+       if (sock_fd) {
+               reply_context = zmalloc(sizeof(*reply_context));
+               if (!reply_context) {
+                       ret = LTTNG_ERR_NOMEM;
+                       goto end;
+               }
+               reply_context->reply_sock_fd = *sock_fd;
+       }
 
        /* Safety net */
        assert(session);
 
 
        /* Safety net */
        assert(session);
 
-       DBG("Begin destroy session %s (id %" PRIu64 ")", session->name, session->id);
+       DBG("Begin destroy session %s (id %" PRIu64 ")", session->name,
+                       session->id);
+       if (session->active) {
+               DBG("Session \"%s\" is active, attempting to stop it before destroying it",
+                               session->name);
+               ret = cmd_stop_trace(session);
+               if (ret != LTTNG_OK && ret != LTTNG_ERR_TRACE_ALREADY_STOPPED) {
+                       /* Carry on with the destruction of the session. */
+                       ERR("Failed to stop session \"%s\" as part of its destruction: %s",
+                                       session->name, lttng_strerror(-ret));
+               }
+       }
 
        if (session->rotation_schedule_timer_enabled) {
                if (timer_session_rotation_schedule_timer_stop(
 
        if (session->rotation_schedule_timer_enabled) {
                if (timer_session_rotation_schedule_timer_stop(
@@ -3039,7 +3152,10 @@ int cmd_destroy_session(struct ltt_session *session,
                        ERR("Failed to perform an implicit rotation as part of the destruction of session \"%s\": %s",
                                        session->name, lttng_strerror(-ret));
                }
                        ERR("Failed to perform an implicit rotation as part of the destruction of session \"%s\": %s",
                                        session->name, lttng_strerror(-ret));
                }
-       }
+                if (reply_context) {
+                       reply_context->implicit_rotation_on_destroy = true;
+                }
+        }
 
        if (session->shm_path[0]) {
                /*
 
        if (session->shm_path[0]) {
                /*
@@ -3101,8 +3217,19 @@ int cmd_destroy_session(struct ltt_session *session,
         * _at least_ up to the point when that reference is released.
         */
        session_destroy(session);
         * _at least_ up to the point when that reference is released.
         */
        session_destroy(session);
-       ret = LTTNG_OK;
-
+       if (reply_context) {
+               ret = session_add_destroy_notifier(session,
+                               cmd_destroy_session_reply,
+                               (void *) reply_context);
+               if (ret) {
+                       ret = LTTNG_ERR_FATAL;
+                       goto end;
+               } else {
+                       *sock_fd = -1;
+               }
+        }
+        ret = LTTNG_OK;
+end:
        return ret;
 }
 
        return ret;
 }
 
index 0821fb33d77ffdd5e296ec97d6bc6cd63e8e0e63..21a12d51f6721566445e54d786059adb927e0f90 100644 (file)
@@ -47,7 +47,8 @@ void cmd_init(void);
 enum lttng_error_code cmd_create_session(struct command_ctx *cmd_ctx, int sock,
                struct lttng_session_descriptor **return_descriptor);
 int cmd_destroy_session(struct ltt_session *session,
 enum lttng_error_code cmd_create_session(struct command_ctx *cmd_ctx, int sock,
                struct lttng_session_descriptor **return_descriptor);
 int cmd_destroy_session(struct ltt_session *session,
-               struct notification_thread_handle *notification_thread_handle);
+               struct notification_thread_handle *notification_thread_handle,
+               int *sock_fd);
 
 /* Channel commands */
 int cmd_disable_channel(struct ltt_session *session,
 
 /* Channel commands */
 int cmd_disable_channel(struct ltt_session *session,
index dd5cee4bd038333c7bb94e8e5649bfb38803ac4d..ac7f7c910317d45158ac75991fa55cea17af7610 100644 (file)
@@ -1335,8 +1335,8 @@ static void destroy_all_sessions_and_wait(void)
                        goto unlock_session;
                }
                (void) cmd_stop_trace(session);
                        goto unlock_session;
                }
                (void) cmd_stop_trace(session);
-               (void) cmd_destroy_session(session,
-                               notification_thread_handle);
+               (void) cmd_destroy_session(session, notification_thread_handle,
+                               NULL);
        unlock_session:
                session_unlock(session);
                session_put(session);
        unlock_session:
                session_unlock(session);
                session_put(session);
index abac2404f04bdda9b2c3a94ec8507c950f3a427a..4a15c9a9ad53eac1106c01f380bea8f70c114985 100644 (file)
 #include "trace-ust.h"
 #include "timer.h"
 
 #include "trace-ust.h"
 #include "timer.h"
 
+struct ltt_session_destroy_notifier_element {
+       ltt_session_destroy_notifier notifier;
+       void *user_data;
+};
+
 /*
  * NOTES:
  *
 /*
  * NOTES:
  *
@@ -245,7 +250,7 @@ void session_get_net_consumer_ports(const struct ltt_session *session,
  * The caller must hold the session lock.
  */
 struct lttng_trace_archive_location *session_get_trace_archive_location(
  * The caller must hold the session lock.
  */
 struct lttng_trace_archive_location *session_get_trace_archive_location(
-               struct ltt_session *session)
+               const struct ltt_session *session)
 {
        int ret;
        struct lttng_trace_archive_location *location = NULL;
 {
        int ret;
        struct lttng_trace_archive_location *location = NULL;
@@ -737,6 +742,22 @@ int session_set_trace_chunk(struct ltt_session *session,
                        current_trace_chunk);
 }
 
                        current_trace_chunk);
 }
 
+static
+void session_notify_destruction(const struct ltt_session *session)
+{
+       size_t i;
+       const size_t count = lttng_dynamic_array_get_count(
+                       &session->destroy_notifiers);
+
+       for (i = 0; i < count; i++) {
+               const struct ltt_session_destroy_notifier_element *element =
+                       lttng_dynamic_array_get_element(
+                                       &session->destroy_notifiers, i);
+
+               element->notifier(session, element->user_data);
+       }
+}
+
 static
 void session_release(struct urcu_ref *ref)
 {
 static
 void session_release(struct urcu_ref *ref)
 {
@@ -749,6 +770,9 @@ void session_release(struct urcu_ref *ref)
 
        usess = session->ust_session;
        ksess = session->kernel_session;
 
        usess = session->ust_session;
        ksess = session->kernel_session;
+
+       session_notify_destruction(session);
+       lttng_dynamic_array_reset(&session->destroy_notifiers, NULL);
        if (session->current_trace_chunk) {
                ret = session_close_trace_chunk(session, session->current_trace_chunk);
                if (ret) {
        if (session->current_trace_chunk) {
                ret = session_close_trace_chunk(session, session->current_trace_chunk);
                if (ret) {
@@ -852,6 +876,18 @@ void session_destroy(struct ltt_session *session)
        session_put(session);
 }
 
        session_put(session);
 }
 
+int session_add_destroy_notifier(struct ltt_session *session,
+               ltt_session_destroy_notifier notifier, void *user_data)
+{
+       const struct ltt_session_destroy_notifier_element element = {
+               .notifier = notifier,
+               .user_data = user_data
+       };
+
+       return lttng_dynamic_array_add_element(&session->destroy_notifiers,
+                       &element);
+}
+
 /*
  * Return a ltt_session structure ptr that matches name. If no session found,
  * NULL is returned. This must be called with the session list lock held using
 /*
  * Return a ltt_session structure ptr that matches name. If no session found,
  * NULL is returned. This must be called with the session list lock held using
@@ -940,6 +976,8 @@ enum lttng_error_code session_create(const char *name, uid_t uid, gid_t gid,
                goto error;
        }
 
                goto error;
        }
 
+       lttng_dynamic_array_init(&new_session->destroy_notifiers,
+                       sizeof(struct ltt_session_destroy_notifier_element));
        urcu_ref_init(&new_session->ref);
        pthread_mutex_init(&new_session->lock, NULL);
 
        urcu_ref_init(&new_session->ref);
        pthread_mutex_init(&new_session->lock, NULL);
 
index 1cea52a61fc64a75169041aa7bbddee7b8180082..0b4746cb51b80c5fe62d28997eb0944e77bc24e2 100644 (file)
@@ -23,6 +23,7 @@
 #include <urcu/list.h>
 
 #include <common/hashtable/hashtable.h>
 #include <urcu/list.h>
 
 #include <common/hashtable/hashtable.h>
+#include <common/dynamic-array.h>
 #include <lttng/rotation.h>
 #include <lttng/location.h>
 #include <lttng/lttng-error.h>
 #include <lttng/rotation.h>
 #include <lttng/location.h>
 #include <lttng/lttng-error.h>
@@ -33,6 +34,9 @@
 
 struct ltt_ust_session;
 
 
 struct ltt_ust_session;
 
+typedef void (*ltt_session_destroy_notifier)(const struct ltt_session *session,
+               void *user_data);
+
 /*
  * Tracing session list
  *
 /*
  * Tracing session list
  *
@@ -178,6 +182,7 @@ struct ltt_session {
        enum lttng_rotation_state rotation_state;
        char *last_archived_chunk_name;
        LTTNG_OPTIONAL(uint64_t) last_archived_chunk_id;
        enum lttng_rotation_state rotation_state;
        char *last_archived_chunk_name;
        LTTNG_OPTIONAL(uint64_t) last_archived_chunk_id;
+       struct lttng_dynamic_array destroy_notifiers;
 };
 
 /* Prototypes */
 };
 
 /* Prototypes */
@@ -190,6 +195,8 @@ void session_unlock(struct ltt_session *session);
 void session_unlock_list(void);
 
 void session_destroy(struct ltt_session *session);
 void session_unlock_list(void);
 
 void session_destroy(struct ltt_session *session);
+int session_add_destroy_notifier(struct ltt_session *session,
+               ltt_session_destroy_notifier notifier, void *user_data);
 
 bool session_get(struct ltt_session *session);
 void session_put(struct ltt_session *session);
 
 bool session_get(struct ltt_session *session);
 void session_put(struct ltt_session *session);
@@ -202,7 +209,7 @@ void session_get_net_consumer_ports(
                const struct ltt_session *session,
                uint16_t *control_port, uint16_t *data_port);
 struct lttng_trace_archive_location *session_get_trace_archive_location(
                const struct ltt_session *session,
                uint16_t *control_port, uint16_t *data_port);
 struct lttng_trace_archive_location *session_get_trace_archive_location(
-               struct ltt_session *session);
+               const struct ltt_session *session);
 
 struct ltt_session *session_find_by_name(const char *name);
 struct ltt_session *session_find_by_id(uint64_t id);
 
 struct ltt_session *session_find_by_name(const char *name);
 struct ltt_session *session_find_by_id(uint64_t id);
index 6878aaa0da20a146808592b54d89efcfabd56977..77acb180f8b8d91ee44bfd6249f86c4c8cc696b1 100644 (file)
@@ -113,7 +113,7 @@ static int destroy_session(struct lttng_session *session)
                print_session_stats(session->name);
        }
 
                print_session_stats(session->name);
        }
 
-       ret = lttng_destroy_session_no_wait(session->name);
+       ret = lttng_destroy_session(session->name);
        if (ret < 0) {
                goto error;
        }
        if (ret < 0) {
                goto error;
        }
index 5df5127b38a342890a6dddd523de1349d43c5cd0..08bbb64b91a30a58ff3ef2c3adab4998205fb7c4 100644 (file)
 /* Default maximal size of message notification channel message payloads. */
 #define DEFAULT_MAX_NOTIFICATION_CLIENT_MESSAGE_PAYLOAD_SIZE   65536
 
 /* Default maximal size of message notification channel message payloads. */
 #define DEFAULT_MAX_NOTIFICATION_CLIENT_MESSAGE_PAYLOAD_SIZE   65536
 
+/* Default maximal size of trace archive location. */
+#define DEFAULT_MAX_TRACE_ARCHIVE_LOCATION_PAYLOAD_SIZE                65536
+
 /* Default maximal size of message notification channel message payloads. */
 #define DEFAULT_CLIENT_MAX_QUEUED_NOTIFICATIONS_COUNT          100
 
 /* Default maximal size of message notification channel message payloads. */
 #define DEFAULT_CLIENT_MAX_QUEUED_NOTIFICATIONS_COUNT          100
 
index 2ba62d7be38fc68abe9561810e9cbb9813703e98..a87c53a89d90fc1ec91dcb9f6ca6a2b48a779002 100644 (file)
@@ -217,6 +217,7 @@ static const char *error_string_array[] = {
        [ ERROR_INDEX(LTTNG_ERR_CREATE_TRACE_CHUNK_FAIL_CONSUMER) ] = "Trace chunk creation failed on consumer",
        [ ERROR_INDEX(LTTNG_ERR_CLOSE_TRACE_CHUNK_FAIL_CONSUMER) ] = "Trace chunk close failed on consumer",
        [ ERROR_INDEX(LTTNG_ERR_TRACE_CHUNK_EXISTS_FAIL_CONSUMER) ] = "Failed to query consumer for trace chunk existence",
        [ ERROR_INDEX(LTTNG_ERR_CREATE_TRACE_CHUNK_FAIL_CONSUMER) ] = "Trace chunk creation failed on consumer",
        [ ERROR_INDEX(LTTNG_ERR_CLOSE_TRACE_CHUNK_FAIL_CONSUMER) ] = "Trace chunk close failed on consumer",
        [ ERROR_INDEX(LTTNG_ERR_TRACE_CHUNK_EXISTS_FAIL_CONSUMER) ] = "Failed to query consumer for trace chunk existence",
+       [ ERROR_INDEX(LTTNG_ERR_INVALID_PROTOCOL) ] = "Protocol error occurred",
 
        /* Last element */
        [ ERROR_INDEX(LTTNG_ERR_NR) ] = "Unknown error code"
 
        /* Last element */
        [ ERROR_INDEX(LTTNG_ERR_NR) ] = "Unknown error code"
index d673c6e19c2a0dc7ad591c18b8e3be851a088d72..3b0093bfbc9e0d7d06d598a74ba6cace921ab6a2 100644 (file)
@@ -445,6 +445,14 @@ struct lttcomm_event_extended_header {
        uint32_t userspace_probe_location_len;
 } LTTNG_PACKED;
 
        uint32_t userspace_probe_location_len;
 } LTTNG_PACKED;
 
+/*
+ * Command header of the reply to an LTTNG_DESTROY_SESSION command.
+ */
+struct lttcomm_session_destroy_command_header {
+       /* enum lttng_session */
+       int32_t rotation_state;
+};
+
 /*
  * Data structure for the response from sessiond to the lttng client.
  */
 /*
  * Data structure for the response from sessiond to the lttng client.
  */
index d18328e4b80f7e4817bf89a6a4846fd8be04117e..32d0aff54f3c04123caf170ec31b158eaa063df8 100644 (file)
@@ -6,7 +6,7 @@ lib_LTLIBRARIES = liblttng-ctl.la
 
 liblttng_ctl_la_SOURCES = lttng-ctl.c snapshot.c lttng-ctl-helper.h \
                lttng-ctl-health.c save.c load.c deprecated-symbols.c \
 
 liblttng_ctl_la_SOURCES = lttng-ctl.c snapshot.c lttng-ctl-helper.h \
                lttng-ctl-health.c save.c load.c deprecated-symbols.c \
-               channel.c rotate.c event.c
+               channel.c rotate.c event.c destruction-handle.c
 
 liblttng_ctl_la_LDFLAGS = \
                $(LT_NO_UNDEFINED)
 
 liblttng_ctl_la_LDFLAGS = \
                $(LT_NO_UNDEFINED)
diff --git a/src/lib/lttng-ctl/destruction-handle.c b/src/lib/lttng-ctl/destruction-handle.c
new file mode 100644 (file)
index 0000000..e22deaa
--- /dev/null
@@ -0,0 +1,429 @@
+/*
+ * Copyright (C) 2019 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <lttng/destruction-handle.h>
+#include <lttng/rotation.h>
+
+#include <common/optional.h>
+#include <common/compat/poll.h>
+#include <common/compat/time.h>
+#include <common/macros.h>
+#include <common/compat/poll.h>
+#include <common/dynamic-buffer.h>
+#include <common/buffer-view.h>
+#include <common/sessiond-comm/sessiond-comm.h>
+#include <lttng/location-internal.h>
+#include "lttng-ctl-helper.h"
+
+#include <stdbool.h>
+
+enum communication_state {
+       COMMUNICATION_STATE_RECEIVE_LTTNG_MSG,
+       COMMUNICATION_STATE_RECEIVE_COMMAND_HEADER,
+       COMMUNICATION_STATE_RECEIVE_PAYLOAD,
+       COMMUNICATION_STATE_END,
+       COMMUNICATION_STATE_ERROR,
+};
+
+struct lttng_destruction_handle {
+       LTTNG_OPTIONAL(enum lttng_error_code) destruction_return_code;
+       LTTNG_OPTIONAL(enum lttng_rotation_state) rotation_state;
+       struct lttng_trace_archive_location *location;
+       struct {
+               int socket;
+               struct lttng_poll_event events;
+               size_t bytes_left_to_receive;
+               enum communication_state state;
+               struct lttng_dynamic_buffer buffer;
+               LTTNG_OPTIONAL(size_t) data_size;
+       } communication;
+};
+
+void lttng_destruction_handle_destroy(struct lttng_destruction_handle *handle)
+{
+       int ret;
+
+       if (!handle) {
+               return;
+       }
+
+       if (handle->communication.socket >= 0) {
+               ret = close(handle->communication.socket);
+               if (ret) {
+                       PERROR("Failed to close lttng-sessiond command socket");
+               }
+        }
+        lttng_poll_clean(&handle->communication.events);
+       lttng_dynamic_buffer_reset(&handle->communication.buffer);
+       lttng_trace_archive_location_destroy(handle->location);
+       free(handle);
+}
+
+static
+struct lttng_destruction_handle *lttng_destruction_handle_create(
+               int sessiond_socket)
+{
+       int ret;
+       struct lttng_destruction_handle *handle = zmalloc(sizeof(*handle));
+
+       if (!handle) {
+               goto end;
+       }
+       lttng_dynamic_buffer_init(&handle->communication.buffer);
+       handle->communication.socket = sessiond_socket;
+       ret = lttng_poll_create(&handle->communication.events, 1, 0);
+       if (ret) {
+               goto error;
+       }
+
+       ret = lttng_poll_add(&handle->communication.events, sessiond_socket,
+                       LPOLLIN | LPOLLHUP | LPOLLRDHUP | LPOLLERR);
+        if (ret) {
+               goto error;
+        }
+
+       handle->communication.bytes_left_to_receive =
+                       sizeof(struct lttcomm_lttng_msg);
+       handle->communication.state = COMMUNICATION_STATE_RECEIVE_LTTNG_MSG;
+end:
+       return handle;
+error:
+       lttng_destruction_handle_destroy(handle);
+       return NULL;
+}
+
+static
+int handle_state_transition(struct lttng_destruction_handle *handle)
+{
+       int ret = 0;
+
+       assert(handle->communication.bytes_left_to_receive == 0);
+
+       switch (handle->communication.state) {
+       case COMMUNICATION_STATE_RECEIVE_LTTNG_MSG:
+       {
+               const struct lttcomm_lttng_msg *msg =
+                               (typeof(msg)) handle->communication.buffer.data;
+
+               LTTNG_OPTIONAL_SET(&handle->destruction_return_code,
+                               (enum lttng_error_code) msg->ret_code);
+               if (handle->destruction_return_code.value != LTTNG_OK) {
+                       handle->communication.state = COMMUNICATION_STATE_END;
+                       break;
+               } else if (msg->cmd_header_size != sizeof(struct lttcomm_session_destroy_command_header) ||
+                               msg->data_size > DEFAULT_MAX_TRACE_ARCHIVE_LOCATION_PAYLOAD_SIZE) {
+                       handle->communication.state = COMMUNICATION_STATE_ERROR;
+                       ret = -1;
+                       break;
+               }
+
+               handle->communication.state =
+                               COMMUNICATION_STATE_RECEIVE_COMMAND_HEADER;
+               handle->communication.bytes_left_to_receive =
+                               msg->cmd_header_size;
+               LTTNG_OPTIONAL_SET(&handle->communication.data_size,
+                               msg->data_size);
+               ret = lttng_dynamic_buffer_set_size(
+                               &handle->communication.buffer, 0);
+               assert(!ret);
+               break;
+       }
+       case COMMUNICATION_STATE_RECEIVE_COMMAND_HEADER:
+       {
+               const struct lttcomm_session_destroy_command_header *hdr =
+                               (typeof(hdr)) handle->communication.buffer.data;
+
+               LTTNG_OPTIONAL_SET(&handle->rotation_state,
+                               (enum lttng_rotation_state) hdr->rotation_state);
+               switch (handle->rotation_state.value) {
+               case LTTNG_ROTATION_STATE_COMPLETED:
+                       handle->communication.state =
+                                       COMMUNICATION_STATE_RECEIVE_PAYLOAD;
+                       handle->communication.bytes_left_to_receive =
+                                       LTTNG_OPTIONAL_GET(handle->communication.data_size);
+                       break;
+               case LTTNG_ROTATION_STATE_ERROR:
+               case LTTNG_ROTATION_STATE_NO_ROTATION:
+                       handle->communication.state = COMMUNICATION_STATE_END;
+                       break;
+               default:
+                       handle->communication.state = COMMUNICATION_STATE_ERROR;
+                       ret = -1;
+                       break;
+               }
+               break;
+       }
+       case COMMUNICATION_STATE_RECEIVE_PAYLOAD:
+       {
+               ssize_t location_ret;
+               struct lttng_trace_archive_location *location;
+               const struct lttng_buffer_view view =
+                               lttng_buffer_view_from_dynamic_buffer(
+                                       &handle->communication.buffer, 0, -1);
+
+               location_ret = lttng_trace_archive_location_create_from_buffer(
+                               &view, &location);
+               if (location_ret < 0) {
+                       ERR("Failed to deserialize trace archive location");
+                       handle->communication.state = COMMUNICATION_STATE_ERROR;
+                       ret = -1;
+                       break;
+               } else {
+                       handle->location = location;
+                       handle->communication.state = COMMUNICATION_STATE_END;
+               }
+               break;
+       }
+       default:
+               abort();
+       }
+
+       /* Clear reception buffer on state transition. */
+       if (lttng_dynamic_buffer_set_size(&handle->communication.buffer, 0)) {
+               abort();
+       }
+       return ret;
+}
+
+static
+int handle_incoming_data(struct lttng_destruction_handle *handle)
+{
+       int ret;
+       ssize_t comm_ret;
+       const size_t original_buffer_size = handle->communication.buffer.size;
+
+       /* Reserve space for reception. */
+       ret = lttng_dynamic_buffer_set_size(&handle->communication.buffer,
+                       original_buffer_size + handle->communication.bytes_left_to_receive);
+       if (ret) {
+               goto end;
+       }
+
+       comm_ret = lttcomm_recv_unix_sock(handle->communication.socket,
+                       handle->communication.buffer.data + original_buffer_size,
+                       handle->communication.bytes_left_to_receive);
+       if (comm_ret <= 0) {
+               ret = -1;
+               goto end;
+       }
+
+       handle->communication.bytes_left_to_receive -= comm_ret;
+       if (handle->communication.bytes_left_to_receive == 0) {
+               ret = handle_state_transition(handle);
+       } else {
+               ret = lttng_dynamic_buffer_set_size(
+                               &handle->communication.buffer,
+                               original_buffer_size + comm_ret);
+       }
+end:
+       return ret;
+}
+
+enum lttng_destruction_handle_status
+lttng_destruction_handle_wait_for_completion(
+               struct lttng_destruction_handle *handle, int timeout_ms)
+{
+       int ret;
+       enum lttng_destruction_handle_status status;
+       unsigned long time_left_ms = 0;
+       const bool has_timeout = timeout_ms > 0;
+        struct timespec initial_time;
+
+        if (handle->communication.state == COMMUNICATION_STATE_ERROR) {
+               status = LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR;
+               goto end;
+       } else if (handle->communication.state == COMMUNICATION_STATE_END) {
+               status = LTTNG_DESTRUCTION_HANDLE_STATUS_COMPLETED;
+               goto end;
+       }
+        if (has_timeout) {
+               ret = lttng_clock_gettime(CLOCK_MONOTONIC, &initial_time);
+               if (ret) {
+                       status = LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR;
+                       goto end;
+               }
+               time_left_ms = (unsigned long) timeout_ms;
+        }
+
+        while (handle->communication.state != COMMUNICATION_STATE_END &&
+                       (time_left_ms || !has_timeout)) {
+               int ret;
+               uint32_t revents;
+                struct timespec current_time, diff;
+               unsigned long diff_ms;
+
+                ret = lttng_poll_wait(&handle->communication.events,
+                               has_timeout ? time_left_ms : -1);
+                if (ret == 0) {
+                       /* timeout */
+                       break;
+               } else if (ret < 0) {
+                       status = LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR;
+                       goto end;
+               }
+
+               /* The sessiond connection socket is the only monitored fd. */
+               revents = LTTNG_POLL_GETEV(&handle->communication.events, 0);
+               if (revents & LPOLLIN) {
+                       ret = handle_incoming_data(handle);
+                       if (ret) {
+                               handle->communication.state =
+                                               COMMUNICATION_STATE_ERROR;
+                               status = LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR;
+                               goto end;
+                       }
+               } else {
+                       handle->communication.state = COMMUNICATION_STATE_ERROR;
+                       status = LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR;
+                       goto end;
+               }
+               if (!has_timeout) {
+                       continue;
+               }
+
+               ret = lttng_clock_gettime(CLOCK_MONOTONIC, &current_time);
+               if (ret) {
+                       status = LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR;
+                       goto end;
+               }
+               diff = timespec_abs_diff(initial_time, current_time);
+               ret = timespec_to_ms(diff, &diff_ms);
+               if (ret) {
+                       ERR("Failed to compute elapsed time while waiting for completion");
+                       status = LTTNG_DESTRUCTION_HANDLE_STATUS_ERROR;
+                       goto end;
+               }
+               DBG("%lums elapsed while waiting for session destruction completion",
+                               diff_ms);
+               diff_ms = max_t(unsigned long, diff_ms, 1);
+               diff_ms = min_t(unsigned long, diff_ms, time_left_ms);
+               time_left_ms -= diff_ms;
+       }
+
+       status = handle->communication.state == COMMUNICATION_STATE_END ?
+                       LTTNG_DESTRUCTION_HANDLE_STATUS_COMPLETED :
+                       LTTNG_DESTRUCTION_HANDLE_STATUS_TIMEOUT;
+end:
+       return status;
+}
+
+enum lttng_destruction_handle_status
+lttng_destruction_handle_get_rotation_state(
+               const struct lttng_destruction_handle *handle,
+               enum lttng_rotation_state *rotation_state)
+{
+       enum lttng_destruction_handle_status status =
+                       LTTNG_DESTRUCTION_HANDLE_STATUS_OK;
+
+       if (!handle->rotation_state.is_set) {
+               status = LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID;
+               goto end;
+       }
+       *rotation_state = handle->rotation_state.value;
+end:
+       return status;
+}
+
+enum lttng_destruction_handle_status
+lttng_destruction_handle_get_archive_location(
+               const struct lttng_destruction_handle *handle,
+               const struct lttng_trace_archive_location **location)
+{
+       enum lttng_destruction_handle_status status =
+                       LTTNG_DESTRUCTION_HANDLE_STATUS_OK;
+
+       if (!handle->location) {
+               status = LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID;
+               goto end;
+       }
+       *location = handle->location;
+end:
+       return status;
+}
+
+enum lttng_destruction_handle_status
+lttng_destruction_handle_get_result(
+               const struct lttng_destruction_handle *handle,
+               enum lttng_error_code *result)
+{
+       enum lttng_destruction_handle_status status =
+                       LTTNG_DESTRUCTION_HANDLE_STATUS_OK;
+
+       if (!handle->destruction_return_code.is_set) {
+               status = LTTNG_DESTRUCTION_HANDLE_STATUS_INVALID;
+               goto end;
+       }
+       *result = handle->destruction_return_code.value;
+end:
+       return status;
+}
+
+enum lttng_error_code lttng_destroy_session_ext(const char *session_name,
+               struct lttng_destruction_handle **_handle)
+{
+       int ret;
+       ssize_t comm_ret;
+       enum lttng_error_code ret_code = LTTNG_OK;
+        struct lttcomm_session_msg lsm = {
+               .cmd_type = LTTNG_DESTROY_SESSION,
+       };
+       int sessiond_socket = -1;
+       struct lttng_destruction_handle *handle = NULL;
+
+       ret = lttng_strncpy(lsm.session.name, session_name,
+                       sizeof(lsm.session.name));
+       if (ret) {
+               ret_code = LTTNG_ERR_INVALID;
+               goto error;
+       }
+
+       ret = connect_sessiond();
+       if (ret < 0) {
+               ret_code = LTTNG_ERR_NO_SESSIOND;
+               goto error;
+       } else {
+               sessiond_socket = ret;
+       }
+
+       handle = lttng_destruction_handle_create(sessiond_socket);
+       if (!handle) {
+               ret_code = LTTNG_ERR_NOMEM;
+               goto error;
+       }
+
+       comm_ret = lttcomm_send_unix_sock(sessiond_socket, &lsm, sizeof(lsm));
+       if (comm_ret < 0) {
+               ret_code = LTTNG_ERR_FATAL;
+               goto error;
+       }
+       sessiond_socket = -1;
+
+       /* Transfer the handle to the caller. */
+       if (_handle) {
+               *_handle = handle;
+               handle = NULL;
+       }
+error:
+       if (sessiond_socket >= 0) {
+               ret = close(sessiond_socket);
+               PERROR("Failed to close the LTTng session daemon connection socket");
+       }
+       if (handle) {
+               lttng_destruction_handle_destroy(handle);
+       }
+       return ret_code;
+}
index 9b50aacf75c85019b2dbef4635954193f6105f09..4341ee6b5f3f5daf0e0bb0ae4ac4b46be2c125f5 100644 (file)
@@ -79,4 +79,6 @@ int lttng_ctl_ask_sessiond(struct lttcomm_session_msg *lsm, void **buf)
 
 int lttng_check_tracing_group(void);
 
 
 int lttng_check_tracing_group(void);
 
+int connect_sessiond(void);
+
 #endif /* LTTNG_CTL_HELPER_H */
 #endif /* LTTNG_CTL_HELPER_H */
index 20dca8132186e46531589d9294b31a44dc52e9b3..8c52c456dd15bf63a0cee9797515d373246e5b24 100644 (file)
@@ -45,6 +45,7 @@
 #include <lttng/userspace-probe-internal.h>
 #include <lttng/session-internal.h>
 #include <lttng/session-descriptor-internal.h>
 #include <lttng/userspace-probe-internal.h>
 #include <lttng/session-internal.h>
 #include <lttng/session-descriptor-internal.h>
+#include <lttng/destruction-handle.h>
 
 #include "filter/filter-ast.h"
 #include "filter/filter-parser.h"
 
 #include "filter/filter-ast.h"
 #include "filter/filter-parser.h"
@@ -68,7 +69,7 @@ do {                                                          \
 
 
 /* Socket to session daemon for communication */
 
 
 /* Socket to session daemon for communication */
-static int sessiond_socket;
+static int sessiond_socket = -1;
 static char sessiond_sock_path[PATH_MAX];
 
 /* Variables */
 static char sessiond_sock_path[PATH_MAX];
 
 /* Variables */
@@ -423,17 +424,12 @@ error:
 /*
  * Connect to the LTTng session daemon.
  *
 /*
  * Connect to the LTTng session daemon.
  *
- * On success, return 0. On error, return -1.
+ * On success, return the socket's file descriptor. On error, return -1.
  */
  */
-static int connect_sessiond(void)
+LTTNG_HIDDEN int connect_sessiond(void)
 {
        int ret;
 
 {
        int ret;
 
-       /* Don't try to connect if already connected. */
-       if (connected) {
-               return 0;
-       }
-
        ret = set_session_daemon_path();
        if (ret < 0) {
                goto error;
        ret = set_session_daemon_path();
        if (ret < 0) {
                goto error;
@@ -445,15 +441,18 @@ static int connect_sessiond(void)
                goto error;
        }
 
                goto error;
        }
 
-       sessiond_socket = ret;
-       connected = 1;
-
-       return 0;
+       return ret;
 
 error:
        return -1;
 }
 
 
 error:
        return -1;
 }
 
+static void reset_global_sessiond_connection_state(void)
+{
+       sessiond_socket = -1;
+       connected = 0;
+}
+
 /*
  *  Clean disconnect from the session daemon.
  *
 /*
  *  Clean disconnect from the session daemon.
  *
@@ -465,8 +464,7 @@ static int disconnect_sessiond(void)
 
        if (connected) {
                ret = lttcomm_close_unix_sock(sessiond_socket);
 
        if (connected) {
                ret = lttcomm_close_unix_sock(sessiond_socket);
-               sessiond_socket = 0;
-               connected = 0;
+               reset_global_sessiond_connection_state();
        }
 
        return ret;
        }
 
        return ret;
@@ -541,6 +539,9 @@ int lttng_ctl_ask_sessiond_fds_varlen(struct lttcomm_session_msg *lsm,
        if (ret < 0) {
                ret = -LTTNG_ERR_NO_SESSIOND;
                goto end;
        if (ret < 0) {
                ret = -LTTNG_ERR_NO_SESSIOND;
                goto end;
+       } else {
+               sessiond_socket = ret;
+               connected = 1;
        }
 
        /* Send command to session daemon */
        }
 
        /* Send command to session daemon */
@@ -1993,45 +1994,47 @@ end:
        return ret;
 }
 
        return ret;
 }
 
-/*
- * Destroy session using name.
- * Returns size of returned session payload data or a negative error code.
- */
-static
-int _lttng_destroy_session(const char *session_name)
-{
-       struct lttcomm_session_msg lsm;
-
-       if (session_name == NULL) {
-               return -LTTNG_ERR_INVALID;
-       }
-
-       memset(&lsm, 0, sizeof(lsm));
-       lsm.cmd_type = LTTNG_DESTROY_SESSION;
-
-       lttng_ctl_copy_string(lsm.session.name, session_name,
-                       sizeof(lsm.session.name));
-
-       return lttng_ctl_ask_sessiond(&lsm, NULL);
-}
-
 /*
  * Stop the session and wait for the data before destroying it
  */
 int lttng_destroy_session(const char *session_name)
 {
        int ret;
 /*
  * Stop the session and wait for the data before destroying it
  */
 int lttng_destroy_session(const char *session_name)
 {
        int ret;
+       enum lttng_error_code ret_code;
+       enum lttng_destruction_handle_status status;
+       struct lttng_destruction_handle *handle = NULL;
 
        /*
 
        /*
-        * Stop the tracing and wait for the data.
+        * Stop the tracing and wait for the data to be
+        * consumed.
         */
        ret = _lttng_stop_tracing(session_name, 1);
        if (ret && ret != -LTTNG_ERR_TRACE_ALREADY_STOPPED) {
                goto end;
        }
 
         */
        ret = _lttng_stop_tracing(session_name, 1);
        if (ret && ret != -LTTNG_ERR_TRACE_ALREADY_STOPPED) {
                goto end;
        }
 
-       ret = _lttng_destroy_session(session_name);
+       ret_code = lttng_destroy_session_ext(session_name, &handle);
+       if (ret_code != LTTNG_OK) {
+               ret = (int) -ret_code;
+               goto end;
+       }
+       assert(handle);
+
+       /* Block until the completion of the destruction of the session. */
+       status = lttng_destruction_handle_wait_for_completion(handle, -1);
+       if (status != LTTNG_DESTRUCTION_HANDLE_STATUS_COMPLETED) {
+               ret = -LTTNG_ERR_UNK;
+               goto end;
+       }
+
+       status = lttng_destruction_handle_get_result(handle, &ret_code);
+       if (status != LTTNG_DESTRUCTION_HANDLE_STATUS_OK) {
+               ret = -LTTNG_ERR_UNK;
+               goto end;
+       }
+       ret = ret_code == LTTNG_OK ? LTTNG_OK : -ret_code;
 end:
 end:
+       lttng_destruction_handle_destroy(handle);
        return ret;
 }
 
        return ret;
 }
 
@@ -2040,21 +2043,10 @@ end:
  */
 int lttng_destroy_session_no_wait(const char *session_name)
 {
  */
 int lttng_destroy_session_no_wait(const char *session_name)
 {
-       int ret;
-
-       /*
-        * Stop the tracing without waiting for the data.
-        * The session might already have been stopped, so just
-        * skip this error.
-        */
-       ret = _lttng_stop_tracing(session_name, 0);
-       if (ret && ret != -LTTNG_ERR_TRACE_ALREADY_STOPPED) {
-               goto end;
-       }
+       enum lttng_error_code ret_code;
 
 
-       ret = _lttng_destroy_session(session_name);
-end:
-       return ret;
+       ret_code = lttng_destroy_session_ext(session_name, NULL);
+       return ret_code == LTTNG_OK ? ret_code : -ret_code;
 }
 
 /*
 }
 
 /*
This page took 0.046127 seconds and 5 git commands to generate.