lttng rotate command
[lttng-tools.git] / src / bin / lttng-sessiond / main.c
index b1229e7214828af2fcb260c3983d0e4d7e3cd1be..226433ead4057a3b1751de9d60e8c6e7aa3f0e09 100644 (file)
@@ -78,6 +78,7 @@
 #include "agent.h"
 #include "ht-cleanup.h"
 #include "sessiond-config.h"
+#include "sessiond-timer.h"
 
 static const char *help_msg =
 #ifdef LTTNG_EMBED_HELP
@@ -210,6 +211,7 @@ static pthread_t agent_reg_thread;
 static pthread_t load_session_thread;
 static pthread_t notification_thread;
 static pthread_t rotation_thread;
+static pthread_t timer_thread;
 
 /*
  * UST registration command queue. This queue is tied with a futex and uses a N
@@ -2901,6 +2903,22 @@ static unsigned int lttng_sessions_count(uid_t uid, gid_t gid)
        return i;
 }
 
+/*
+ * Check if the current kernel tracer supports the session rotation feature.
+ * Return 1 if it does, 0 otherwise.
+ */
+static int check_rotate_compatible(void)
+{
+       int ret = 1;
+
+       if (kernel_tracer_version.major != 2 || kernel_tracer_version.minor < 11) {
+               DBG("Kernel tracer version is not compatible with the rotation feature");
+               ret = 0;
+       }
+
+       return ret;
+}
+
 /*
  * Process the command requested by the lttng client within the command
  * context structure. This function make sure that the return structure (llm)
@@ -2945,6 +2963,9 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock,
        case LTTNG_REGENERATE_STATEDUMP:
        case LTTNG_REGISTER_TRIGGER:
        case LTTNG_UNREGISTER_TRIGGER:
+       case LTTNG_ROTATE_SESSION:
+       case LTTNG_ROTATION_GET_INFO:
+       case LTTNG_SESSION_GET_CURRENT_OUTPUT:
                need_domain = 0;
                break;
        default:
@@ -2987,6 +3008,8 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock,
        case LTTNG_LIST_SYSCALLS:
        case LTTNG_LIST_TRACKER_PIDS:
        case LTTNG_DATA_PENDING:
+       case LTTNG_ROTATE_SESSION:
+       case LTTNG_ROTATION_GET_INFO:
                break;
        default:
                /* Setup lttng message with no payload */
@@ -4075,6 +4098,79 @@ error_add_context:
                                notification_thread_handle);
                break;
        }
+       case LTTNG_ROTATE_SESSION:
+       {
+               struct lttng_rotate_session_return rotate_return;
+
+               DBG("Client rotate session \"%s\"", cmd_ctx->session->name);
+
+               memset(&rotate_return, 0, sizeof(rotate_return));
+               if (cmd_ctx->session->kernel_session && !check_rotate_compatible()) {
+                       DBG("Kernel tracer version is not compatible with the rotation feature");
+                       ret = LTTNG_ERR_ROTATION_WRONG_VERSION;
+                       goto error;
+               }
+
+               ret = cmd_rotate_session(cmd_ctx->session, &rotate_return);
+               if (ret < 0) {
+                       ret = -ret;
+                       goto error;
+               }
+
+               ret = setup_lttng_msg_no_cmd_header(cmd_ctx, &rotate_return,
+                               sizeof(rotate_return));
+               if (ret < 0) {
+                       ret = -ret;
+                       goto error;
+               }
+
+               ret = LTTNG_OK;
+               break;
+       }
+       case LTTNG_ROTATION_GET_INFO:
+       {
+               struct lttng_rotation_get_info_return get_info_return;
+
+               memset(&get_info_return, 0, sizeof(get_info_return));
+               ret = cmd_rotate_get_info(cmd_ctx->session, &get_info_return,
+                               cmd_ctx->lsm->u.get_rotation_info.rotation_id);
+               if (ret < 0) {
+                       ret = -ret;
+                       goto error;
+               }
+
+               ret = setup_lttng_msg_no_cmd_header(cmd_ctx, &get_info_return,
+                               sizeof(get_info_return));
+               if (ret < 0) {
+                       ret = -ret;
+                       goto error;
+               }
+
+               ret = LTTNG_OK;
+               break;
+       }
+       case LTTNG_SESSION_GET_CURRENT_OUTPUT:
+       {
+               struct lttng_session_get_current_output_return output_return;
+
+               memset(&output_return, 0, sizeof(output_return));
+               ret = cmd_session_get_current_output(cmd_ctx->session,
+                               &output_return);
+               if (ret < 0) {
+                       ret = -ret;
+                       goto error;
+               }
+
+               ret = setup_lttng_msg_no_cmd_header(cmd_ctx, &output_return,
+                               sizeof(output_return));
+               if (ret < 0) {
+                       ret = -ret;
+                       goto error;
+               }
+
+               ret = LTTNG_OK;
+               break;
+       }
        default:
                ret = LTTNG_ERR_UND;
                break;
@@ -5469,6 +5565,48 @@ end:
        return ret;
 }
 
