From d27a5d3212ae1e2ee29f35abf3899a75af26ec71 Mon Sep 17 00:00:00 2001 From: Rusty Russell <rusty@rustcorp.com.au> Date: Tue, 11 Apr 2017 23:52:32 -0700 Subject: [PATCH] lightningd/lightningd: shutdown subdaemons on exit. Especially under valgrind, we should give them some time to exit. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> --- lightningd/lightningd.c | 17 ++++++++++++++++- lightningd/subd.c | 26 ++++++++++++++++++++++++++ lightningd/subd.h | 10 ++++++++++ 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/lightningd/lightningd.c b/lightningd/lightningd.c index 58946d116..1e9be5abc 100644 --- a/lightningd/lightningd.c +++ b/lightningd/lightningd.c @@ -197,6 +197,20 @@ void derive_peer_seed(struct lightningd *ld, struct privkey *peer_seed, ld->peer_counter++; } +static void shutdown_subdaemons(struct lightningd *ld) +{ + struct peer *p; + + /* Let everyone shutdown cleanly. */ + subd_shutdown(ld->hsm, 10); + subd_shutdown(ld->gossip, 10); + + /* Duplicates are OK: no need to check here. */ + list_for_each(&ld->peers, p, list) + if (p->owner) + subd_shutdown(p->owner, 0); +} + int main(int argc, char *argv[]) { struct lightningd *ld = new_lightningd(NULL); @@ -250,7 +264,6 @@ int main(int argc, char *argv[]) #if 0 /* Load peers from database. */ db_load_peers(dstate); - #endif for (;;) { @@ -265,6 +278,8 @@ int main(int argc, char *argv[]) timer_expired(&ld->dstate, expired); } + shutdown_subdaemons(ld); + tal_free(ld); opt_free_table(); return 0; diff --git a/lightningd/subd.c b/lightningd/subd.c index 70754b340..cb58f5884 100644 --- a/lightningd/subd.c +++ b/lightningd/subd.c @@ -431,6 +431,32 @@ void subd_req_(const tal_t *ctx, add_req(ctx, sd, type, num_fds_in, replycb, replycb_data); } +void subd_shutdown(struct subd *sd, unsigned int seconds) +{ + /* Idempotent. */ + if (!sd->conn) + return; + + log_debug(sd->log, "Shutting down"); + + /* No finished callback any more. */ + sd->finished = NULL; + /* Don't free sd when we close connection manually. */ + tal_steal(sd->ld, sd); + /* Close connection: should begin shutdown now. */ + sd->conn = tal_free(sd->conn); + + /* Do we actually want to wait? */ + while (seconds) { + if (waitpid(sd->pid, NULL, WNOHANG) > 0) { + tal_del_destructor(sd, destroy_subd); + return; + } + sleep(1); + seconds--; + } +} + char *opt_subd_debug(const char *optarg, struct lightningd *ld) { ld->dev_debug_subdaemon = optarg; diff --git a/lightningd/subd.h b/lightningd/subd.h index 6a00a7a55..b1c717686 100644 --- a/lightningd/subd.h +++ b/lightningd/subd.h @@ -113,6 +113,16 @@ void subd_req_(const tal_t *ctx, bool (*replycb)(struct subd *, const u8 *, const int *, void *), void *replycb_data); +/** + * subd_shutdown - try to politely shut down a subdaemon. + * @subd: subd to shutdown. + * @seconds: maximum seconds to wait for it to exit. + * + * This closes the fd to the subdaemon, and gives it a little while to exit. + * The @finished callback will never be called. + */ +void subd_shutdown(struct subd *subd, unsigned int seconds); + char *opt_subd_debug(const char *optarg, struct lightningd *ld); #endif /* LIGHTNING_LIGHTNINGD_SUBD_H */