From 9b61c19a208b358a238b7f7d0464c05301c8b31f Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 20 May 2019 20:40:54 +0930 Subject: [PATCH] libplugin: simple timer support. Signed-off-by: Rusty Russell --- plugins/libplugin.c | 63 ++++++++++++++++++++++++++++++++++++++++++++- plugins/libplugin.h | 15 ++++++++++- 2 files changed, 76 insertions(+), 2 deletions(-) diff --git a/plugins/libplugin.c b/plugins/libplugin.c index dae18b402..857f109eb 100644 --- a/plugins/libplugin.c +++ b/plugins/libplugin.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -26,8 +27,17 @@ static u64 next_outreq_id; * struct json_command as it's good practice to have those const. */ static STRMAP(const char *) usagemap; +/* Timers */ +static struct timers timers; +static bool in_timer; + bool deprecated_apis; +struct plugin_timer { + struct timer timer; + struct command_result *(*cb)(void); +}; + struct plugin_conn { int fd; MEMBUF(char) mb; @@ -232,6 +242,13 @@ command_done_raw(struct command *cmd, return end_cmd(cmd); } +struct command_result *timer_complete(void) +{ + assert(in_timer); + in_timer = false; + return &complete; +} + struct command_result *command_success(struct command *cmd, const char *result) { return command_done_raw(cmd, "result", result, strlen(result)); @@ -582,6 +599,31 @@ static void setup_command_usage(const struct plugin_command *commands, } } +static void call_plugin_timer(struct plugin_conn *rpc, struct timer *timer) +{ + struct plugin_timer *t = container_of(timer, struct plugin_timer, timer); + + in_timer = true; + t->cb(); + tal_free(t); +} + +static void destroy_plugin_timer(struct plugin_timer *timer) +{ + timer_del(&timers, &timer->timer); +} + +struct plugin_timer *plugin_timer(struct plugin_conn *rpc, struct timerel t, + struct command_result *(*cb)(void)) +{ + struct plugin_timer *timer = tal(NULL, struct plugin_timer); + timer->cb = cb; + timer_init(&timer->timer); + timer_addrel(&timers, &timer->timer, t); + tal_add_destructor(timer, destroy_plugin_timer); + return timer; +} + void plugin_main(char *argv[], void (*init)(struct plugin_conn *rpc), const struct plugin_command *commands, @@ -606,6 +648,7 @@ void plugin_main(char *argv[], setup_command_usage(commands, num_commands); + timers_init(&timers, time_mono()); membuf_init(&rpc_conn.mb, tal_arr(ctx, char, READ_CHUNKSIZE), READ_CHUNKSIZE, membuf_tal_realloc); @@ -650,6 +693,10 @@ void plugin_main(char *argv[], fds[1].events = POLLIN; for (;;) { + struct timer *expired; + struct timemono now, first; + int t; + clean_tmpctx(); /* If we already have some input, process now. */ @@ -663,8 +710,22 @@ void plugin_main(char *argv[], continue; } + /* Handle any timeouts */ + now = time_mono(); + expired = timers_expire(&timers, now); + if (expired) { + call_plugin_timer(&rpc_conn, expired); + continue; + } + + /* If we have a pending timer, timeout then */ + if (timer_earliest(&timers, &first)) + t = time_to_msec(timemono_between(first, now)); + else + t = -1; + /* Otherwise, we poll. */ - poll(fds, 2, -1); + poll(fds, 2, t); if (fds[0].revents & POLLIN) handle_new_command(ctx, &request_conn, &rpc_conn, diff --git a/plugins/libplugin.h b/plugins/libplugin.h index 87623a901..5ea2e2974 100644 --- a/plugins/libplugin.h +++ b/plugins/libplugin.h @@ -55,7 +55,9 @@ const char *rpc_delve(const tal_t *ctx, const char *method, const char *params, struct plugin_conn *rpc, const char *guide); -/* Async rpc request. For convenience, and single ' are turned into ". */ +/* Async rpc request. For convenience, and single ' are turned into ". + * @cmd can be NULL if we're coming from a timer callback. + */ PRINTF_FMT(6,7) struct command_result * send_outreq_(struct command *cmd, const char *method, @@ -96,6 +98,17 @@ struct command_result *forward_result(struct command *cmd, const jsmntok_t *result, void *arg); +/* Callback for timer where we expect a 'command_result'. */ +struct command_result *timer_complete(void); + +/* Access timer infrastructure to add a timer. + * + * Freeing this releases the timer (don't free it in timer cb though) + */ +struct plugin_timer *plugin_timer(struct plugin_conn *rpc, + struct timerel t, + struct command_result *(*cb)(void)); + /* Macro to define arguments */ #define plugin_option(name, description, set, arg) \ (name), \