don't close file descriptors twice
[ust.git] / libust / tracectl.c
index 3cb86edc80180f535e8a5773d8413ee11032db64..e0b9370963a482a206be9b358d4705ecae727e9c 100644 (file)
 
 #define _GNU_SOURCE
 #include <stdio.h>
+#include <stdlib.h>
 #include <stdint.h>
 #include <signal.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/un.h>
-#include <sched.h>
 #include <fcntl.h>
 #include <poll.h>
 #include <regex.h>
-
-#include <urcu-bp.h>
+#include <urcu/uatomic_arch.h>
 
 #include <ust/marker.h>
 #include <ust/tracectl.h>
@@ -37,8 +36,6 @@
 #include "buffers.h"
 #include "marker-control.h"
 
-//#define USE_CLONE
-
 #define USTSIGNAL SIGIO
 
 #define MAX_MSG_SIZE (100)
@@ -125,15 +122,6 @@ static void print_markers(FILE *fp)
 
 static int init_socket(void);
 
-/* This needs to be called whenever a new thread is created. It notifies
- * liburcu of the new thread.
- */
-
-void ust_register_thread(void)
-{
-       rcu_register_thread();
-}
-
 int fd_notif = -1;
 void notif_cb(void)
 {
@@ -241,9 +229,13 @@ void process_blocked_consumers(void)
                                continue;
                        }
                        if(result == 0) {
+                               int res;
                                DBG("PRODUCER END");
 
-                               close(bc->fd_producer);
+                               res = close(bc->fd_producer);
+                               if(res == -1) {
+                                       PERROR("close");
+                               }
 
                                list_del(&bc->list);
 
@@ -357,10 +349,7 @@ static int do_cmd_get_shmid(const char *recvbuf, struct ustcomm_source *src)
                }
        }
 
