Fix off-by-one in open_memstream
[ust.git] / libust / tracectl.c
index 7c054670e41de5a186f02f4c4bceb2b09bee8f16..0cff6fda9f035e8a009232268530e8e39e206ab4 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,6 +63,16 @@ 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[];
@@ -73,6 +84,8 @@ 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 +110,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 +129,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 +152,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 +207,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 +365,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 +403,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();
@@ -530,9 +543,19 @@ unlock_traces:
        return retval;
 }
 
+static void release_listener_mutex(void *ptr)
+{
+       pthread_mutex_unlock(&listener_thread_data_mutex);
+}
+
 static void listener_cleanup(void *ptr)
 {
-       ustcomm_del_named_sock(listen_sock, 0);
+       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);
 }
 
 static void force_subbuf_switch()
@@ -548,20 +571,18 @@ static void force_subbuf_switch()
 /* Simple commands are those which need only respond with a return value. */
 static int process_simple_client_cmd(int command, char *recv_buf)
 {
+       int result;
+
        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;
+               struct ustcomm_single_field *sock_msg;
+               sock_msg = (struct ustcomm_single_field *)recv_buf;
+               result = ustcomm_unpack_single_field(sock_msg);
+               if (result < 0) {
+                       return result;
                }
-               return setenv("UST_DAEMON_SOCKET", sock_msg->sock_path, 1);
+               return setenv("UST_DAEMON_SOCKET", sock_msg->field, 1);
        }
 
        case FORCE_SUBBUF_SWITCH:
@@ -827,7 +848,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 +957,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 +983,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,22 +1020,22 @@ 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;
 
@@ -1028,10 +1049,10 @@ static void process_client_cmd(struct ustcomm_header *recv_header,
        case STOP_TRACE:
        case DESTROY_TRACE:
        {
-               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,7 +1061,7 @@ 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;
 
        }
@@ -1079,6 +1100,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 +1130,7 @@ void *listener_main(void *p)
                                                           epoll_sock->fd);
                                }
                        }
+                       pthread_cleanup_pop(1); /* release listener mutex */
                }
        }
 
@@ -1231,6 +1255,7 @@ free_name:
 
 static void __attribute__((constructor)) init()
 {
+       struct timespec ts;
        int result;
        char* autoprobe_val = NULL;
        char* subbuffer_size_val = NULL;
@@ -1264,6 +1289,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 +1337,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 +1532,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.
@@ -1558,6 +1592,7 @@ 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,11 +1601,14 @@ 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);
@@ -1579,19 +1617,22 @@ static void ust_fork(void)
        /* 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);
        }
 
-       /* Clean up the listener socket and epoll, keeping the scoket file */
-       ustcomm_del_named_sock(listen_sock, 1);
+       /*
+        * 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 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 +1687,16 @@ 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);
 }
 
 /* Don't call this function directly in a traced program */
@@ -1653,6 +1704,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,7 +1717,7 @@ 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 */
+       /* Release mutexes and reenable signals */
        ust_after_fork_common(fork_info);
 }
 
@@ -1672,7 +1726,15 @@ void ust_after_fork_child(ust_fork_info_t *fork_info)
        /* First sanitize the child */
        ust_fork();
 
-       /* Then reenable interrupts */
+       /* Then release mutexes and reenable signals */
        ust_after_fork_common(fork_info);
+
+       /*
+        * Make sure we clean up the urcu-bp thread list in the child by running
+        * the garbage collection before any pthread_create can be called.
+        * Failure to do so could lead to a deadlock caused by reuse of a thread
+        * ID before urcu-bp garbage collection is performed.
+        */
+       synchronize_rcu();
 }
 
This page took 0.029221 seconds and 4 git commands to generate.