summaryrefslogtreecommitdiff
path: root/ctdb
diff options
context:
space:
mode:
authorAmitay Isaacs <amitay@gmail.com>2017-11-17 12:38:18 +1100
committerMartin Schwenke <martins@samba.org>2017-11-21 05:03:17 +0100
commit41d888afbecfca6e4ea3c6c86c05101bd5e5b5c4 (patch)
treeeb8b8cec81bd393604568e439853b6cbaa523a19 /ctdb
parent7558592d15fa4911fa8d2061aa56e2b151f516a2 (diff)
downloadsamba-41d888afbecfca6e4ea3c6c86c05101bd5e5b5c4.tar.gz
ctdb-common: Add async version of reconfigure in sock_daemon
Signed-off-by: Amitay Isaacs <amitay@gmail.com> Reviewed-by: Martin Schwenke <martin@meltin.net>
Diffstat (limited to 'ctdb')
-rw-r--r--ctdb/common/sock_daemon.c34
-rw-r--r--ctdb/common/sock_daemon.h8
-rwxr-xr-xctdb/tests/cunit/sock_daemon_test_001.sh9
-rw-r--r--ctdb/tests/src/sock_daemon_test.c110
4 files changed, 161 insertions, 0 deletions
diff --git a/ctdb/common/sock_daemon.c b/ctdb/common/sock_daemon.c
index 6b05e2462f9..ce6f9230a6d 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 7f19b32dcd4..2cc94c6bf5d 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 aa1d6b471db..e5bae38d3a0 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 72f265f0b78..05a5748fa6d 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]);
}
/*