From a615b56d76a12a71bc9418e389d748f0d71c03f5 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 1 May 2014 14:12:39 +1000 Subject: [PATCH] Install signal handlers which push the signal to the top process which will try to gracefully shut down each child process --- src/ckpool.c | 63 +++++++++++++++++++++++++++++++++++++++--------- src/connector.c | 2 +- src/generator.c | 6 +++-- src/libckpool.c | 5 +--- src/stratifier.c | 18 +++++++++----- 5 files changed, 70 insertions(+), 24 deletions(-) diff --git a/src/ckpool.c b/src/ckpool.c index 39ee1bf2..54156d08 100644 --- a/src/ckpool.c +++ b/src/ckpool.c @@ -134,6 +134,15 @@ static void rm_namepid(proc_instance_t *pi) unlink(s); } +/* Disable signal handlers for child processes, but simply pass them onto the + * parent process to shut down cleanly. */ +static void childsighandler(int sig) +{ + pid_t ppid = getppid(); + + kill(ppid, sig); +} + static void launch_process(proc_instance_t *pi) { pid_t pid; @@ -142,8 +151,15 @@ static void launch_process(proc_instance_t *pi) if (pid < 0) quit(1, "Failed to fork %s in launch_process", pi->processname); if (!pid) { + struct sigaction handler; int ret; + handler.sa_handler = &childsighandler; + handler.sa_flags = 0; + sigemptyset(&handler.sa_mask); + sigaction(SIGTERM, &handler, NULL); + sigaction(SIGINT, &handler, NULL); + rename_proc(pi->processname); write_namepid(pi); ret = pi->process(pi); @@ -160,23 +176,47 @@ static void clean_up(ckpool_t *ckp) dealloc(ckp->socket_dir); } +static void __shutdown_children(ckpool_t *ckp, int sig) +{ + pthread_cancel(ckp->pth_watchdog); + join_pthread(ckp->pth_watchdog); + + if (!kill(ckp->generator.pid, 0)) + kill(ckp->generator.pid, sig); + if (!kill(ckp->stratifier.pid, 0)) + kill(ckp->stratifier.pid, sig); + if (!kill(ckp->connector.pid, 0)) + kill(ckp->connector.pid, sig); +} + static void shutdown_children(ckpool_t *ckp, int sig) { pthread_cancel(ckp->pth_watchdog); join_pthread(ckp->pth_watchdog); - kill(ckp->generator.pid, sig); - kill(ckp->stratifier.pid, sig); - kill(ckp->connector.pid, sig); + + __shutdown_children(ckp, sig); } static void sighandler(int sig) { + pthread_cancel(global_ckp->pth_watchdog); + join_pthread(global_ckp->pth_watchdog); + + /* First attempt, send a shutdown message */ + send_proc(&global_ckp->generator, "shutdown"); + send_proc(&global_ckp->stratifier, "shutdown"); + send_proc(&global_ckp->connector, "shutdown"); + if (sig != 9) { - shutdown_children(global_ckp, 15); - pthread_cancel(global_ckp->pth_listener); + /* Wait a second, then send SIGTERM */ + sleep(1); + __shutdown_children(global_ckp, SIGTERM); + /* Wait another second, then send SIGKILL */ sleep(1); + __shutdown_children(global_ckp, SIGKILL); + pthread_cancel(global_ckp->pth_listener); } else { - shutdown_children(global_ckp, 9); + __shutdown_children(global_ckp, SIGKILL); exit(1); } } @@ -367,11 +407,6 @@ int main(int argc, char **argv) /* Ignore sigpipe */ signal(SIGPIPE, SIG_IGN); - handler.sa_handler = &sighandler; - handler.sa_flags = 0; - sigemptyset(&handler.sa_mask); - sigaction(SIGTERM, &handler, NULL); - sigaction(SIGINT, &handler, NULL); ret = mkdir(ckp.socket_dir, 0700); if (ret && errno != EEXIST) @@ -408,6 +443,12 @@ int main(int argc, char **argv) launch_process(&ckp.stratifier); launch_process(&ckp.connector); + handler.sa_handler = &sighandler; + handler.sa_flags = 0; + sigemptyset(&handler.sa_mask); + sigaction(SIGTERM, &handler, NULL); + sigaction(SIGINT, &handler, NULL); + test_functions(&ckp); create_pthread(&ckp.pth_watchdog, watchdog, &ckp); diff --git a/src/connector.c b/src/connector.c index a2178678..18e73d0c 100644 --- a/src/connector.c +++ b/src/connector.c @@ -512,5 +512,5 @@ out: send_proc(&ckp->main, "shutdown"); sleep(1); } - return ret; + exit(ret); } diff --git a/src/generator.c b/src/generator.c index 26035d35..cbc1c49e 100644 --- a/src/generator.c +++ b/src/generator.c @@ -46,8 +46,10 @@ retry: goto retry; } LOGDEBUG("Generator received request: %s", buf); - if (!strncasecmp(buf, "shutdown", 8)) + if (!strncasecmp(buf, "shutdown", 8)) { + ret = 0; goto out; + } if (!strncasecmp(buf, "getbase", 7)) { if (!gen_gbtbase(cs, &gbt)) { LOGWARNING("Failed to get block template from %s:%s", @@ -154,5 +156,5 @@ out: send_proc(&ckp->main, "shutdown"); sleep(1); } - return ret; + exit(ret); } diff --git a/src/libckpool.c b/src/libckpool.c index 053842b5..1e8343e4 100644 --- a/src/libckpool.c +++ b/src/libckpool.c @@ -56,10 +56,7 @@ void create_pthread(pthread_t *thread, void *(*start_routine)(void *), void *arg void join_pthread(pthread_t thread) { - int ret = pthread_join(thread, NULL); - - if (unlikely(ret)) - quit(1, "Failed to pthread_join"); + pthread_join(thread, NULL); } diff --git a/src/stratifier.c b/src/stratifier.c index d1b5a00a..ea8e7b92 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -582,7 +582,7 @@ static void drop_client(int id) ck_uilock(&instance_lock); } -static int strat_loop(ckpool_t *ckp, proc_instance_t *pi) +static int stratum_loop(ckpool_t *ckp, proc_instance_t *pi) { int sockd, ret = 0, selret; unixsock_t *us = &pi->us; @@ -626,9 +626,10 @@ retry: goto retry; } LOGDEBUG("Stratifier received request: %s", buf); - if (!strncasecmp(buf, "shutdown", 8)) + if (!strncasecmp(buf, "shutdown", 8)) { + ret = 0; goto out; - else if (!strncasecmp(buf, "update", 6)) { + } else if (!strncasecmp(buf, "update", 6)) { update_base(ckp); goto reset; } else if (!strncasecmp(buf, "dropclient", 10)) { @@ -1422,7 +1423,7 @@ int stratifier(proc_instance_t *pi) pthread_t pth_blockupdate, pth_stratum_receiver, pth_stratum_sender; pthread_t pth_statsupdate; ckpool_t *ckp = pi->ckp; - int ret = 0; + int ret; /* Store this for use elsewhere */ hex2bin(scriptsig_header_bin, scriptsig_header, 41); @@ -1450,7 +1451,12 @@ int stratifier(proc_instance_t *pi) cklock_init(&share_lock); - strat_loop(ckp, pi); + ret = stratum_loop(ckp, pi); + LOGINFO("%s stratifier exiting with return code %d", ckp->name, ret); + if (ret) { + send_proc(&ckp->main, "shutdown"); + sleep(1); + } - return ret; + exit(ret); }