diff --git a/plugins/autoclean.c b/plugins/autoclean.c index f1e2e5198..83c896db8 100644 --- a/plugins/autoclean.c +++ b/plugins/autoclean.c @@ -206,7 +206,7 @@ static const struct subsystem_ops *get_subsystem_ops(const struct per_subsystem } /* Mutual recursion */ -static void do_clean_timer(void *unused); +static struct command_result *do_clean_timer(struct command *cmd, void *unused); static struct command_result *do_clean(struct clean_info *cinfo); static struct clean_info *new_clean_info(const tal_t *ctx, @@ -267,7 +267,7 @@ static struct command_result *clean_finished(struct clean_info *cinfo) } while (next_sv(&sv)); /* autoclean-once? */ - if (cinfo->cmd) { + if (cinfo != timer_cinfo) { struct json_stream *response = jsonrpc_stream_success(cinfo->cmd); json_object_start(response, "autoclean"); @@ -287,9 +287,10 @@ static struct command_result *clean_finished(struct clean_info *cinfo) return command_finished(cinfo->cmd, response); } else { /* timer */ plugin_log(plugin, LOG_DBG, "setting next timer"); - cleantimer = plugin_timer(plugin, time_from_sec(cycle_seconds), + cleantimer = global_timer(plugin, + time_from_sec(cycle_seconds), do_clean_timer, NULL); - return timer_complete(plugin); + return timer_complete(cinfo->cmd); } } @@ -554,7 +555,7 @@ static struct command_result *do_clean(struct clean_info *cinfo) filter = tal_fmt(tmpctx, "{\"%s\":[{%s}]}", ops->arr_name, ops->list_filter); - req = jsonrpc_request_with_filter_start(plugin, NULL, + req = jsonrpc_request_with_filter_start(plugin, cinfo->cmd, tal_fmt(tmpctx, "list%s", ops->system_name), @@ -641,11 +642,12 @@ static struct command_result *start_clean(struct clean_info *cinfo) } /* Needs a different signature than do_clean */ -static void do_clean_timer(void *unused) +static struct command_result *do_clean_timer(struct command *cmd, void *unused) { assert(timer_cinfo->cleanup_reqs_remaining == 0); cleantimer = NULL; - start_clean(timer_cinfo); + timer_cinfo->cmd = cmd; + return start_clean(timer_cinfo); } static struct command_result *param_subsystem(struct command *cmd, @@ -750,7 +752,7 @@ static const char *init(struct plugin *p, tal_steal(plugin, timer_cinfo); plugin_set_memleak_handler(plugin, memleak_mark_timer_cinfo); - cleantimer = plugin_timer(p, time_from_sec(cycle_seconds), do_clean_timer, NULL); + cleantimer = global_timer(p, time_from_sec(cycle_seconds), do_clean_timer, NULL); /* We don't care if this fails (it usually does, since entries * don't exist! */ @@ -777,7 +779,8 @@ static char *cycle_seconds_option(struct plugin *plugin, const char *arg, /* If timer is not running right now, reset it to new cycle_seconds */ if (cleantimer) { tal_free(cleantimer); - cleantimer = plugin_timer(plugin, time_from_sec(*cycle_seconds), + cleantimer = global_timer(plugin, + time_from_sec(*cycle_seconds), do_clean_timer, NULL); } return NULL; diff --git a/plugins/bcli.c b/plugins/bcli.c index 9e2f1eff2..1bb0226a9 100644 --- a/plugins/bcli.c +++ b/plugins/bcli.c @@ -199,15 +199,16 @@ static void destroy_bcli(struct bitcoin_cli *bcli) list_del_from(&bitcoind->current, &bcli->list); } -static void retry_bcli(void *cb_arg) +static struct command_result *retry_bcli(struct command *cmd, + struct bitcoin_cli *bcli) { - struct bitcoin_cli *bcli = cb_arg; list_del_from(&bitcoind->current, &bcli->list); tal_del_destructor(bcli, destroy_bcli); list_add_tail(&bitcoind->pending[bcli->prio], &bcli->list); tal_free(bcli->output); next_bcli(bcli->prio); + return timer_complete(cmd); } /* We allow 60 seconds of spurious errors, eg. reorg. */ @@ -238,7 +239,7 @@ static void bcli_failure(struct bitcoin_cli *bcli, bitcoind->error_count++; /* Retry in 1 second */ - plugin_timer(bcli->cmd->plugin, time_from_sec(1), retry_bcli, bcli); + command_timer(bcli->cmd, time_from_sec(1), retry_bcli, bcli); } static void bcli_finished(struct io_conn *conn UNUSED, struct bitcoin_cli *bcli) diff --git a/plugins/fetchinvoice.c b/plugins/fetchinvoice.c index 8e49de23e..2ca652d81 100644 --- a/plugins/fetchinvoice.c +++ b/plugins/fetchinvoice.c @@ -397,11 +397,13 @@ static void destroy_sent(struct sent *sent) } /* We've received neither a reply nor a payment; return failure. */ -static void timeout_sent_invreq(struct sent *sent) +static struct command_result *timeout_sent_invreq(struct command *timer_cmd, + struct sent *sent) { /* This will free sent! */ discard_result(command_fail(sent->cmd, OFFER_TIMEOUT, "Timeout waiting for response")); + return timer_complete(timer_cmd); } static struct command_result *sendonionmsg_done(struct command *cmd, @@ -409,9 +411,9 @@ static struct command_result *sendonionmsg_done(struct command *cmd, const jsmntok_t *result UNUSED, struct sent *sent) { - tal_steal(cmd, plugin_timer(cmd->plugin, - time_from_sec(sent->wait_timeout), - timeout_sent_invreq, sent)); + command_timer(cmd, + time_from_sec(sent->wait_timeout), + timeout_sent_invreq, sent); return command_still_pending(cmd); } @@ -618,7 +620,8 @@ static struct command_result *send_message(struct command *cmd, } /* We've received neither a reply nor a payment; return failure. */ -static void timeout_sent_inv(struct sent *sent) +static struct command_result *timeout_sent_inv(struct command *timer_cmd, + struct sent *sent) { struct json_out *details = json_out_new(sent); @@ -630,6 +633,7 @@ static void timeout_sent_inv(struct sent *sent) discard_result(command_done_err(sent->cmd, OFFER_TIMEOUT, "Failed: timeout waiting for response", details)); + return timer_complete(timer_cmd); } static struct command_result *prepare_inv_timeout(struct command *cmd, @@ -637,9 +641,9 @@ static struct command_result *prepare_inv_timeout(struct command *cmd, const jsmntok_t *result UNUSED, struct sent *sent) { - tal_steal(cmd, plugin_timer(cmd->plugin, - time_from_sec(sent->wait_timeout), - timeout_sent_inv, sent)); + command_timer(cmd, + time_from_sec(sent->wait_timeout), + timeout_sent_inv, sent); return sendonionmsg_done(cmd, buf, result, sent); } diff --git a/plugins/libplugin.c b/plugins/libplugin.c index 77fee44e2..20f0ecdec 100644 --- a/plugins/libplugin.c +++ b/plugins/libplugin.c @@ -25,7 +25,8 @@ struct plugin_timer { struct timer timer; - void (*cb)(void *cb_arg); + const char *id; + struct command_result *(*cb)(struct command *cmd, void *cb_arg); void *cb_arg; }; @@ -133,7 +134,6 @@ struct plugin { STRMAP(const char *) usagemap; /* Timers */ struct timers timers; - size_t in_timer; /* Feature set for lightningd */ struct feature_set *our_features; @@ -605,10 +605,10 @@ struct command_result *command_err_raw(struct command *cmd, json_str, strlen(json_str)); } -struct command_result *timer_complete(struct plugin *p) +struct command_result *timer_complete(struct command *cmd) { - assert(p->in_timer > 0); - p->in_timer--; + assert(cmd->type == COMMAND_TYPE_TIMER); + tal_free(cmd); return &complete; } @@ -1677,11 +1677,14 @@ static void setup_command_usage(struct plugin *p) static void call_plugin_timer(struct plugin *p, struct timer *timer) { struct plugin_timer *t = container_of(timer, struct plugin_timer, timer); + struct command *timer_cmd; + struct command_result *res; - p->in_timer++; - /* Free this if they don't. */ - tal_steal(tmpctx, t); - t->cb(t->cb_arg); + /* This *isn't* owned by timer, which is owned by original command, + * since they may free that in callback */ + timer_cmd = new_command(p, p, t->id, "timer", COMMAND_TYPE_TIMER); + res = t->cb(timer_cmd, t->cb_arg); + assert(res == &pending || res == &complete); } static void destroy_plugin_timer(struct plugin_timer *timer, struct plugin *p) @@ -1689,11 +1692,15 @@ static void destroy_plugin_timer(struct plugin_timer *timer, struct plugin *p) timer_del(&p->timers, &timer->timer); } -struct plugin_timer *plugin_timer_(struct plugin *p, struct timerel t, - void (*cb)(void *cb_arg), - void *cb_arg) +static struct plugin_timer *new_timer(const tal_t *ctx, + struct plugin *p, + const char *id TAKES, + struct timerel t, + struct command_result *(*cb)(struct command *, void *), + void *cb_arg) { - struct plugin_timer *timer = notleak(tal(NULL, struct plugin_timer)); + struct plugin_timer *timer = notleak(tal(ctx, struct plugin_timer)); + timer->id = tal_strdup(timer, id); timer->cb = cb; timer->cb_arg = cb_arg; timer_init(&timer->timer); @@ -1702,6 +1709,24 @@ struct plugin_timer *plugin_timer_(struct plugin *p, struct timerel t, return timer; } +struct plugin_timer *global_timer_(struct plugin *p, + struct timerel t, + struct command_result *(*cb)(struct command *cmd, void *cb_arg), + void *cb_arg) +{ + return new_timer(p, p, "timer", t, cb, cb_arg); +} + +struct plugin_timer *command_timer_(struct command *cmd, + struct timerel t, + struct command_result *(*cb)(struct command *cmd, void *cb_arg), + void *cb_arg) +{ + return new_timer(cmd, cmd->plugin, + take(tal_fmt(NULL, "%s-timer", cmd->id)), + t, cb, cb_arg); +} + void plugin_logv(struct plugin *p, enum log_level l, const char *fmt, va_list ap) { @@ -2280,7 +2305,6 @@ static struct plugin *new_plugin(const tal_t *ctx, p->manifested = p->initialized = p->exiting = false; p->restartability = restartability; strmap_init(&p->usagemap); - p->in_timer = 0; p->commands = commands; if (taken(commands)) diff --git a/plugins/libplugin.h b/plugins/libplugin.h index 7633f0ed7..4a1f1be26 100644 --- a/plugins/libplugin.h +++ b/plugins/libplugin.h @@ -433,27 +433,42 @@ struct command_result *forward_result(struct command *cmd, /* Callback for timer where we expect a 'command_result'. All timers * must return this eventually, though they may do so via a convoluted * send_req() path. */ -struct command_result *timer_complete(struct plugin *p); +struct command_result *timer_complete(struct command *cmd); /* Signals that we've completed a command. Useful for when - * there's no `cmd` present */ + * there's no `cmd` present. Deprecated! */ struct command_result *command_done(void); -/* Access timer infrastructure to add a timer. +/* Access timer infrastructure to add a global timer for the plugin. * - * Freeing this releases the timer, otherwise it's freed after @cb - * if it hasn't been freed already. + * This is a timer with the same lifetime as the plugin. */ -struct plugin_timer *plugin_timer_(struct plugin *p, +struct plugin_timer *global_timer_(struct plugin *p, struct timerel t, - void (*cb)(void *cb_arg), + struct command_result *(*cb)(struct command *cmd, void *cb_arg), void *cb_arg); -#define plugin_timer(plugin, time, cb, cb_arg) \ - plugin_timer_((plugin), (time), \ - typesafe_cb(void, void *, \ - (cb), (cb_arg)), \ - (cb_arg)) \ +#define global_timer(plugin, time, cb, cb_arg) \ + global_timer_((plugin), (time), \ + typesafe_cb_preargs(struct command_result *, \ + void *, \ + (cb), (cb_arg), \ + struct command *), \ + (cb_arg)) \ + +/* Timer based off specific cmd */ +struct plugin_timer *command_timer_(struct command *cmd, + struct timerel t, + struct command_result *(*cb)(struct command *cmd, void *cb_arg), + void *cb_arg); + +#define command_timer(cmd, time, cb, cb_arg) \ + command_timer_((cmd), (time), \ + typesafe_cb_preargs(struct command_result *, \ + void *, \ + (cb), (cb_arg), \ + struct command *), \ + (cb_arg)) \ /* Log something */ void plugin_log(struct plugin *p, enum log_level l, const char *fmt, ...) PRINTF_FMT(3, 4); diff --git a/plugins/recover.c b/plugins/recover.c index b46d55dc7..052de006f 100644 --- a/plugins/recover.c +++ b/plugins/recover.c @@ -28,9 +28,9 @@ static struct plugin_timer *lost_state_timer, *find_exes_timer, *peer_storage_ti /* This tells if we are already in the process of recovery. */ static bool recovery, already_has_peers; -static void do_check_lost_peer (void *unused); -static void do_check_gossip (struct command *cmd); -static void do_find_peer_storage (struct command *cmd); +static struct command_result *do_check_lost_peer (struct command *cmd, void *unused); +static struct command_result *do_check_gossip (struct command *cmd, void *unused); +static struct command_result *do_find_peer_storage (struct command *cmd, void *unused); static struct node_id local_id; /* List of most connected nodes on the network */ @@ -84,9 +84,10 @@ static struct command_result *after_restorefrompeer(struct command *cmd, plugin_log(plugin, LOG_DBG, "restorefrompeer called"); peer_storage_timer = - plugin_timer(plugin, time_from_sec(CHECK_STORAGE_INTERVAL), - do_find_peer_storage, cmd); - return command_still_pending(cmd); + global_timer(plugin, + time_from_sec(CHECK_STORAGE_INTERVAL), + do_find_peer_storage, NULL); + return timer_complete(cmd); } static struct command_result *find_peer_storage (struct command *cmd) @@ -101,14 +102,13 @@ static struct command_result *find_peer_storage (struct command *cmd) return send_outreq(plugin, req); } -static void do_find_peer_storage (struct command *cmd) +static struct command_result *do_find_peer_storage(struct command *cmd, void *unused) { - find_peer_storage(cmd); - return; + return find_peer_storage(cmd); } -static void do_check_gossip (struct command *cmd) +static struct command_result *do_check_gossip(struct command *cmd, void *unused) { find_exes_timer = NULL; @@ -144,14 +144,15 @@ static void do_check_gossip (struct command *cmd) } peer_storage_timer = - plugin_timer(plugin, time_from_sec(CHECK_STORAGE_INTERVAL), - do_find_peer_storage, cmd); - return; + global_timer(plugin, + time_from_sec(CHECK_STORAGE_INTERVAL), + do_find_peer_storage, NULL); + return timer_complete(cmd); } - find_exes_timer = plugin_timer( - plugin, time_from_sec(CHECK_PEER_INTERVAL), do_check_gossip, cmd); - return; + find_exes_timer = global_timer( + plugin, time_from_sec(CHECK_PEER_INTERVAL), do_check_gossip, NULL); + return timer_complete(cmd); } static void entering_recovery_mode(struct command *cmd) @@ -182,7 +183,7 @@ static void entering_recovery_mode(struct command *cmd) NULL); send_outreq(plugin, req_emer_recovery); - find_exes_timer = plugin_timer( + find_exes_timer = global_timer( plugin, time_from_sec(CHECK_GOSSIP_INTERVAL), do_check_gossip, cmd); return; } @@ -216,32 +217,32 @@ static struct command_result *after_listpeerchannels(struct command *cmd, } lost_state_timer = - plugin_timer(plugin, time_from_sec(CHECK_PEER_INTERVAL), + global_timer(plugin, time_from_sec(CHECK_PEER_INTERVAL), do_check_lost_peer, NULL); return command_still_pending(cmd); } -static struct command_result *check_lost_peer(void *unused) +static struct command_result *check_lost_peer(struct command *cmd) { struct out_req *req; - req = jsonrpc_request_start(plugin, NULL, "listpeerchannels", - after_listpeerchannels, - &forward_error, NULL); + req = jsonrpc_request_start(plugin, cmd, "listpeerchannels", + after_listpeerchannels, + &forward_error, NULL); return send_outreq(plugin, req); } -static void do_check_lost_peer (void *unused) +static struct command_result *do_check_lost_peer(struct command *cmd, void *unused) { /* Set to NULL when already in progress. */ lost_state_timer = NULL; if (recovery) { - return; + return timer_complete(cmd); } - check_lost_peer(unused); + return check_lost_peer(cmd); } static const char *init(struct plugin *p, @@ -251,7 +252,7 @@ static const char *init(struct plugin *p, plugin = p; plugin_log(p, LOG_DBG, "Recover Plugin Initialised!"); recovery = false; - lost_state_timer = plugin_timer(plugin, time_from_sec(STARTUP_TIME), + lost_state_timer = global_timer(plugin, time_from_sec(STARTUP_TIME), do_check_lost_peer, NULL); u32 num_peers; size_t num_cupdates_rejected; diff --git a/plugins/renepay/mods.c b/plugins/renepay/mods.c index 3d410cbce..f5e232eea 100644 --- a/plugins/renepay/mods.c +++ b/plugins/renepay/mods.c @@ -771,21 +771,24 @@ REGISTER_PAYMENT_MODIFIER(send_routes, send_routes_cb); * The payment main thread sleeps for some time. */ -static void sleep_done(struct payment *payment) +static struct command_result *sleep_done(struct command *cmd, struct payment *payment) { + struct command_result *ret; payment->waitresult_timer = NULL; - // TODO: is this compulsory? - timer_complete(pay_plugin->plugin); + ret = timer_complete(cmd); payment_continue(payment); + return ret; } static struct command_result *sleep_cb(struct payment *payment) { - assert(payment->waitresult_timer == NULL); - payment->waitresult_timer = plugin_timer( - pay_plugin->plugin, time_from_msec(COLLECTOR_TIME_WINDOW_MSEC), sleep_done, payment); struct command *cmd = payment_command(payment); assert(cmd); + assert(payment->waitresult_timer == NULL); + payment->waitresult_timer + = command_timer(cmd, + time_from_msec(COLLECTOR_TIME_WINDOW_MSEC), + sleep_done, payment); return command_still_pending(cmd); } diff --git a/plugins/spender/multifundchannel.c b/plugins/spender/multifundchannel.c index 4a06ad177..a2eaf8113 100644 --- a/plugins/spender/multifundchannel.c +++ b/plugins/spender/multifundchannel.c @@ -1649,10 +1649,12 @@ perform_multiconnect(struct multifundchannel_command *mfc) /* Initiate the multifundchannel execution. */ -static void -perform_multifundchannel(struct multifundchannel_command *mfc) +static struct command_result * +perform_multifundchannel(struct command *timer_cmd, + struct multifundchannel_command *mfc) { perform_multiconnect(mfc); + return timer_complete(timer_cmd); } @@ -1778,8 +1780,8 @@ post_cleanup_redo_multifundchannel(struct multifundchannel_redo *redo) /* Okay, we still have destinations to try: wait a second in case it * takes that long to disconnect from peer, then retry. */ - plugin_timer(mfc->cmd->plugin, time_from_sec(1), - perform_multifundchannel, mfc); + command_timer(mfc->cmd, time_from_sec(1), + perform_multifundchannel, mfc); return command_still_pending(mfc->cmd); } @@ -2011,7 +2013,7 @@ json_multifundchannel(struct command *cmd, mfc->sigs_collected = false; - perform_multifundchannel(mfc); + perform_multiconnect(mfc); return command_still_pending(mfc->cmd); }