Make app socket directories per-user v2
[ust.git] / libust / tracectl.c
index 7c054670e41de5a186f02f4c4bceb2b09bee8f16..ae92b7e17577f279d30456622842037d371455ca 100644 (file)
@@ -39,6 +39,7 @@
 #include <ust/marker.h>
 #include <ust/tracepoint.h>
 #include <ust/tracectl.h>
+#include <ust/clock.h>
 #include "tracer.h"
 #include "usterr.h"
 #include "ustcomm.h"
@@ -62,17 +63,27 @@ static char receive_buffer[USTCOMM_BUFFER_SIZE];
 static char send_buffer[USTCOMM_BUFFER_SIZE];
 
 static int epoll_fd;
+
+/*
+ * Listener thread data vs fork() protection mechanism. Ensures that no listener
+ * thread mutexes and data structures are being concurrently modified or held by
+ * other threads when fork() is executed.
+ */
+static pthread_mutex_t listener_thread_data_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* Mutex protecting listen_sock. Nests inside listener_thread_data_mutex. */
+static pthread_mutex_t listen_sock_mutex = PTHREAD_MUTEX_INITIALIZER;
 static struct ustcomm_sock *listen_sock;
 
 extern struct chan_info_struct chan_infos[];
 
-static struct cds_list_head open_buffers_list = CDS_LIST_HEAD_INIT(open_buffers_list);
-
 static struct cds_list_head ust_socks = CDS_LIST_HEAD_INIT(ust_socks);
 
 /* volatile because shared between the listener and the main thread */
 int buffers_to_export = 0;
 
+int ust_clock_source;
+
 static long long make_pidunique(void)
 {
        s64 retval;
@@ -97,11 +108,11 @@ static void print_markers(FILE *fp)
 
        while (iter.marker) {
                fprintf(fp, "marker: %s/%s %d \"%s\" %p\n",
-                       iter.marker->channel,
-                       iter.marker->name,
-                       (int)imv_read(iter.marker->state),
-                       iter.marker->format,
-                       iter.marker->location);
+                       (*iter.marker)->channel,
+                       (*iter.marker)->name,
+                       (int)imv_read((*iter.marker)->state),
+                       (*iter.marker)->format,
+                       (*iter.marker)->location);
                marker_iter_next(&iter);
        }
        unlock_markers();
@@ -116,16 +127,16 @@ static void print_trace_events(FILE *fp)
        trace_event_iter_start(&iter);
 
        while (iter.trace_event) {
-               fprintf(fp, "trace_event: %s\n", iter.trace_event->name);
+               fprintf(fp, "trace_event: %s\n", (*iter.trace_event)->name);
                trace_event_iter_next(&iter);
        }
        unlock_trace_events();
 }
 
