Update version to 0.16
[ust.git] / libust / tracectl.c
index f720244530c9f60b77f5978875f712a5ea69658a..410b1c72e75cb52a2fd24a2898c590f31c011455 100644 (file)
@@ -21,6 +21,7 @@
  */
 
 #define _GNU_SOURCE
+#define _LGPL_SOURCE
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdint.h>
 #include <fcntl.h>
 #include <poll.h>
 #include <regex.h>
-#include <urcu/uatomic_arch.h>
+#include <urcu/uatomic.h>
 #include <urcu/list.h>
 
 #include <ust/marker.h>
 #include <ust/tracepoint.h>
+#include <ust/tracepoint-internal.h>
 #include <ust/tracectl.h>
 #include <ust/clock.h>
 #include "tracer.h"
-#include "usterr.h"
+#include "usterr_signal_safe.h"
 #include "ustcomm.h"
 #include "buffers.h"
 #include "marker-control.h"
@@ -63,12 +65,20 @@ 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 */
@@ -90,31 +100,32 @@ static long long make_pidunique(void)
        return retval;
 }
 
-static void print_markers(FILE *fp)
+static void print_ust_marker(FILE *fp)
 {
-       struct marker_iter iter;
-
-       lock_markers();
-       marker_iter_reset(&iter);
-       marker_iter_start(&iter);
-
-       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);
-               marker_iter_next(&iter);
-       }
-       unlock_markers();
+       struct ust_marker_iter iter;
+
+       ust_marker_iter_reset(&iter);
+       ust_marker_iter_start(&iter);
+
+       while (iter.ust_marker) {
+               fprintf(fp, "ust_marker: %s/%s %d \"%s\" %p\n",
+                       (*iter.ust_marker)->channel,
+                       (*iter.ust_marker)->name,
+                       (int)(*iter.ust_marker)->state,
+                       (*iter.ust_marker)->format,
+                       NULL);  /*
+                                * location is null for now, will be added
+                                * to a different table.
+                                */
+               ust_marker_iter_next(&iter);
+       }
+       ust_marker_iter_stop(&iter);
 }
 
 static void print_trace_events(FILE *fp)
 {
        struct trace_event_iter iter;
 
-       lock_trace_events();
        trace_event_iter_reset(&iter);
        trace_event_iter_start(&iter);
 
@@ -122,7 +133,7 @@ static void print_trace_events(FILE *fp)
                fprintf(fp, "trace_event: %s\n", (*iter.trace_event)->name);
                trace_event_iter_next(&iter);
        }
-       unlock_trace_events();
+       trace_event_iter_stop(&iter);
 }
 
 static int connect_ustconsumer(void)
@@ -479,11 +490,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();
 
@@ -533,52 +539,47 @@ 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)
 {
-       int result;
+       struct ust_trace *trace;
+       int i, j, retval = 0;
 
-       switch(command) {
-       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) {
-                       return result;
+       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;
+        }
+
+       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 setenv("UST_DAEMON_SOCKET", sock_msg->field, 1);
        }
 
-       case FORCE_SUBBUF_SWITCH:
-               /* FIXME: return codes? */
-               force_subbuf_switch();
-
-               break;
-
-       default:
-               return -EINVAL;
-       }
+unlock_traces:
+       ltt_unlock_traces();
 
-       return 0;
+       return retval;
 }
 
