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 */