-static int connect_ustd(void)
+static int connect_ustconsumer(void)
 {
        int result, fd;
-       char default_daemon_path[] = SOCK_DIR "/ustd";
+       char default_daemon_path[] = SOCK_DIR "/ustconsumer";
        char *explicit_daemon_path, *daemon_path;
 
        explicit_daemon_path = getenv("UST_DAEMON_SOCKET");
@@ -139,7 +150,7 @@ static int connect_ustd(void)
 
        result = ustcomm_connect_path(daemon_path, &fd);
        if (result < 0) {
-               WARN("connect_ustd failed, daemon_path: %s",
+               WARN("connect_ustconsumer failed, daemon_path: %s",
                     daemon_path);
                return result;
        }
@@ -194,12 +205,12 @@ static void inform_consumer_daemon(const char *trace_name)
        struct ust_trace *trace;
        const char *ch_name;
 
-       sock = connect_ustd();
+       sock = connect_ustconsumer();
        if (sock < 0) {
                return;
        }
 
-       DBG("Connected to ustd");
+       DBG("Connected to ustconsumer");
 
        ltt_lock_traces();
 
@@ -352,7 +363,7 @@ static int set_subbuf_size(const char *trace_name, const char *ch_name,
        }
 
        channel->subbuf_size = power;
-       DBG("the set_subbuf_size for the requested channel is %u", channel->subbuf_size);
+       DBG("the set_subbuf_size for the requested channel is %zu", channel->subbuf_size);
 
 unlock_traces:
        ltt_unlock_traces();
@@ -390,7 +401,7 @@ static int set_subbuf_num(const char *trace_name, const char *ch_name,
        }
 
        channel->subbuf_cnt = num;
-       DBG("the set_subbuf_cnt for the requested channel is %zd", channel->subbuf_cnt);
+       DBG("the set_subbuf_cnt for the requested channel is %u", channel->subbuf_cnt);
 
 unlock_traces:
        ltt_unlock_traces();
@@ -476,11 +487,6 @@ static int notify_buffer_mapped(const char *trace_name,
                CMM_STORE_SHARED(buffers_to_export, CMM_LOAD_SHARED(buffers_to_export)-1);
        }
 
-       /* The buffer has been exported, ergo, we can add it to the
-        * list of open buffers
-        */
-       cds_list_add(&buf->open_buffers_list, &open_buffers_list);
-
 unlock_traces:
        ltt_unlock_traces();
 
@@ -530,53 +536,46 @@ unlock_traces:
        return retval;
 }
 
-static void listener_cleanup(void *ptr)
+static void release_listener_mutex(void *ptr)
 {
-       ustcomm_del_named_sock(listen_sock, 0);
+       pthread_mutex_unlock(&listener_thread_data_mutex);
 }
 
-static void force_subbuf_switch()
+static void listener_cleanup(void *ptr)
 {
-       struct ust_buffer *buf;
-
-       cds_list_for_each_entry(buf, &open_buffers_list,
-                           open_buffers_list) {
-               ltt_force_switch(buf, FORCE_FLUSH);
+       pthread_mutex_lock(&listen_sock_mutex);
+       if (listen_sock) {
+               ustcomm_del_named_sock(listen_sock, 0);
+               listen_sock = NULL;
        }
+       pthread_mutex_unlock(&listen_sock_mutex);
 }
 
-/* Simple commands are those which need only respond with a return value. */
-static int process_simple_client_cmd(int command, char *recv_buf)
+static int force_subbuf_switch(const char *trace_name)
 {
-       switch(command) {
-       case SET_SOCK_PATH:
-       {
-               struct ustcomm_sock_path *sock_msg;
-               sock_msg = (struct ustcomm_sock_path *)recv_buf;
-               sock_msg->sock_path =
-                       ustcomm_restore_ptr(sock_msg->sock_path,
-                                           sock_msg->data,
-                                           sizeof(sock_msg->data));
-               if (!sock_msg->sock_path) {
-
-                       return -EINVAL;
-               }
-               return setenv("UST_DAEMON_SOCKET", sock_msg->sock_path, 1);
-       }
-
-       case FORCE_SUBBUF_SWITCH:
-               /* FIXME: return codes? */
-               force_subbuf_switch();
+       struct ust_trace *trace;
+       int i, j, retval = 0;
 
-               break;
+       ltt_lock_traces();
+       trace = _ltt_trace_find(trace_name);
+       if (!trace) {
+                retval = -ENODATA;
+                DBG("Cannot find trace. It was likely destroyed by the user.");
+                goto unlock_traces;
+        }
 
-       default:
-               return -EINVAL;
+       for (i = 0; i < trace->nr_channels; i++) {
+               for (j = 0; j < trace->channels[i].n_cpus; j++) {
+                       ltt_force_switch(trace->channels[i].buf[j],
+                                        FORCE_FLUSH);
+               }
        }
 
-       return 0;
-}
+unlock_traces:
+       ltt_unlock_traces();
 
+       return retval;
+}
 
 static int process_trace_cmd(int command, char *trace_name)
 {
@@ -695,6 +694,15 @@ static int process_trace_cmd(int command, char *trace_name)
                        return result;
                }
                return 0;
+       case FORCE_SUBBUF_SWITCH:
+               DBG("force switch");
+
+               result = force_subbuf_switch(trace_name);
+               if (result < 0) {
+                       ERR("force_subbuf_switch failed");
+                       return result;
+               }
+               return 0;
        }
 
        return 0;
@@ -827,7 +835,7 @@ static void process_marker_cmd(int sock, int command,
 {
        struct ustcomm_header _reply_header;
        struct ustcomm_header *reply_header = &_reply_header;
-       int result;
+       int result = 0;
 
        memset(reply_header, 0, sizeof(*reply_header));
 
@@ -936,7 +944,7 @@ static void process_client_cmd(struct ustcomm_header *recv_header,
                print_markers(fp);
                fclose(fp);
 
-               reply_header->size = size;
+               reply_header->size = size + 1;  /* Include final \0 */
 
                result = ustcomm_send(sock, reply_header, ptr);
 
@@ -962,7 +970,7 @@ static void process_client_cmd(struct ustcomm_header *recv_header,
                print_trace_events(fp);
                fclose(fp);
 
-               reply_header->size = size;
+               reply_header->size = size + 1;  /* Include final \0 */
 
                result = ustcomm_send(sock, reply_header, ptr);
 
@@ -999,27 +1007,42 @@ static void process_client_cmd(struct ustcomm_header *recv_header,
        }
        case GET_SOCK_PATH:
        {
-               struct ustcomm_sock_path *sock_msg;
+               struct ustcomm_single_field *sock_msg;
                char *sock_path_env;
 
-               sock_msg = (struct ustcomm_sock_path *)send_buf;
+               sock_msg = (struct ustcomm_single_field *)send_buf;
 
                sock_path_env = getenv("UST_DAEMON_SOCKET");
 
                if (!sock_path_env) {
-                       result = ustcomm_pack_sock_path(reply_header,
-                                                       sock_msg,
-                                                       SOCK_DIR "/ustd");
+                       result = ustcomm_pack_single_field(reply_header,
+                                                          sock_msg,
+                                                          SOCK_DIR "/ustconsumer");
 
                } else {
-                       result = ustcomm_pack_sock_path(reply_header,
-                                                       sock_msg,
-                                                       sock_path_env);
+                       result = ustcomm_pack_single_field(reply_header,
+                                                          sock_msg,
+                                                          sock_path_env);
                }
                reply_header->result = result;
 
                goto send_response;
        }
+       case SET_SOCK_PATH:
+       {
+               struct ustcomm_single_field *sock_msg;
+               sock_msg = (struct ustcomm_single_field *)recv_buf;
+               result = ustcomm_unpack_single_field(sock_msg);
+               if (result < 0) {
+                       reply_header->result = -EINVAL;
+                       goto send_response;
+               }
+
+               reply_header->result = setenv("UST_DAEMON_SOCKET",
+                                             sock_msg->field, 1);
+
+               goto send_response;
+       }
        case START:
        case SETUP_TRACE:
        case ALLOC_TRACE:
@@ -1027,11 +1050,12 @@ static void process_client_cmd(struct ustcomm_header *recv_header,
        case START_TRACE:
        case STOP_TRACE:
        case DESTROY_TRACE:
+       case FORCE_SUBBUF_SWITCH:
        {
-               struct ustcomm_trace_info *trace_inf =
-                       (struct ustcomm_trace_info *)recv_buf;
+               struct ustcomm_single_field *trace_inf =
+                       (struct ustcomm_single_field *)recv_buf;
 
-               result = ustcomm_unpack_trace_info(trace_inf);
+               result = ustcomm_unpack_single_field(trace_inf);
                if (result < 0) {
                        ERR("couldn't unpack trace info");
                        reply_header->result = -EINVAL;
@@ -1040,16 +1064,14 @@ static void process_client_cmd(struct ustcomm_header *recv_header,
 
                reply_header->result =
                        process_trace_cmd(recv_header->command,
-                                         trace_inf->trace);
+                                         trace_inf->field);
                goto send_response;
 
        }
        default:
-               reply_header->result =
-                       process_simple_client_cmd(recv_header->command,
-                                                 recv_buf);
-               goto send_response;
+               reply_header->result = -EINVAL;
 
+               goto send_response;
        }
 
        return;
@@ -1079,6 +1101,8 @@ void *listener_main(void *p)
                }
 
                for (i = 0; i < nfds; i++) {
+                       pthread_mutex_lock(&listener_thread_data_mutex);
+                       pthread_cleanup_push(release_listener_mutex, NULL);
                        epoll_sock = (struct ustcomm_sock *)events[i].data.ptr;
                        if (epoll_sock == listen_sock) {
                                addr_size = sizeof(struct sockaddr);
@@ -1107,6 +1131,7 @@ void *listener_main(void *p)
                                                           epoll_sock->fd);
                                }
                        }
+                       pthread_cleanup_pop(1); /* release listener mutex */
                }
        }
 
@@ -1196,41 +1221,46 @@ static void auto_probe_connect(struct marker *m)
 
 static struct ustcomm_sock * init_app_socket(int epoll_fd)
 {
-       char *name;
+       char *dir_name, *sock_name;
        int result;
-       struct ustcomm_sock *sock;
+       struct ustcomm_sock *sock = NULL;
+
+       dir_name = ustcomm_user_sock_dir();
+       if (!dir_name)
+               return NULL;
 
-       result = asprintf(&name, "%s/%d", SOCK_DIR, (int)getpid());
+       result = asprintf(&sock_name, "%s/%d", dir_name, (int)getpid());
        if (result < 0) {
                ERR("string overflow allocating socket name, "
                    "UST thread bailing");
-               return NULL;
+               goto free_dir_name;
        }
 
-       result = ensure_dir_exists(SOCK_DIR);
+       result = ensure_dir_exists(dir_name);
        if (result == -1) {
                ERR("Unable to create socket directory %s, UST thread bailing",
-                   SOCK_DIR);
-               goto free_name;
+                   dir_name);
+               goto free_sock_name;
        }
 
-       sock = ustcomm_init_named_socket(name, epoll_fd);
+       sock = ustcomm_init_named_socket(sock_name, epoll_fd);
        if (!sock) {
                ERR("Error initializing named socket (%s). Check that directory"
-                   "exists and that it is writable. UST thread bailing", name);
-               goto free_name;
+                   "exists and that it is writable. UST thread bailing", sock_name);
+               goto free_sock_name;
        }
 
-       free(name);
-       return sock;
+free_sock_name:
+       free(sock_name);
+free_dir_name:
+       free(dir_name);
 
-free_name:
-       free(name);
-       return NULL;
+       return sock;
 }
 
 static void __attribute__((constructor)) init()
 {
+       struct timespec ts;
        int result;
        char* autoprobe_val = NULL;
        char* subbuffer_size_val = NULL;
@@ -1264,6 +1294,15 @@ static void __attribute__((constructor)) init()
 
        create_listener();
 
+       /* Get clock the clock source type */
+
+       /* Default clock source */
+       ust_clock_source = CLOCK_TRACE;
+       if (clock_gettime(ust_clock_source, &ts) != 0) {
+               ust_clock_source = CLOCK_MONOTONIC;
+               DBG("UST traces will not be synchronized with LTTng traces");
+       }
+
        autoprobe_val = getenv("UST_AUTOPROBE");
        if (autoprobe_val) {
                struct marker_iter iter;
@@ -1303,8 +1342,8 @@ static void __attribute__((constructor)) init()
 
                DBG("now iterating on markers already registered");
                while (iter.marker) {
-                       DBG("now iterating on marker %s", iter.marker->name);
-                       auto_probe_connect(iter.marker);
+                       DBG("now iterating on marker %s", (*iter.marker)->name);
+                       auto_probe_connect(*iter.marker);
                        marker_iter_next(&iter);
                }
        }
@@ -1498,7 +1537,7 @@ static void stop_listener(void)
 }
 
 /* This destructor keeps the process alive for a few seconds in order
- * to leave time to ustd to connect to its buffers. This is necessary
+ * to leave time for ustconsumer to connect to its buffers. This is necessary
  * for programs whose execution is very short. It is also useful in all
  * programs when tracing is started close to the end of the program
  * execution.
@@ -1556,8 +1595,8 @@ void ust_potential_exec(void)
 
 static void ust_fork(void)
 {
-       struct ust_buffer *buf, *buf_tmp;
        struct ustcomm_sock *sock, *sock_tmp;
+       struct ust_trace *trace, *trace_tmp;
        int result;
 
        /* FIXME: technically, the locks could have been taken before the fork */