-
 static int process_trace_cmd(int command, char *trace_name)
 {
        int result;
@@ -696,6 +697,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;
@@ -823,8 +833,8 @@ static void process_buffer_cmd(int sock, int command,
 
 }
 
-static void process_marker_cmd(int sock, int command,
-                              struct ustcomm_marker_info *marker_inf)
+static void process_ust_marker_cmd(int sock, int command,
+                              struct ustcomm_ust_marker_info *ust_marker_inf)
 {
        struct ustcomm_header _reply_header;
        struct ustcomm_header *reply_header = &_reply_header;
@@ -835,26 +845,26 @@ static void process_marker_cmd(int sock, int command,
        switch(command) {
        case ENABLE_MARKER:
 
-               result = ltt_marker_connect(marker_inf->channel,
-                                           marker_inf->marker,
+               result = ltt_ust_marker_connect(ust_marker_inf->channel,
+                                           ust_marker_inf->ust_marker,
                                            "default");
                if (result < 0) {
-                       WARN("could not enable marker; channel=%s,"
+                       WARN("could not enable ust_marker; channel=%s,"
                             " name=%s",
-                            marker_inf->channel,
-                            marker_inf->marker);
+                            ust_marker_inf->channel,
+                            ust_marker_inf->ust_marker);
 
                }
                break;
        case DISABLE_MARKER:
-               result = ltt_marker_disconnect(marker_inf->channel,
-                                              marker_inf->marker,
+               result = ltt_ust_marker_disconnect(ust_marker_inf->channel,
+                                              ust_marker_inf->ust_marker,
                                               "default");
                if (result < 0) {
-                       WARN("could not disable marker; channel=%s,"
+                       WARN("could not disable ust_marker; channel=%s,"
                             " name=%s",
-                            marker_inf->channel,
-                            marker_inf->marker);
+                            ust_marker_inf->channel,
+                            ust_marker_inf->ust_marker);
                }
                break;
        }
@@ -912,15 +922,15 @@ static void process_client_cmd(struct ustcomm_header *recv_header,
        case ENABLE_MARKER:
        case DISABLE_MARKER:
        {
-               struct ustcomm_marker_info *marker_inf;
-               marker_inf = (struct ustcomm_marker_info *)recv_buf;
-               result = ustcomm_unpack_marker_info(marker_inf);
+               struct ustcomm_ust_marker_info *ust_marker_inf;
+               ust_marker_inf = (struct ustcomm_ust_marker_info *)recv_buf;
+               result = ustcomm_unpack_ust_marker_info(ust_marker_inf);
                if (result < 0) {
-                       ERR("couldn't unpack marker info");
+                       ERR("couldn't unpack ust_marker info");
                        reply_header->result = -EINVAL;
                        goto send_response;
                }
-               process_marker_cmd(sock, recv_header->command, marker_inf);
+               process_ust_marker_cmd(sock, recv_header->command, ust_marker_inf);
                return;
        }
        case LIST_MARKERS:
@@ -934,17 +944,17 @@ static void process_client_cmd(struct ustcomm_header *recv_header,
                        ERR("opening memstream failed");
                        return;
                }
-               print_markers(fp);
+               print_ust_marker(fp);
                fclose(fp);
 
-               reply_header->size = size;
+               reply_header->size = size + 1;  /* Include final \0 */
 
                result = ustcomm_send(sock, reply_header, ptr);
 
                free(ptr);
 
                if (result < 0) {
-                       PERROR("failed to send markers list");
+                       PERROR("failed to send ust_marker list");
                }
 
                break;
@@ -963,7 +973,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);
 
@@ -1021,6 +1031,21 @@ static void process_client_cmd(struct ustcomm_header *recv_header,
 
                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:
@@ -1028,6 +1053,7 @@ 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_single_field *trace_inf =
                        (struct ustcomm_single_field *)recv_buf;
@@ -1046,11 +1072,9 @@ static void process_client_cmd(struct ustcomm_header *recv_header,
 
        }
        default:
-               reply_header->result =
-                       process_simple_client_cmd(recv_header->command,
-                                                 recv_buf);
-               goto send_response;
+               reply_header->result = -EINVAL;
 
+               goto send_response;
        }
 
        return;
@@ -1080,6 +1104,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);
@@ -1108,6 +1134,7 @@ void *listener_main(void *p)
                                                           epoll_sock->fd);
                                }
                        }
+                       pthread_cleanup_pop(1); /* release listener mutex */
                }
        }
 
@@ -1164,7 +1191,7 @@ void create_listener(void)
 static int autoprobe_method = AUTOPROBE_DISABLED;
 static regex_t autoprobe_regex;
 
-static void auto_probe_connect(struct marker *m)
+static void auto_probe_connect(struct ust_marker *m)
 {
        int result;
 
@@ -1176,7 +1203,7 @@ static void auto_probe_connect(struct marker *m)
        } else if (autoprobe_method == AUTOPROBE_ENABLE_REGEX) {
                result = asprintf(&concat_name, "%s/%s", m->channel, m->name);
                if (result == -1) {
-                       ERR("auto_probe_connect: asprintf failed (marker %s/%s)",
+                       ERR("auto_probe_connect: asprintf failed (ust_marker %s/%s)",
                                m->channel, m->name);
                        return;
                }
@@ -1187,47 +1214,58 @@ static void auto_probe_connect(struct marker *m)
                free(concat_name);
        }
 
-       result = ltt_marker_connect(m->channel, m->name, probe_name);
+       result = ltt_ust_marker_connect(m->channel, m->name, probe_name);
        if (result && result != -EEXIST)
-               ERR("ltt_marker_connect (marker = %s/%s, errno = %d)", m->channel, m->name, -result);
+               ERR("ltt_ust_marker_connect (ust_marker = %s/%s, errno = %d)", m->channel, m->name, -result);
 
-       DBG("auto connected marker %s (addr: %p) %s to probe default", m->channel, m, m->name);
+       DBG("auto connected ust_marker %s (addr: %p) %s to probe default", m->channel, m, m->name);
 
 }
 
 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;
