From 45193db7ea2195095bd8512aa21628a576219297 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 6 Apr 2023 09:48:50 +0930 Subject: [PATCH] lightningd: add initializing state. Importantly, the code in jsonrpc.c which actually does the io_break: ``` /* Once the stop_conn conn is drained, we can shut down. */ if (jcon->ld->stop_conn == conn && jcon->ld->state == LD_STATE_RUNNING) { /* Return us to toplevel lightningd.c */ log_debug(jcon->ld->log, "io_break: %s", __func__); io_break(jcon->ld); ``` By having the state not set until later, we avoid running this. Of course, we need to avoid calling the main loop when we get there, if we've already been told to shutdown. Signed-off-by: Rusty Russell --- lightningd/lightningd.c | 21 ++++++++++++--------- lightningd/lightningd.h | 1 + tests/test_misc.py | 1 - 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/lightningd/lightningd.c b/lightningd/lightningd.c index ae8f8afc0..8135c282e 100644 --- a/lightningd/lightningd.c +++ b/lightningd/lightningd.c @@ -974,7 +974,7 @@ int main(int argc, char *argv[]) * valgrind will warn us if we make decisions based on uninitialized * variables. */ ld = new_lightningd(NULL); - ld->state = LD_STATE_RUNNING; + ld->state = LD_STATE_INITIALIZING; /*~ We store an copy of our arguments before parsing mangles them, so * we can re-exec if versions of subdaemons change. Note the use of @@ -1174,6 +1174,7 @@ int main(int argc, char *argv[]) type_to_string(tmpctx, struct node_id, &ld->id), json_escape(tmpctx, (const char *)ld->alias)->s, tal_hex(tmpctx, ld->rgb), version()); + ld->state = LD_STATE_RUNNING; /*~ If `closefrom_may_be_slow`, we limit ourselves to 4096 file * descriptors; tell the user about it as that limits the number @@ -1224,14 +1225,16 @@ int main(int argc, char *argv[]) ecdh_hsmd_setup(ld->hsm_fd, hsm_ecdh_failed); /*~ The root of every backtrace (almost). This is our main event - * loop. */ - void *io_loop_ret = io_loop_with_timers(ld); - /*~ io_loop_with_timers will only exit if we call io_break. - * At this point in code, we should use io_break(ld) to - * shut down. - */ - assert(io_loop_ret == ld); - log_debug(ld->log, "io_loop_with_timers: %s", __func__); + * loop. We don't even call it if they've already called `stop` */ + if (!ld->stop_conn) { + void *io_loop_ret = io_loop_with_timers(ld); + /*~ io_loop_with_timers will only exit if we call io_break. + * At this point in code, we should use io_break(ld) to + * shut down. + */ + assert(io_loop_ret == ld); + log_debug(ld->log, "io_loop_with_timers: %s", __func__); + } stop: /* Stop *new* JSON RPC requests. */ diff --git a/lightningd/lightningd.h b/lightningd/lightningd.h index 9739f80e0..0a57dbb97 100644 --- a/lightningd/lightningd.h +++ b/lightningd/lightningd.h @@ -90,6 +90,7 @@ struct config { typedef STRMAP(const char *) alt_subdaemon_map; enum lightningd_state { + LD_STATE_INITIALIZING, LD_STATE_RUNNING, LD_STATE_SHUTDOWN, }; diff --git a/tests/test_misc.py b/tests/test_misc.py index 698a7a5ab..e3a113549 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -3239,7 +3239,6 @@ def test_create_gossip_mesh(node_factory, bitcoind): assert False, "Test failed on purpose, grab the gossip store from /tmp/ltests-..." -@pytest.mark.xfail(strict=True) def test_fast_shutdown(node_factory): l1 = node_factory.get_node(start=False)