Change malloc to zmalloc for libust
[ust.git] / libust / tracectl.c
index 39756a55fec0e72602479593fce153408fc950d5..e64b26f7cf85dc6ad2718d508f0e95d2cd226c8d 100644 (file)
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
  */
 
+/* This file contains the implementation of the UST listener thread, which
+ * receives trace control commands. It also coordinates the initialization of
+ * libust.
+ */
+
 #define _GNU_SOURCE
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdint.h>
+#include <pthread.h>
 #include <signal.h>
 #include <sys/types.h>
 #include <sys/socket.h>
@@ -48,6 +54,8 @@
  */
 s64 pidunique = -1LL;
 
+extern struct chan_info_struct chan_infos[];
+
 struct list_head blocked_consumers = LIST_HEAD_INIT(blocked_consumers);
 
 static struct ustcomm_app ustcomm_app;
@@ -148,7 +156,11 @@ static void inform_consumer_daemon(const char *trace_name)
                        /* iterate on all cpus */
                        for(j=0; j<trace->channels[i].n_cpus; j++) {
                                char *buf;
-                               asprintf(&buf, "%s_%d", trace->channels[i].channel_name, j);
+                               if (asprintf(&buf, "%s_%d", trace->channels[i].channel_name, j) < 0) {
+                                       ERR("inform_consumer_daemon : asprintf failed (%s_%d)",
+                                          trace->channels[i].channel_name, j);
+                                       goto finish;
+                               }
                                result = ustcomm_request_consumer(pid, buf);
                                if(result == -1) {
                                        WARN("Failed to request collection for channel %s. Is the daemon available?", trace->channels[i].channel_name);
@@ -205,7 +217,11 @@ int process_blkd_consumer_act(void *priv, int fd, short events)
        else if(result < 0) {
                ERR("ust_buffers_get_subbuf: error: %s", strerror(-result));
        }
-       asprintf(&reply, "%s %ld", "OK", consumed_old);
+       if (asprintf(&reply, "%s %ld", "OK", consumed_old) < 0) {
+               ERR("process_blkd_consumer_act : asprintf failed (OK %ld)",
+                  consumed_old);
+               return -1;
+       }
        result = ustcomm_send_reply(&bc->server, reply, &bc->src);
        if(result < 0) {
                ERR("ustcomm_send_reply failed");
@@ -242,7 +258,11 @@ void seperate_channel_cpu(const char *channel_and_cpu, char **channel, int *cpu)
                *cpu = atoi(sep+1);
        }
 
-       asprintf(channel, "%.*s", (int)(sep-channel_and_cpu), channel_and_cpu);
+       if (asprintf(channel, "%.*s", (int)(sep-channel_and_cpu), channel_and_cpu) < 0) {
+               ERR("seperate_channel_cpu : asprintf failed (%.*s)",
+                   (int)(sep-channel_and_cpu), channel_and_cpu);
+               return;
+       }
 }
 
 static int do_cmd_get_shmid(const char *recvbuf, struct ustcomm_source *src)
@@ -262,12 +282,14 @@ static int do_cmd_get_shmid(const char *recvbuf, struct ustcomm_source *src)
        channel_and_cpu = nth_token(recvbuf, 1);
        if(channel_and_cpu == NULL) {
                ERR("cannot parse channel");
+               retval = -1;
                goto end;
        }
 
        seperate_channel_cpu(channel_and_cpu, &ch_name, &ch_cpu);
        if(ch_cpu == -1) {
                ERR("problem parsing channel name");
+               retval = -1;
                goto free_short_chan_name;
        }
 
@@ -290,7 +312,12 @@ static int do_cmd_get_shmid(const char *recvbuf, struct ustcomm_source *src)
 
 //                     DBG("the shmid for the requested channel is %d", buf->shmid);
 //                     DBG("the shmid for its buffer structure is %d", channel->buf_struct_shmids);
-                       asprintf(&reply, "%d %d", buf->shmid, channel->buf_struct_shmids[ch_cpu]);
+                       if (asprintf(&reply, "%d %d", buf->shmid, channel->buf_struct_shmids[ch_cpu]) < 0) {
+                               ERR("do_cmd_get_shmid : asprintf failed (%d %d)",
+                                   buf->shmid, channel->buf_struct_shmids[ch_cpu]);
+                               retval = -1;
+                               goto free_short_chan_name;
+                       }
 
                        result = ustcomm_send_reply(&ustcomm_app.server, reply, src);
                        if(result) {
@@ -335,12 +362,14 @@ static int do_cmd_get_n_subbufs(const char *recvbuf, struct ustcomm_source *src)
        channel_and_cpu = nth_token(recvbuf, 1);
        if(channel_and_cpu == NULL) {
                ERR("cannot parse channel");
+               retval = -1;
                goto end;
        }
 
        seperate_channel_cpu(channel_and_cpu, &ch_name, &ch_cpu);
        if(ch_cpu == -1) {
                ERR("problem parsing channel name");
+               retval = -1;
                goto free_short_chan_name;
        }
 
@@ -361,7 +390,12 @@ static int do_cmd_get_n_subbufs(const char *recvbuf, struct ustcomm_source *src)
                        char *reply;
 
                        DBG("the n_subbufs for the requested channel is %d", channel->subbuf_cnt);
-                       asprintf(&reply, "%d", channel->subbuf_cnt);
+                       if (asprintf(&reply, "%d", channel->subbuf_cnt) < 0) {
+                               ERR("do_cmd_get_n_subbufs : asprintf failed (%d)",
+                                   channel->subbuf_cnt);
+                               retval = -1;
+                               goto free_short_chan_name;
+                       }
 
                        result = ustcomm_send_reply(&ustcomm_app.server, reply, src);
                        if(result) {
@@ -404,12 +438,14 @@ static int do_cmd_get_subbuf_size(const char *recvbuf, struct ustcomm_source *sr
        channel_and_cpu = nth_token(recvbuf, 1);
        if(channel_and_cpu == NULL) {
                ERR("cannot parse channel");
+               retval = -1;
                goto end;
        }
 
        seperate_channel_cpu(channel_and_cpu, &ch_name, &ch_cpu);
        if(ch_cpu == -1) {
                ERR("problem parsing channel name");
+               retval = -1;
                goto free_short_chan_name;
        }
 
@@ -430,7 +466,12 @@ static int do_cmd_get_subbuf_size(const char *recvbuf, struct ustcomm_source *sr
                        char *reply;
 
                        DBG("the subbuf_size for the requested channel is %zd", channel->subbuf_size);
-                       asprintf(&reply, "%zd", channel->subbuf_size);
+                       if (asprintf(&reply, "%zd", channel->subbuf_size) < 0) {
+                               ERR("do_cmd_get_subbuf_size : asprintf failed (%zd)",
+                                   channel->subbuf_size);
+                               retval = -1;
+                               goto free_short_chan_name;
+                       }
 
                        result = ustcomm_send_reply(&ustcomm_app.server, reply, src);
                        if(result) {
@@ -456,18 +497,17 @@ static int do_cmd_get_subbuf_size(const char *recvbuf, struct ustcomm_source *sr
        return retval;
 }
 
-static unsigned int poweroftwo(unsigned int x)
-{
-    unsigned int power2 = 1;
-    unsigned int hardcoded = 2147483648u; /* FIX max 2^31 */
-
-    if (x < 2)
-        return 2;
+/* Return the power of two which is equal or higher to v */
 
-    while (power2 < x && power2 < hardcoded)
-        power2 *= 2;
+static unsigned int pow2_higher_or_eq(unsigned int v)
+{
+       int hb = fls(v);
+       int retval = 1<<(hb-1);
 
-    return power2;
+       if(v-retval == 0)
+               return retval;
+       else
+               return retval<<1;
 }
 
 static int do_cmd_set_subbuf_size(const char *recvbuf, struct ustcomm_source *src)
@@ -488,12 +528,14 @@ static int do_cmd_set_subbuf_size(const char *recvbuf, struct ustcomm_source *sr
 
        if(ch_name == NULL) {
                ERR("cannot parse channel");
+               retval = -1;
                goto end;
        }
 
-       power = poweroftwo(size);
+       power = pow2_higher_or_eq(size);
+       power = max_t(unsigned int, 2u, power);
        if (power != size)
-               WARN("using the next 2^n = %u\n", power);
+               WARN("using the next power of two for buffer size = %u\n", power);
 
        ltt_lock_traces();
        trace = _ltt_trace_find_setup(trace_name);
@@ -542,10 +584,12 @@ static int do_cmd_set_subbuf_num(const char *recvbuf, struct ustcomm_source *src
 
        if(ch_name == NULL) {
                ERR("cannot parse channel");
+               retval = -1;
                goto end;
        }
        if (num < 2) {
                ERR("subbuffer count should be greater than 2");
+               retval = -1;
                goto end;
        }
 
@@ -594,12 +638,14 @@ static int do_cmd_get_subbuffer(const char *recvbuf, struct ustcomm_source *src)
        channel_and_cpu = nth_token(recvbuf, 1);
        if(channel_and_cpu == NULL) {
                ERR("cannot parse channel");
+               retval = -1;
                goto end;
        }
 
        seperate_channel_cpu(channel_and_cpu, &ch_name, &ch_cpu);
        if(ch_cpu == -1) {
                ERR("problem parsing channel name");
+               retval = -1;
                goto free_short_chan_name;
        }
 
@@ -629,9 +675,9 @@ static int do_cmd_get_subbuffer(const char *recvbuf, struct ustcomm_source *src)
 
                        found = 1;
 
-                       bc = (struct blocked_consumer *) malloc(sizeof(struct blocked_consumer));
+                       bc = (struct blocked_consumer *) zmalloc(sizeof(struct blocked_consumer));
                        if(bc == NULL) {
-                               ERR("malloc returned NULL");
+                               ERR("zmalloc returned NULL");
                                goto unlock_traces;
                        }
                        bc->fd_consumer = src->fd;
@@ -738,11 +784,19 @@ static int do_cmd_put_subbuffer(const char *recvbuf, struct ustcomm_source *src)
                        result = ust_buffers_put_subbuf(buf, consumed_old);
                        if(result < 0) {
                                WARN("ust_buffers_put_subbuf: error (subbuf=%s)", channel_and_cpu);
-                               asprintf(&reply, "%s", "ERROR");
+                               if (asprintf(&reply, "%s", "ERROR") < 0) {
+                                       ERR("do_cmd_put_subbuffer : asprintf failed (ERROR)");
+                                       retval = -1;
+                                       goto unlock_traces;
+                               }
                        }
                        else {
                                DBG("ust_buffers_put_subbuf: success (subbuf=%s)", channel_and_cpu);
-                               asprintf(&reply, "%s", "OK");
+                               if (asprintf(&reply, "%s", "OK") < 0) {
+                                       ERR("do_cmd_put_subbuffer : asprintf failed (OK)");
+                                       retval = -1;
+                                       goto unlock_traces;
+                               }
                        }
 
                        result = ustcomm_send_reply(&ustcomm_app.server, reply, src);
@@ -779,6 +833,15 @@ static void listener_cleanup(void *ptr)
        ustcomm_fini_app(&ustcomm_app, 0);
 }
 
+static void do_cmd_force_switch()
+{
+       struct blocked_consumer *bc;
+
+       list_for_each_entry(bc, &blocked_consumers, list) {
+               ltt_force_switch(bc->buf, FORCE_FLUSH);
+       }
+}
+
 int process_client_cmd(char *recvbuf, struct ustcomm_source *src)
 {
        int result;
@@ -975,7 +1038,11 @@ int process_client_cmd(char *recvbuf, struct ustcomm_source *src)
        else if(nth_token_is(recvbuf, "get_pidunique", 0) == 1) {
                char *reply;
 
-               asprintf(&reply, "%lld", pidunique);
+               if (asprintf(&reply, "%lld", pidunique) < 0) {
+                       ERR("process_client_cmd : asprintf failed (%lld)",
+                           pidunique);
+                       goto next_cmd;
+               }
 
                result = ustcomm_send_reply(&ustcomm_app.server, reply, src);
                if(result) {
@@ -985,6 +1052,32 @@ int process_client_cmd(char *recvbuf, struct ustcomm_source *src)
 
                free(reply);
        }
+       else if(nth_token_is(recvbuf, "get_sock_path", 0) == 1) {
+               char *reply = getenv("UST_DAEMON_SOCKET");
+               if(!reply) {
+                       if (asprintf(&reply, "%s/%s", SOCK_DIR, "ustd") < 0) {
+                               ERR("process_client_cmd : asprintf failed (%s/ustd)",
+                                   SOCK_DIR);
+                               goto next_cmd;
+                       }
+                       result = ustcomm_send_reply(&ustcomm_app.server, reply, src);
+                       free(reply);
+               }
+               else {
+                       result = ustcomm_send_reply(&ustcomm_app.server, reply, src);
+               }
+               if(result)
+                       ERR("ustcomm_send_reply failed");
+       }
+       else if(nth_token_is(recvbuf, "set_sock_path", 0) == 1) {
+               char *sock_path = nth_token(recvbuf, 1);
+               result = setenv("UST_DAEMON_SOCKET", sock_path, 1);
+               if(result)
+                       ERR("cannot set UST_DAEMON_SOCKET environment variable");
+       }
+       else if(nth_token_is(recvbuf, "force_switch", 0) == 1) {
+               do_cmd_force_switch();
+       }
        else {
                ERR("unable to parse message: %s", recvbuf);
        }
@@ -1030,18 +1123,40 @@ static pthread_t listener_thread;
 void create_listener(void)
 {
        int result;
+       sigset_t sig_all_blocked;
+       sigset_t orig_parent_mask;
 
        if(have_listener) {
                WARN("not creating listener because we already had one");
                return;
        }
 
+       /* A new thread created by pthread_create inherits the signal mask
+        * from the parent. To avoid any signal being received by the
+        * listener thread, we block all signals temporarily in the parent,
+        * while we create the listener thread.
+        */
+
+       sigfillset(&sig_all_blocked);
+
+       result = pthread_sigmask(SIG_SETMASK, &sig_all_blocked, &orig_parent_mask);
+       if(result) {
+               PERROR("pthread_sigmask: %s", strerror(result));
+       }
+
        result = pthread_create(&listener_thread, NULL, listener_main, NULL);
        if(result == -1) {
                PERROR("pthread_create");
        }
 
-       have_listener = 1;
+       /* Restore original signal mask in parent */
+       result = pthread_sigmask(SIG_SETMASK, &orig_parent_mask, NULL);
+       if(result) {
+               PERROR("pthread_sigmask: %s", strerror(result));
+       }
+       else {
+               have_listener = 1;
+       }
 }
 
 static int init_socket(void)
@@ -1091,6 +1206,11 @@ static void __attribute__((constructor)) init()
 {
        int result;
        char* autoprobe_val = NULL;
+       char* subbuffer_size_val = NULL;
+       char* subbuffer_count_val = NULL;
+       unsigned int subbuffer_size;
+       unsigned int subbuffer_count;
+       unsigned int power;
 
        /* Assign the pidunique, to be able to differentiate the processes with same
         * pid, (before and after an exec).
@@ -1174,6 +1294,23 @@ static void __attribute__((constructor)) init()
                }
        }
 
+       subbuffer_size_val = getenv("UST_SUBBUF_SIZE");
+       if(subbuffer_size_val) {
+               sscanf(subbuffer_size_val, "%u", &subbuffer_size);
+               power = pow2_higher_or_eq(subbuffer_size);
+               if(power != subbuffer_size)
+                       WARN("using the next power of two for buffer size = %u\n", power);
+               chan_infos[LTT_CHANNEL_UST].def_subbufsize = power;
+       }
+
+       subbuffer_count_val = getenv("UST_SUBBUF_NUM");
+       if(subbuffer_count_val) {
+               sscanf(subbuffer_count_val, "%u", &subbuffer_count);
+               if(subbuffer_count < 2)
+                       subbuffer_count = 2;
+               chan_infos[LTT_CHANNEL_UST].def_subbufcount = subbuffer_count;
+       }
+
        if(getenv("UST_TRACE")) {
                char trace_name[] = "auto";
                char trace_type[] = "ustrelay";
@@ -1240,7 +1377,6 @@ static void __attribute__((constructor)) init()
                inform_consumer_daemon(trace_name);
        }
 
-
        return;
 
        /* should decrementally destroy stuff if error */
@@ -1318,10 +1454,13 @@ int restarting_usleep(useconds_t usecs)
        return result;
 }
 
-static void stop_listener()
+static void stop_listener(void)
 {
        int result;
 
+       if(!have_listener)
+               return;
+
        result = pthread_cancel(listener_thread);
        if(result != 0) {
                ERR("pthread_cancel: %s", strerror(result));
This page took 0.038704 seconds and 4 git commands to generate.