From c1b4a74f272977ebdc735c040e976853c7ca800f Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Fri, 17 Nov 2017 12:38:47 +1100 Subject: [PATCH] ctdb-common: Add async version of shutdown in sock_daemon Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke Autobuild-User(master): Martin Schwenke Autobuild-Date(master): Tue Nov 21 08:58:45 CET 2017 on sn-devel-144 --- ctdb/common/sock_daemon.c | 68 +++++++++++++++++++++++++++---- ctdb/common/sock_daemon.h | 11 +++++ ctdb/tests/src/sock_daemon_test.c | 40 ++++++++++++++++++ 3 files changed, 110 insertions(+), 9 deletions(-) diff --git a/ctdb/common/sock_daemon.c b/ctdb/common/sock_daemon.c index ce6f9230a6d..7554cd6da07 100644 --- a/ctdb/common/sock_daemon.c +++ b/ctdb/common/sock_daemon.c @@ -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) diff --git a/ctdb/common/sock_daemon.h b/ctdb/common/sock_daemon.h index 2cc94c6bf5d..a071833c2f3 100644 --- a/ctdb/common/sock_daemon.h +++ b/ctdb/common/sock_daemon.h @@ -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); diff --git a/ctdb/tests/src/sock_daemon_test.c b/ctdb/tests/src/sock_daemon_test.c index 05a5748fa6d..505ff78e768 100644 --- a/ctdb/tests/src/sock_daemon_test.c +++ b/ctdb/tests/src/sock_daemon_test.c @@ -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); -- 2.34.1