+static
+struct rotation_thread_timer_queue *create_rotate_timer_queue(void)
+{
+       struct rotation_thread_timer_queue *queue = NULL;
+
+       queue = zmalloc(sizeof(struct rotation_thread_timer_queue));
+       if (!queue) {
+               PERROR("Failed to allocate timer rotate queue");
+               goto end;
+       }
+
+       queue->event_pipe = lttng_pipe_open(FD_CLOEXEC | O_NONBLOCK);
+       CDS_INIT_LIST_HEAD(&queue->list);
+       pthread_mutex_init(&queue->lock, NULL);
+
+end:
+       return queue;
+}
+
+static
+void destroy_rotate_timer_queue(struct rotation_thread_timer_queue *queue)
+{
+       struct sessiond_rotation_timer *node, *tmp_node;
+
+       if (!queue) {
+               return;
+       }
+
+       lttng_pipe_destroy(queue->event_pipe);
+
+       pthread_mutex_lock(&queue->lock);
+       /* Empty wait queue. */
+       cds_list_for_each_entry_safe(node, tmp_node, &queue->list, head) {
+               cds_list_del(&node->head);
+               free(node);
+       }
+       pthread_mutex_unlock(&queue->lock);
+
+       pthread_mutex_destroy(&queue->lock);
+       free(queue);
+}
+
 /*
  * main
  */
@@ -5482,9 +5620,13 @@ int main(int argc, char **argv)
                        *kernel_channel_monitor_pipe = NULL;
        bool notification_thread_running = false;
        bool rotation_thread_running = false;
+       bool timer_thread_running = false;
        struct lttng_pipe *ust32_channel_rotate_pipe = NULL,
                        *ust64_channel_rotate_pipe = NULL,
                        *kernel_channel_rotate_pipe = NULL;
+       struct timer_thread_parameters timer_thread_ctx;
+       /* Queue of rotation jobs populated by the sessiond-timer. */
+       struct rotation_thread_timer_queue *rotation_timer_queue = NULL;
 
        init_kernel_workarounds();
 
@@ -5495,6 +5637,11 @@ int main(int argc, char **argv)
                goto exit_set_signal_handler;
        }
 
+       if (sessiond_timer_signal_init()) {
+               retval = -1;
+               goto exit_set_signal_handler;
+       }
+
        page_size = sysconf(_SC_PAGESIZE);
        if (page_size < 0) {
                PERROR("sysconf _SC_PAGESIZE");
@@ -5682,6 +5829,17 @@ int main(int argc, char **argv)
                goto exit_init_data;
        }
 
+       /*
+        * The rotation_timer_queue structure is shared between the sessiond timer
+        * thread and the rotation thread. The main() keeps the ownership and
+        * destroys it when both threads have quit.
+        */
+       rotation_timer_queue = create_rotate_timer_queue();
+       if (!rotation_timer_queue) {
+               retval = -1;
+               goto exit_init_data;
+       }
+       timer_thread_ctx.rotation_timer_queue = rotation_timer_queue;
 
        ust64_channel_monitor_pipe = lttng_pipe_open(0);
        if (!ust64_channel_monitor_pipe) {
@@ -5900,19 +6058,31 @@ int main(int argc, char **argv)
        }
        notification_thread_running = true;
 
+       /* Create timer thread. */
+       ret = pthread_create(&timer_thread, default_pthread_attr(),
+                       sessiond_timer_thread, &timer_thread_ctx);
+       if (ret) {
+               errno = ret;
+               PERROR("pthread_create timer");
+               retval = -1;
+               stop_threads();
+               goto exit_notification;
+       }
+       timer_thread_running = true;
+
        /* rotation_thread_data acquires the pipes' read side. */
        rotation_thread_handle = rotation_thread_handle_create(
                        ust32_channel_rotate_pipe,
                        ust64_channel_rotate_pipe,
                        kernel_channel_rotate_pipe,
-                       thread_quit_pipe[0]);
+                       thread_quit_pipe[0],
+                       rotation_timer_queue);
        if (!rotation_thread_handle) {
                retval = -1;
                ERR("Failed to create rotation thread shared data");
                stop_threads();
                goto exit_rotation;
        }
-       rotation_thread_running = true;
 
        /* Create rotation thread. */
        ret = pthread_create(&rotation_thread, default_pthread_attr(),
@@ -5924,6 +6094,7 @@ int main(int argc, char **argv)
                stop_threads();
                goto exit_rotation;
        }
+       rotation_thread_running = true;
 
        /* Create thread to manage the client socket */
        ret = pthread_create(&client_thread, default_pthread_attr(),
@@ -6153,6 +6324,22 @@ exit_init_data:
                rotation_thread_handle_destroy(rotation_thread_handle);
        }
 
+       if (timer_thread_running) {
+               kill(getpid(), LTTNG_SESSIOND_SIG_EXIT);
+               ret = pthread_join(timer_thread, &status);
+               if (ret) {
+                       errno = ret;
+                       PERROR("pthread_join timer thread");
+                       retval = -1;
+               }
+       }
+
+       /*
+        * After the rotation and timer thread have quit, we can safely destroy
+        * the rotation_timer_queue.
+        */
+       destroy_rotate_timer_queue(rotation_timer_queue);
+
        rcu_thread_offline();
        rcu_unregister_thread();
 
This page took 0.029377 seconds and 5 git commands to generate.