ctdb-common: Add async version of shutdown in sock_daemon
authorAmitay Isaacs <amitay@gmail.com>
Fri, 17 Nov 2017 01:38:47 +0000 (12:38 +1100)
committerMartin Schwenke <martins@samba.org>
Tue, 21 Nov 2017 07:58:45 +0000 (08:58 +0100)
Signed-off-by: Amitay Isaacs <amitay@gmail.com>
Reviewed-by: Martin Schwenke <martin@meltin.net>
Autobuild-User(master): Martin Schwenke <martins@samba.org>
Autobuild-Date(master): Tue Nov 21 08:58:45 CET 2017 on sn-devel-144

ctdb/common/sock_daemon.c
ctdb/common/sock_daemon.h
ctdb/tests/src/sock_daemon_test.c

index ce6f9230a6d34c4969e445589a4197cca51921cb..7554cd6da0762791bcc6d954825401e0833acbeb 100644 (file)
@@ -524,6 +524,7 @@ struct sock_daemon_run_state {
        pid_t pid_watch;
 
        int fd;
+       int exit_code;
 };
 
 static void sock_daemon_run_started(struct tevent_req *subreq);
@@ -535,6 +536,8 @@ static void sock_daemon_run_signal_handler(struct tevent_context *ev,
 static void sock_daemon_run_reconfigure(struct tevent_req *req);
 static void sock_daemon_run_reconfigure_done(struct tevent_req *subreq);
 static void sock_daemon_run_shutdown(struct tevent_req *req);
+static void sock_daemon_run_shutdown_done(struct tevent_req *subreq);
+static void sock_daemon_run_exit(struct tevent_req *req);
 static bool sock_daemon_run_socket_listen(struct tevent_req *req);
 static void sock_daemon_run_socket_fail(struct tevent_req *subreq);
 static void sock_daemon_run_watch_pid(struct tevent_req *subreq);
@@ -702,6 +705,8 @@ static void sock_daemon_run_signal_handler(struct tevent_context *ev,
 {
        struct tevent_req *req = talloc_get_type_abort(
                private_data, struct tevent_req);
+       struct sock_daemon_run_state *state = tevent_req_data(
+               req, struct sock_daemon_run_state);
 
        D_NOTICE("Received signal %d\n", signum);
 
@@ -711,8 +716,8 @@ static void sock_daemon_run_signal_handler(struct tevent_context *ev,
        }
 
        if (signum == SIGINT || signum == SIGTERM) {
+               state->exit_code = EINTR;
                sock_daemon_run_shutdown(req);
-               tevent_req_error(req, EINTR);
        }
 }
 
@@ -770,6 +775,7 @@ static void sock_daemon_run_reconfigure_done(struct tevent_req *subreq)
 
 static void sock_daemon_run_shutdown(struct tevent_req *req)
 {
+       struct tevent_req *subreq;
        struct sock_daemon_run_state *state = tevent_req_data(
                req, struct sock_daemon_run_state);
        struct sock_daemon_context *sockd = state->sockd;
@@ -782,11 +788,53 @@ static void sock_daemon_run_shutdown(struct tevent_req *req)
                TALLOC_FREE(sock);
        }
 
+       if (sockd->funcs != NULL && sockd->funcs->shutdown_send != NULL &&
+           sockd->funcs->shutdown_recv != NULL) {
+               subreq = sockd->funcs->shutdown_send(state, state->ev,
+                                                    sockd->private_data);
+               if (subreq == NULL) {
+                       sock_daemon_run_exit(req);
+                       return;
+               }
+               tevent_req_set_callback(subreq, sock_daemon_run_shutdown_done,
+                                               req);
+               return;
+       }
+
        if (sockd->funcs != NULL && sockd->funcs->shutdown != NULL) {
                sockd->funcs->shutdown(sockd->private_data);
        }
 
+       sock_daemon_run_exit(req);
+}
+
+static void sock_daemon_run_shutdown_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct sock_daemon_run_state *state = tevent_req_data(
+               req, struct sock_daemon_run_state);
+       struct sock_daemon_context *sockd = state->sockd;
+
+       sockd->funcs->shutdown_recv(subreq);
+       TALLOC_FREE(subreq);
+
+       sock_daemon_run_exit(req);
+}
+
+static void sock_daemon_run_exit(struct tevent_req *req)
+{
+       struct sock_daemon_run_state *state = tevent_req_data(
+               req, struct sock_daemon_run_state);
+       struct sock_daemon_context *sockd = state->sockd;
+
        TALLOC_FREE(sockd->pid_ctx);
+
+       if (state->exit_code == 0) {
+               tevent_req_done(req);
+       } else {
+               tevent_req_error(req, state->exit_code);
+       }
 }
 
 static bool sock_daemon_run_socket_listen(struct tevent_req *req)
@@ -826,13 +874,14 @@ static void sock_daemon_run_socket_fail(struct tevent_req *subreq)
 
        status = sock_socket_start_recv(subreq, &ret, state, &sockpath);
        TALLOC_FREE(subreq);
