mirror of
https://github.com/aljazceru/lightning.git
synced 2026-01-09 00:54:22 +01:00
lightningd: call "shutdown" notification on plugins at shutdown.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> Changelog-Added: Plugins: `shutdown` notification for clean exits.
This commit is contained in:
committed by
Christian Decker
parent
89c3541c83
commit
1d8aecb44f
@@ -89,22 +89,6 @@ struct plugins *plugins_new(const tal_t *ctx, struct log_book *log_book,
|
||||
return p;
|
||||
}
|
||||
|
||||
void plugins_free(struct plugins *plugins)
|
||||
{
|
||||
struct plugin *p;
|
||||
|
||||
plugins->shutdown = true;
|
||||
|
||||
/* Plugins are usually the unit of allocation, and they are internally
|
||||
* consistent, so let's free each plugin first. */
|
||||
while (!list_empty(&plugins->plugins)) {
|
||||
p = list_pop(&plugins->plugins, struct plugin, list);
|
||||
tal_free(p);
|
||||
}
|
||||
|
||||
tal_free(plugins);
|
||||
}
|
||||
|
||||
/* Check that all the plugin's subscriptions are actually for known
|
||||
* notification topics. Emit a warning if that's not the case, but
|
||||
* don't kill the plugin. */
|
||||
@@ -205,8 +189,12 @@ static void destroy_plugin(struct plugin *p)
|
||||
|
||||
/* If we are shutting down, do not continue to checking if
|
||||
* the dying plugin is important. */
|
||||
if (p->plugins->shutdown)
|
||||
if (p->plugins->shutdown) {
|
||||
/* But return if this was the last plugin! */
|
||||
if (list_empty(&p->plugins->plugins))
|
||||
io_break(p->plugins);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Now check if the dying plugin is important. */
|
||||
if (p->important) {
|
||||
@@ -1958,21 +1946,36 @@ static bool plugin_subscriptions_contains(struct plugin *plugin,
|
||||
return false;
|
||||
}
|
||||
|
||||
bool plugin_single_notify(struct plugin *p,
|
||||
const struct jsonrpc_notification *n TAKES)
|
||||
{
|
||||
bool interested;
|
||||
if (plugin_subscriptions_contains(p, n->method)) {
|
||||
plugin_send(p, json_stream_dup(p, n->stream, p->log));
|
||||
interested = true;
|
||||
} else
|
||||
interested = false;
|
||||
|
||||
if (taken(n))
|
||||
tal_free(n);
|
||||
|
||||
return interested;
|
||||
}
|
||||
|
||||
void plugins_notify(struct plugins *plugins,
|
||||
const struct jsonrpc_notification *n TAKES)
|
||||
{
|
||||
struct plugin *p;
|
||||
|
||||
if (taken(n))
|
||||
tal_steal(tmpctx, n);
|
||||
|
||||
/* If we're shutting down, ld->plugins will be NULL */
|
||||
if (plugins) {
|
||||
list_for_each(&plugins->plugins, p, list) {
|
||||
if (plugin_subscriptions_contains(p, n->method))
|
||||
plugin_send(p, json_stream_dup(p, n->stream,
|
||||
p->log));
|
||||
plugin_single_notify(p, n);
|
||||
}
|
||||
}
|
||||
if (taken(n))
|
||||
tal_free(n);
|
||||
}
|
||||
|
||||
static void destroy_request(struct jsonrpc_request *req,
|
||||
@@ -2067,3 +2070,49 @@ bool was_plugin_destroyed(struct plugin_destroyed *pd)
|
||||
tal_free(pd);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void plugin_shutdown_timeout(struct lightningd *ld)
|
||||
{
|
||||
io_break(ld->plugins);
|
||||
}
|
||||
|
||||
void shutdown_plugins(struct lightningd *ld)
|
||||
{
|
||||
struct plugin *p, *next;
|
||||
|
||||
/* This makes sure we don't complain about important plugins
|
||||
* vanishing! */
|
||||
ld->plugins->shutdown = true;
|
||||
|
||||
/* Tell them all to shutdown; if they care. */
|
||||
list_for_each_safe(&ld->plugins->plugins, p, next, list) {
|
||||
/* Kill immediately, deletes self from list. */
|
||||
if (!notify_plugin_shutdown(ld, p))
|
||||
tal_free(p);
|
||||
}
|
||||
|
||||
/* If anyone was interested in shutdown, give them time. */
|
||||
if (!list_empty(&ld->plugins->plugins)) {
|
||||
struct oneshot *t;
|
||||
|
||||
/* 30 seconds should do it. */
|
||||
t = new_reltimer(ld->timers, ld,
|
||||
time_from_sec(30),
|
||||
plugin_shutdown_timeout, ld);
|
||||
|
||||
io_loop_with_timers(ld);
|
||||
tal_free(t);
|
||||
|
||||
/* Report and free remaining plugins. */
|
||||
while (!list_empty(&ld->plugins->plugins)) {
|
||||
p = list_pop(&ld->plugins->plugins, struct plugin, list);
|
||||
log_debug(ld->log,
|
||||
"%s: failed to shutdown, killing.",
|
||||
p->shortname);
|
||||
tal_free(p);
|
||||
}
|
||||
}
|
||||
|
||||
/* NULL stops notifications trying to access plugins. */
|
||||
ld->plugins = tal_free(ld->plugins);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user