@@ -1566,32 +1605,32 @@ static void ust_fork(void)
        /* Get the pid of the new process */
        processpid = getpid();
 
-       /* break lock if necessary */
-       ltt_unlock_traces();
+       /*
+        * FIXME: This could be prettier, we loop over the list twice and
+        * following good locking practice should lock around the loop
+        */
+       cds_list_for_each_entry_safe(trace, trace_tmp, &ltt_traces.head, list) {
+               ltt_trace_stop(trace->trace_name);
+       }
 
-       ltt_trace_stop("auto");
-       ltt_trace_destroy("auto", 1);
        /* Delete all active connections, but leave them in the epoll set */
        cds_list_for_each_entry_safe(sock, sock_tmp, &ust_socks, list) {
                ustcomm_del_sock(sock, 1);
        }
 
-       /* Delete all blocked consumers */
-       cds_list_for_each_entry_safe(buf, buf_tmp, &open_buffers_list,
-                                open_buffers_list) {
-               result = close(buf->data_ready_fd_read);
-               if (result == -1) {
-                       PERROR("close");
-               }
-               result = close(buf->data_ready_fd_write);
-               if (result == -1) {
-                       PERROR("close");
-               }
-               cds_list_del(&buf->open_buffers_list);
+       /*
+        * FIXME: This could be prettier, we loop over the list twice and
+        * following good locking practice should lock around the loop
+        */
+       cds_list_for_each_entry_safe(trace, trace_tmp, &ltt_traces.head, list) {
+               ltt_trace_destroy(trace->trace_name, 1);
        }
 
-       /* Clean up the listener socket and epoll, keeping the scoket file */
-       ustcomm_del_named_sock(listen_sock, 1);
+       /* Clean up the listener socket and epoll, keeping the socket file */
+       if (listen_sock) {
+               ustcomm_del_named_sock(listen_sock, 1);
+               listen_sock = NULL;
+       }
        close(epoll_fd);
 
        /* Re-start the launch sequence */
@@ -1646,6 +1685,17 @@ void ust_before_fork(ust_fork_info_t *fork_info)
                 PERROR("sigprocmask");
                 return;
         }