+       time_t mtime;
+
+       dir_name = ustcomm_user_sock_dir();
+       if (!dir_name)
+               return NULL;
+
+       mtime = ustcomm_pid_st_mtime(getpid());
+       if (!mtime) {
+               goto free_dir_name;
+       }
 
-       result = asprintf(&name, "%s/%d", SOCK_DIR, (int)getpid());
+       result = asprintf(&sock_name, "%s/%d.%ld", dir_name,
+                         (int) getpid(), (long) mtime);
        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, S_IRWXU);
        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()
@@ -1275,20 +1313,19 @@ static void __attribute__((constructor)) init()
                DBG("UST traces will not be synchronized with LTTng traces");
        }
 
+       if (getenv("UST_TRACE") || getenv("UST_AUTOPROBE")) {
+               /* Ensure ust_marker control is initialized */
+               init_ust_marker_control();
+       }
+
        autoprobe_val = getenv("UST_AUTOPROBE");
        if (autoprobe_val) {
-               struct marker_iter iter;
+               struct ust_marker_iter iter;
 
                DBG("Autoprobe enabled.");
 
-               /* Ensure markers are initialized */
-               //init_markers();
-
-               /* Ensure marker control is initialized, for the probe */
-               init_marker_control();
-
                /* first, set the callback that will connect the
-                * probe on new markers
+                * probe on new ust_marker
                 */
                if (autoprobe_val[0] == '/') {
                        result = regcomp(&autoprobe_regex, autoprobe_val+1, 0);
@@ -1306,18 +1343,19 @@ static void __attribute__((constructor)) init()
                        autoprobe_method = AUTOPROBE_ENABLE_ALL;
                }
 
-               marker_set_new_marker_cb(auto_probe_connect);
+               ust_marker_set_new_ust_marker_cb(auto_probe_connect);
 
                /* Now, connect the probes that were already registered. */
-               marker_iter_reset(&iter);
-               marker_iter_start(&iter);
-
-               DBG("now iterating on markers already registered");
-               while (iter.marker) {
-                       DBG("now iterating on marker %s", (*iter.marker)->name);
-                       auto_probe_connect(*iter.marker);
-                       marker_iter_next(&iter);
+               ust_marker_iter_reset(&iter);
+               ust_marker_iter_start(&iter);
+
+               DBG("now iterating on ust_marker already registered");
+               while (iter.ust_marker) {
+                       DBG("now iterating on ust_marker %s", (*iter.ust_marker)->name);
+                       auto_probe_connect(*iter.ust_marker);
+                       ust_marker_iter_next(&iter);
                }
+               ust_marker_iter_stop(&iter);
        }
 
        if (getenv("UST_OVERWRITE")) {
@@ -1361,19 +1399,13 @@ static void __attribute__((constructor)) init()
 
                DBG("starting early tracing");
 
-               /* Ensure marker control is initialized */
-               init_marker_control();
-
-               /* Ensure markers are initialized */
-               init_markers();
-
                /* Ensure buffers are initialized, for the transport to be available.
                 * We are about to set a trace type and it will fail without this.
                 */
                init_ustrelay_transport();
 
                /* FIXME: When starting early tracing (here), depending on the
-                * order of constructors, it is very well possible some marker
+                * order of constructors, it is very well possible some ust_marker
                 * sections are not yet registered. Because of this, some
                 * channels may not be registered. Yet, we are about to ask the
                 * daemon to collect the channels. Channels which are not yet
@@ -1548,7 +1580,7 @@ static void __attribute__((destructor)) keepalive()
 
 void ust_potential_exec(void)
 {
-       trace_mark(ust, potential_exec, MARK_NOARGS);
+       ust_marker(potential_exec, UST_MARKER_NOARGS);
 
        DBG("test");
 
@@ -1567,7 +1599,6 @@ 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;
@@ -1578,9 +1609,6 @@ 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
@@ -1594,12 +1622,6 @@ static void ust_fork(void)
                ustcomm_del_sock(sock, 1);
        }
 
-       /* Delete all blocked consumers */
-       cds_list_for_each_entry_safe(buf, buf_tmp, &open_buffers_list,
-                                open_buffers_list) {
-               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
@@ -1608,8 +1630,11 @@ static void ust_fork(void)
                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 */
@@ -1664,6 +1689,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 */
@@ -1671,6 +1707,8 @@ 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) {
@@ -1681,16 +1719,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 */
+       /* Release mutexes and reenable signals */
        ust_after_fork_common(fork_info);
 }
 
This page took 0.031171 seconds and 4 git commands to generate.