Implement ioctl-alike communication
[lttng-ust.git] / libust / lttng-ust-comm.c
index c9cb777709dab0d84ffffebe26352fcfdfbde563..037b314765ab12b6974f1ca26e294d1771fde504 100644 (file)
 #include <lttng-ust-comm.h>
 #include <ust/usterr-signal-safe.h>
 #include <pthread.h>
+#include <assert.h>
+
+/*
+ * communication thread mutex. Held when handling a command, also held
+ * by fork() to deal with removal of threads, and by exit path.
+ */
+static pthread_mutex_t lttng_ust_comm_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* Should the ust comm thread quit ? */
+static int lttng_ust_comm_should_quit;
+
+/*
+ * Info about socket and associated listener thread.
+ */
+struct sock_info {
+       char sock_path[PATH_MAX];
+       int socket;
+       pthread_t ust_listener; /* listener thread */
+       int root_handle;
+};
 
 /* Socket from app (connect) to session daemon (listen) for communication */
-static char global_apps_sock_path[PATH_MAX] = DEFAULT_GLOBAL_APPS_UNIX_SOCK;
-static pthread_t global_ust_listener;
+struct sock_info global_apps = {
+       .sock_path = DEFAULT_GLOBAL_APPS_UNIX_SOCK,
+       .socket = -1,
+       .root_handle = -1,
+};
 
 /* TODO: allow global_apps_sock_path override */
 
-static char local_apps_sock_path[PATH_MAX];
-static pthread_t local_ust_listener;
+struct sock_info local_apps = {
+       .socket = -1,
+       .root_handle = -1,
+};
 
 static
 int setup_local_apps_socket(void)
@@ -45,7 +70,7 @@ int setup_local_apps_socket(void)
        home_dir = (const char *) getenv("HOME");
        if (!home_dir)
                return -ENOENT;
-       snprintf(local_apps_sock_path, PATH_MAX,
+       snprintf(local_apps.sock_path, PATH_MAX,
                 DEFAULT_HOME_APPS_UNIX_SOCK, home_dir);
        return 0;
 }
@@ -72,83 +97,172 @@ int register_app_to_sessiond(int socket)
        return ret;
 }
 