-       sock_daemon_run_shutdown(req);
        if (! status) {
                D_ERR("socket %s closed unexpectedly\n", sockpath);
-               tevent_req_error(req, ret);
+               state->exit_code = ret;
        } else {
-               tevent_req_done(req);
+               state->exit_code = 0;
        }
+
+       sock_daemon_run_shutdown(req);
 }
 
 static void sock_daemon_run_watch_pid(struct tevent_req *subreq)
@@ -855,8 +904,8 @@ static void sock_daemon_run_watch_pid(struct tevent_req *subreq)
        if (ret == -1) {
                if (errno == ESRCH) {
                        D_ERR("PID %d gone away, exiting\n", state->pid_watch);
+                       state->exit_code = ESRCH;
                        sock_daemon_run_shutdown(req);
-                       tevent_req_error(req, ESRCH);
                        return;
                } else {
                        D_ERR("Failed to check PID status %d, ret=%d\n",
@@ -898,17 +947,18 @@ static void sock_daemon_run_wait_done(struct tevent_req *subreq)
        struct sock_daemon_run_state *state = tevent_req_data(
                req, struct sock_daemon_run_state);
        struct sock_daemon_context *sockd = state->sockd;
-       int ret;
+       int ret = 0;
        bool status;
 
        status = sockd->funcs->wait_recv(subreq, &ret);
        TALLOC_FREE(subreq);
-       sock_daemon_run_shutdown(req);
        if (! status) {
-               tevent_req_error(req, ret);
+               state->exit_code = ret;
        } else {
-               tevent_req_done(req);
+               state->exit_code = 0;
        }
+
+       sock_daemon_run_shutdown(req);
 }
 
 bool sock_daemon_run_recv(struct tevent_req *req, int *perr)
index 2cc94c6bf5dd38d5de9dcf0d8871d9de74e0b2e6..a071833c2f382c43f5b9e2d9f41d1f6f9e39e259 100644 (file)
@@ -63,6 +63,12 @@ struct sock_client_context;
  * shutdown() is called when process receives SIGINT or SIGTERM or
  *             when wait computation has finished
  *
+ * shutdown_send()/shutdown_recv() is the async version of shutdown()
+ *
+ * Please note that only one (sync or async) version of these functions
+ * will be called.  If both versions are defined, then only async function
+ * will be called.
+ *
  * wait_send() starts the async computation to keep running the daemon
  * wait_recv() ends the async computation to keep running the daemon
  *
@@ -86,6 +92,11 @@ struct sock_daemon_funcs {
 
        void (*shutdown)(void *private_data);
 
+       struct tevent_req * (*shutdown_send)(TALLOC_CTX *mem_ctx,
+                                            struct tevent_context *ev,
+                                            void *private_data);
+       void (*shutdown_recv)(struct tevent_req *req);
+
        struct tevent_req * (*wait_send)(TALLOC_CTX *mem_ctx,
                                         struct tevent_context *ev,
                                         void *private_data);
index 05a5748fa6df191fbc5c6c95126b87c1e55453db..505ff78e768582dcbb3e9e90c2f77d6cacae457a 100644 (file)
@@ -297,6 +297,40 @@ static void test2_shutdown(void *private_data)
        assert(nwritten == sizeof(ret));
 }
 
+struct test2_shutdown_state {
+       int fd;
+};
+
+static struct tevent_req *test2_shutdown_send(TALLOC_CTX *mem_ctx,
+                                             struct tevent_context *ev,
+                                             void *private_data)
+{
+       struct tevent_req *req;
+       struct test2_shutdown_state *state;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct test2_shutdown_state);
+       if (req == NULL) {
+               return NULL;
+       }
+
+       state->fd = *(int *)private_data;
+
+       tevent_req_done(req);
+       return tevent_req_post(req, ev);
+}
+
+static void test2_shutdown_recv(struct tevent_req *req)
+{
+       struct test2_shutdown_state *state = tevent_req_data(
+               req, struct test2_shutdown_state);
+       int ret = 3;
+       ssize_t nwritten;
+
+       nwritten = write(state->fd, &ret, sizeof(ret));
+       assert(nwritten == sizeof(ret));
+}
+
 static void test2(TALLOC_CTX *mem_ctx, const char *pidfile,
                  const char *sockpath)
 {
@@ -405,6 +439,8 @@ static void test2(TALLOC_CTX *mem_ctx, const char *pidfile,
                        .startup = test2_startup,
                        .reconfigure_send = test2_reconfigure_send,
                        .reconfigure_recv = test2_reconfigure_recv,
+                       .shutdown_send = test2_shutdown_send,
+                       .shutdown_recv = test2_shutdown_recv,
                };
 
                close(fd[0]);
@@ -449,6 +485,10 @@ static void test2(TALLOC_CTX *mem_ctx, const char *pidfile,
        ret = kill(pid, SIGTERM);
        assert(ret == 0);
 
+       n = read(fd[0], &ret, sizeof(ret));
+       assert(n == sizeof(ret));
+       assert(ret == 3);
+
        pid2 = waitpid(pid, &ret, 0);
        assert(pid2 == pid);
        assert(WEXITSTATUS(ret) == 0);