-       if(found) {
-               buffers_to_export--;
-       }
-       else {
+       if(!found) {
                ERR("channel not found (%s)", channel_and_cpu);
        }
 
@@ -662,7 +651,7 @@ static int do_cmd_get_subbuffer(const char *recvbuf, struct ustcomm_source *src)
        if(trace == NULL) {
                int result;
 
-               WARN("Cannot find trace. It was likely destroyed by the user.");
+               DBG("Cannot find trace. It was likely destroyed by the user.");
                result = ustcomm_send_reply(&ustcomm_app.server, "NOTFOUND", src);
                if(result) {
                        ERR("ustcomm_send_reply failed");
@@ -695,6 +684,14 @@ static int do_cmd_get_subbuffer(const char *recvbuf, struct ustcomm_source *src)
 
                        list_add(&bc->list, &blocked_consumers);
 
+                       /* Being here is the proof the daemon has mapped the buffer in its
+                        * memory. We may now decrement buffers_to_export.
+                        */
+                       if(uatomic_read(&buf->consumed) == 0) {
+                               DBG("decrementing buffers_to_export");
+                               buffers_to_export--;
+                       }
+
                        break;
                }
        }
@@ -761,7 +758,7 @@ static int do_cmd_put_subbuffer(const char *recvbuf, struct ustcomm_source *src)
        trace = _ltt_trace_find(trace_name);
 
        if(trace == NULL) {
-               WARN("Cannot find trace. It was likely destroyed by the user.");
+               DBG("Cannot find trace. It was likely destroyed by the user.");
                result = ustcomm_send_reply(&ustcomm_app.server, "NOTFOUND", src);
                if(result) {
                        ERR("ustcomm_send_reply failed");
@@ -819,14 +816,19 @@ static int do_cmd_put_subbuffer(const char *recvbuf, struct ustcomm_source *src)
        return retval;
 }
 
+static void listener_cleanup(void *ptr)
+{
+       ustcomm_fini_app(&ustcomm_app, 0);
+}
+
 void *listener_main(void *p)
 {
        int result;
 
-       ust_register_thread();
-
        DBG("LISTENER");
 
+       pthread_cleanup_push(listener_cleanup, NULL);
+
        for(;;) {
                char trace_name[] = "auto";
                char trace_type[] = "ustrelay";
@@ -964,7 +966,7 @@ void *listener_main(void *p)
 
                        DBG("trace destroy");
 
-                       result = ltt_trace_destroy(trace_name);
+                       result = ltt_trace_destroy(trace_name, 0);
                        if(result < 0) {
                                ERR("ltt_trace_destroy failed");
                                return (void *)1;
@@ -1101,34 +1103,29 @@ void *listener_main(void *p)
        next_cmd:
                free(recvbuf);
        }
+
+       pthread_cleanup_pop(1);
 }
 
 volatile sig_atomic_t have_listener = 0;
+/* These should only be accessed in the parent thread,
+ * not the listener.
+ */
+static pthread_t listener_thread;
 
 void create_listener(void)
 {
-#ifdef USE_CLONE
-       static char listener_stack[16384];
        int result;
-#else
-       pthread_t thread;
-#endif
 
        if(have_listener) {
                WARN("not creating listener because we already had one");
                return;
        }
 
-#ifdef USE_CLONE
-       result = clone((int (*)(void *)) listener_main, listener_stack+sizeof(listener_stack)-1, CLONE_FS | CLONE_FILES | CLONE_VM | CLONE_SIGHAND | CLONE_THREAD, NULL);
+       result = pthread_create(&listener_thread, NULL, listener_main, NULL);
        if(result == -1) {
-               perror("clone");
-               return;
+               PERROR("pthread_create");
        }
-#else
-
-       pthread_create(&thread, NULL, listener_main, NULL);
-#endif
 
        have_listener = 1;
 }
@@ -1186,16 +1183,8 @@ static void __attribute__((constructor)) init()
         */
        pidunique = make_pidunique();
 
-       /* Initialize RCU in case the constructor order is not good. */
-       rcu_init();
-
-       /* It is important to do this before events start to be generated. */
-       ust_register_thread();
-
        DBG("Tracectl constructor");
 
-       /* Must create socket before signal handler to prevent races.
-         */
        result = init_socket();
        if(result == -1) {
                ERR("init_socket error");
@@ -1348,7 +1337,7 @@ static void destroy_traces(void)
                ERR("ltt_trace_stop error");
        }
 
-       result = ltt_trace_destroy("auto");
+       result = ltt_trace_destroy("auto", 0);
        if(result == -1) {
                ERR("ltt_trace_destroy error");
        }
@@ -1395,6 +1384,20 @@ int restarting_usleep(useconds_t usecs)
        return result;
 }
 
+static void stop_listener()
+{
+       int result;
+
+       result = pthread_cancel(listener_thread);
+       if(result == -1) {
+               PERROR("pthread_cancel");
+       }
+       result = pthread_join(listener_thread, NULL);
+       if(result == -1) {
+               PERROR("pthread_join");
+       }
+}
+
 /* 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
  * for programs whose execution is very short. It is also useful in all
@@ -1425,7 +1428,8 @@ static void __attribute__((destructor)) keepalive()
 
        destroy_traces();
 
-       ustcomm_fini_app(&ustcomm_app);
+       /* Ask the listener to stop and clean up. */
+       stop_listener();
 }
 
 void ust_potential_exec(void)
@@ -1453,24 +1457,35 @@ static void ust_fork(void)
        struct blocked_consumer *deletable_bc = NULL;
        int result;
 
+       /* FIXME: technically, the locks could have been taken before the fork */
        DBG("ust: forking");
+
+       /* break lock if necessary */
+       ltt_unlock_traces();
+
        ltt_trace_stop("auto");
-       ltt_trace_destroy("auto");
+       ltt_trace_destroy("auto", 1);
        /* Delete all active connections */
        ustcomm_close_all_connections(&ustcomm_app.server);
 
        /* Delete all blocked consumers */
        list_for_each_entry(bc, &blocked_consumers, list) {
-               close(bc->fd_producer);
-               close(bc->fd_consumer);
+               result = close(bc->fd_producer);
+               if(result == -1) {
+                       PERROR("close");
+               }
                free(deletable_bc);
                deletable_bc = bc;
                list_del(&bc->list);
        }
 
+       /* free app, keeping socket file */
+       ustcomm_fini_app(&ustcomm_app, 1);
+
+       buffers_to_export = 0;
        have_listener = 0;
-       create_listener();
        init_socket();
+       create_listener();
        ltt_trace_setup("auto");
        result = ltt_trace_set_type("auto", "ustrelay");
        if(result < 0) {
This page took 0.02727 seconds and 4 git commands to generate.