+static
+int send_reply(int sock, struct lttcomm_ust_reply *lur)
+{
+       ssize_t len;
+
+       len = lttcomm_send_unix_sock(sock, lur, sizeof(*lur));
+       switch (len) {
+       case sizeof(*lur):
+               DBG("message successfully sent");
+               return 0;
+       case -1:
+               if (errno == ECONNRESET) {
+                       printf("remote end closed connection\n");
+                       return 0;
+               }
+               return -1;
+       default:
+               printf("incorrect message size: %zd\n", len);
+               return -1;
+       }
+}
 
 static
 int handle_message(int sock, struct lttcomm_ust_msg *lum)
 {
-       ssize_t len;
-       int ret;
+       int ret = 0;
+       const struct objd_ops *ops;
+       struct lttcomm_ust_reply lur;
 
-       switch (lum->cmd_type) {
-       case UST_CREATE_SESSION:
-       {
-               struct lttcomm_ust_reply lur;
+       pthread_mutex_lock(&lttng_ust_comm_mutex);
 
-               DBG("Handling create session message");
-               memset(&lur, 0, sizeof(lur));
-               lur.cmd_type = UST_CREATE_SESSION;
+       memset(&lur, 0, sizeof(lur));
 
-               /* ... */
-               ret = 0;
+       if (lttng_ust_comm_should_quit) {
+               ret = -EPERM;
+               goto end;
+       }
 
-               if (!ret)
-                       lur.ret_code = LTTCOMM_OK;
+       ops = objd_ops(lum->handle);
+       if (!ops) {
+               ret = -ENOENT;
+               goto end;
+       }
+
+       switch (lum->cmd) {
+       case LTTNG_UST_RELEASE:
+               if (lum->handle == LTTNG_UST_ROOT_HANDLE)
+                       ret = -EPERM;
                else
-                       lur.ret_code = LTTCOMM_SESSION_FAIL;
-               lur.ret_val = 42;
-               len = lttcomm_send_unix_sock(sock, &lur, sizeof(lur));
-               switch (len) {
-               case sizeof(lur):
-                       printf("message successfully sent\n");
-                       break;
-               case -1:
-                       if (errno == ECONNRESET) {
-                               printf("remote end closed connection\n");
-                               return 0;
-                       }
-                       return -1;
-               default:
-                       printf("incorrect message size: %zd\n", len);
-                       return -1;
-               }
+                       ret = objd_unref(lum->handle);
                break;
-       }
        default:
-               ERR("Unimplemented command %d", (int) lum->cmd_type);
-               return -1;
+               if (ops->cmd)
+                       ret = ops->cmd(lum->handle, lum->cmd,
+                                       (unsigned long) &lum->u);
+               else
+                       ret = -ENOSYS;
+               break;
        }
-       return 0;
+
+end:
+       lur.handle = lum->handle;
+       lur.cmd = lum->cmd;
+       lur.ret_val = ret;
+       if (ret >= 0) {
+               lur.ret_code = LTTCOMM_OK;
+       } else {
+               lur.ret_code = LTTCOMM_SESSION_FAIL;
+       }
+       ret = send_reply(sock, &lur);
+
+       pthread_mutex_unlock(&lttng_ust_comm_mutex);
+       return ret;
 }
 
 static
-void *ust_listener_thread(void *arg)
+void cleanup_sock_info(struct sock_info *sock_info)
 {
-       const char *sock_path = (const char *) arg;
-       int sock;
        int ret;
 
+       if (sock_info->socket != -1) {
+               ret = close(sock_info->socket);
+               if (ret) {
+                       ERR("Error closing local apps socket");
+               }
+               sock_info->socket = -1;
+       }
+       if (sock_info->root_handle != -1) {
+               ret = objd_unref(sock_info->root_handle);
+               if (ret) {
+                       ERR("Error unref root handle");
+               }
+               sock_info->root_handle = -1;
+       }
+}
+
+/*
+ * This thread does not allocate any resource, except within
+ * handle_message, within mutex protection. This mutex protects against
+ * fork and exit.
+ * The other moment it allocates resources is at socket connexion, which
+ * is also protected by the mutex.
+ */
+static
+void *ust_listener_thread(void *arg)
+{
+       struct sock_info *sock_info = arg;
+       int sock, ret;
+
        /* Restart trying to connect to the session daemon */
 restart:
+       pthread_mutex_lock(&lttng_ust_comm_mutex);
+
+       if (lttng_ust_comm_should_quit) {
+               pthread_mutex_unlock(&lttng_ust_comm_mutex);
+               goto quit;
+       }
+
+       if (sock_info->socket != -1) {
+               ret = close(sock_info->socket);
+               if (ret) {
+                       ERR("Error closing local apps socket");
+               }
+               sock_info->socket = -1;
+       }
 
        /* Check for sessiond availability with pipe TODO */
 
        /* Register */
-       ret = lttcomm_connect_unix_sock(sock_path);
+       ret = lttcomm_connect_unix_sock(sock_info->sock_path);
        if (ret < 0) {
                ERR("Error connecting to global apps socket");
+               pthread_mutex_unlock(&lttng_ust_comm_mutex);
+               sleep(5);
+               goto restart;
        }
-       sock = ret;
+
+       sock_info->socket = sock = ret;
+
+       /*
+        * Create only one root handle per listener thread for the whole
+        * process lifetime.
+        */
+       if (sock_info->root_handle == -1) {
+               ret = lttng_abi_create_root_handle();
+               if (ret) {
+                       ERR("Error creating root handle");
+                       pthread_mutex_unlock(&lttng_ust_comm_mutex);
+                       goto quit;
+               }
+               sock_info->root_handle = ret;
+       }
+
        ret = register_app_to_sessiond(sock);
        if (ret < 0) {
                ERR("Error registering app to local apps socket");
+               pthread_mutex_unlock(&lttng_ust_comm_mutex);
                sleep(5);
                goto restart;
        }
+       pthread_mutex_unlock(&lttng_ust_comm_mutex);
+
        for (;;) {
                ssize_t len;
                struct lttcomm_ust_msg lum;
 
-               /* Receive session handle */
                len = lttcomm_recv_unix_sock(sock, &lum, sizeof(lum));
                switch (len) {
                case 0: /* orderly shutdown */
@@ -157,7 +271,7 @@ restart:
                case sizeof(lum):
                        DBG("message received\n");
                        ret = handle_message(sock, &lum);
-                       if (ret) {
+                       if (ret < 0) {
                                ERR("Error handling message\n");
                        }
                        continue;
@@ -174,11 +288,8 @@ restart:
 
        }
 end:
-       ret = close(sock);
-       if (ret) {
-               ERR("Error closing local apps socket");
-       }
        goto restart;   /* try to reconnect */
+quit:
        return NULL;
 }
 
@@ -195,17 +306,16 @@ void __attribute__((constructor)) lttng_ust_comm_init(void)
 
        init_usterr();
 
-       /* Connect to the per-user (local) sessiond apps socket */
        ret = setup_local_apps_socket();
        if (ret) {
                ERR("Error setting up to local apps socket");
        }
 #if 0
-       ret = pthread_create(&global_ust_listener, NULL,
-                       ust_listener_thread, global_apps_sock_path);
+       ret = pthread_create(&global_apps.ust_listener, NULL,
+                       ust_listener_thread, &global_apps);
 #endif //0
-       ret = pthread_create(&local_ust_listener, NULL,
-                       ust_listener_thread, local_apps_sock_path);
+       ret = pthread_create(&local_apps.ust_listener, NULL,
+                       ust_listener_thread, &local_apps);
 }
 
 void __attribute__((destructor)) lttng_ust_comm_exit(void)
@@ -217,13 +327,32 @@ void __attribute__((destructor)) lttng_ust_comm_exit(void)
         * A) we don't want to hang application teardown.
         * B) the thread is not allocating any resource.
         */
-       ret = pthread_cancel(global_ust_listener);
+
+       /*
+        * Require the communication thread to quit. Synchronize with
+        * mutexes to ensure it is not in a mutex critical section when
+        * pthread_cancel is later called.
+        */
+       pthread_mutex_lock(&lttng_ust_comm_mutex);
+       lttng_ust_comm_should_quit = 1;
+       pthread_mutex_unlock(&lttng_ust_comm_mutex);
+
+#if 0
+       ret = pthread_cancel(global_apps.ust_listener);
        if (ret) {
                ERR("Error cancelling global ust listener thread");
        }
-       ret = pthread_cancel(local_ust_listener);
+#endif //0
+
+       cleanup_sock_info(&global_apps);
+
+       ret = pthread_cancel(local_apps.ust_listener);
        if (ret) {
                ERR("Error cancelling local ust listener thread");
        }
+
+       cleanup_sock_info(&local_apps);
+
        lttng_ust_abi_exit();
+       ltt_events_exit();
 }
This page took 0.027131 seconds and 4 git commands to generate.