+
+       /*
+        * Take the fork lock to make sure we are not in the middle of
+        * something in the listener thread.
+        */
+       pthread_mutex_lock(&listener_thread_data_mutex);
+       /*
+        * Hold listen_sock_mutex to protect from listen_sock teardown.
+        */
+       pthread_mutex_lock(&listen_sock_mutex);
+       rcu_bp_before_fork();
 }
 
 /* Don't call this function directly in a traced program */
@@ -1653,6 +1703,9 @@ static void ust_after_fork_common(ust_fork_info_t *fork_info)
 {
        int result;
 
+       pthread_mutex_unlock(&listen_sock_mutex);
+       pthread_mutex_unlock(&listener_thread_data_mutex);
+
         /* Restore signals */
         result = sigprocmask(SIG_SETMASK, &fork_info->orig_sigs, NULL);
         if (result == -1) {
@@ -1663,16 +1716,20 @@ static void ust_after_fork_common(ust_fork_info_t *fork_info)
 
 void ust_after_fork_parent(ust_fork_info_t *fork_info)
 {
-       /* Reenable signals */
+       rcu_bp_after_fork_parent();
+       /* Release mutexes and reenable signals */
        ust_after_fork_common(fork_info);
 }
 
 void ust_after_fork_child(ust_fork_info_t *fork_info)
 {
-       /* First sanitize the child */
+       /* Release urcu mutexes */
+       rcu_bp_after_fork_child();
+
+       /* Sanitize the child */
        ust_fork();
 
-       /* Then reenable interrupts */
+       /* Then release mutexes and reenable signals */
        ust_after_fork_common(fork_info);
 }
 
This page took 0.03147 seconds and 4 git commands to generate.