From: Amitay Isaacs Date: Fri, 17 Nov 2017 01:38:18 +0000 (+1100) Subject: ctdb-common: Add async version of reconfigure in sock_daemon X-Git-Url: http://git.samba.org/?p=metze%2Fsamba%2Fwip.git;a=commitdiff_plain;h=41d888afbecfca6e4ea3c6c86c05101bd5e5b5c4 ctdb-common: Add async version of reconfigure in sock_daemon Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- diff --git a/ctdb/common/sock_daemon.c b/ctdb/common/sock_daemon.c index 6b05e2462f90..ce6f9230a6d3 100644 --- a/ctdb/common/sock_daemon.c +++ b/ctdb/common/sock_daemon.c @@ -533,6 +533,7 @@ static void sock_daemon_run_signal_handler(struct tevent_context *ev, int signum, int count, void *siginfo, void *private_data); 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 bool sock_daemon_run_socket_listen(struct tevent_req *req); static void sock_daemon_run_socket_fail(struct tevent_req *subreq); @@ -717,10 +718,23 @@ static void sock_daemon_run_signal_handler(struct tevent_context *ev, static void sock_daemon_run_reconfigure(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; + if (sockd->funcs != NULL && sockd->funcs->reconfigure_send != NULL && + sockd->funcs->reconfigure_recv != NULL) { + subreq = sockd->funcs->reconfigure_send(state, state->ev, + sockd->private_data); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, + sock_daemon_run_reconfigure_done, req); + return; + } + if (sockd->funcs != NULL && sockd->funcs->reconfigure != NULL) { int ret; @@ -734,6 +748,26 @@ static void sock_daemon_run_reconfigure(struct tevent_req *req) } } +static void sock_daemon_run_reconfigure_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; + int ret; + bool status; + + status = sockd->funcs->reconfigure_recv(subreq, &ret); + TALLOC_FREE(subreq); + if (! status) { + D_ERR("reconfigure failed, ret=%d\n", ret); + return; + } + + D_NOTICE("reconfigure completed successfully\n"); +} + static void sock_daemon_run_shutdown(struct tevent_req *req) { struct sock_daemon_run_state *state = tevent_req_data( diff --git a/ctdb/common/sock_daemon.h b/ctdb/common/sock_daemon.h index 7f19b32dcd4d..2cc94c6bf5dd 100644 --- a/ctdb/common/sock_daemon.h +++ b/ctdb/common/sock_daemon.h @@ -58,6 +58,8 @@ struct sock_client_context; * reconfigure() should return 0 for success, non-zero value on failure * On failure, sock_daemon_run() will continue to run. * + * reconfigure_send()/reconfigure_recv() is the async version of reconfigure() + * * shutdown() is called when process receives SIGINT or SIGTERM or * when wait computation has finished * @@ -76,6 +78,12 @@ struct sock_daemon_funcs { bool (*startup_recv)(struct tevent_req *req, int *perr); int (*reconfigure)(void *private_data); + + struct tevent_req * (*reconfigure_send)(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + void *private_data); + bool (*reconfigure_recv)(struct tevent_req *req, int *perr); + void (*shutdown)(void *private_data); struct tevent_req * (*wait_send)(TALLOC_CTX *mem_ctx, diff --git a/ctdb/tests/cunit/sock_daemon_test_001.sh b/ctdb/tests/cunit/sock_daemon_test_001.sh index aa1d6b471db4..e5bae38d3a0b 100755 --- a/ctdb/tests/cunit/sock_daemon_test_001.sh +++ b/ctdb/tests/cunit/sock_daemon_test_001.sh @@ -44,6 +44,15 @@ test2[PID]: Received signal 10 test2[PID]: reconfigure completed successfully test2[PID]: Received signal 15 test2[PID]: Shutting down +test2[PID]: daemon started, pid=PID +test2[PID]: startup completed successfully +test2[PID]: listening on $sockpath +test2[PID]: Received signal 10 +test2[PID]: reconfigure failed, ret=2 +test2[PID]: Received signal 1 +test2[PID]: reconfigure completed successfully +test2[PID]: Received signal 15 +test2[PID]: Shutting down EOF unit_test sock_daemon_test "$pidfile" "$sockpath" 2 diff --git a/ctdb/tests/src/sock_daemon_test.c b/ctdb/tests/src/sock_daemon_test.c index 72f265f0b784..05a5748fa6df 100644 --- a/ctdb/tests/src/sock_daemon_test.c +++ b/ctdb/tests/src/sock_daemon_test.c @@ -240,6 +240,53 @@ static int test2_reconfigure(void *private_data) return 0; } +struct test2_reconfigure_state { + int fd; +}; + +static struct tevent_req *test2_reconfigure_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + void *private_data) +{ + struct tevent_req *req; + struct test2_reconfigure_state *state; + static bool first_time = true; + + req = tevent_req_create(mem_ctx, &state, + struct test2_reconfigure_state); + if (req == NULL) { + return NULL; + } + + state->fd = *(int *)private_data; + + if (first_time) { + first_time = false; + tevent_req_error(req, 2); + } else { + tevent_req_done(req); + } + + return tevent_req_post(req, ev); +} + +static bool test2_reconfigure_recv(struct tevent_req *req, int *perr) +{ + struct test2_reconfigure_state *state = tevent_req_data( + req, struct test2_reconfigure_state); + int ret = 2; + ssize_t nwritten; + + nwritten = write(state->fd, &ret, sizeof(ret)); + assert(nwritten == sizeof(ret)); + + if (tevent_req_is_unix_error(req, perr)) { + return false; + } + + return true; +} + static void test2_shutdown(void *private_data) { int fd = *(int *)private_data; @@ -344,6 +391,69 @@ static void test2(TALLOC_CTX *mem_ctx, const char *pidfile, ret = stat(sockpath, &st); assert(ret == -1); + + ret = pipe(fd); + assert(ret == 0); + + pid = fork(); + assert(pid != -1); + + if (pid == 0) { + struct tevent_context *ev; + struct sock_daemon_context *sockd; + struct sock_daemon_funcs test2_funcs = { + .startup = test2_startup, + .reconfigure_send = test2_reconfigure_send, + .reconfigure_recv = test2_reconfigure_recv, + }; + + close(fd[0]); + + ev = tevent_context_init(mem_ctx); + assert(ev != NULL); + + ret = sock_daemon_setup(mem_ctx, "test2", "file:", "NOTICE", + &test2_funcs, &fd[1], &sockd); + assert(ret == 0); + + ret = sock_daemon_add_unix(sockd, sockpath, + &dummy_socket_funcs, NULL); + assert(ret == 0); + + ret = sock_daemon_run(ev, sockd, pidfile, false, false, -1); + assert(ret == EINTR); + + exit(0); + } + + close(fd[1]); + + n = read(fd[0], &ret, sizeof(ret)); + assert(n == sizeof(ret)); + assert(ret == 1); + + ret = kill(pid, SIGUSR1); + assert(ret == 0); + + n = read(fd[0], &ret, sizeof(ret)); + assert(n == sizeof(ret)); + assert(ret == 2); + + ret = kill(pid, SIGHUP); + assert(ret == 0); + + n = read(fd[0], &ret, sizeof(ret)); + assert(n == sizeof(ret)); + assert(ret == 2); + + ret = kill(pid, SIGTERM); + assert(ret == 0); + + pid2 = waitpid(pid, &ret, 0); + assert(pid2 == pid); + assert(WEXITSTATUS(ret) == 0); + + close(fd[0]); } /*