libplugin: simple timer support.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2019-05-20 20:40:54 +09:30 committed by Christian Decker
parent c83066f8ed
commit 9b61c19a20
2 changed files with 76 additions and 2 deletions

View File

@ -4,6 +4,7 @@
#include <ccan/read_write_all/read_write_all.h>
#include <ccan/strmap/strmap.h>
#include <ccan/tal/str/str.h>
#include <ccan/timer/timer.h>
#include <common/daemon.h>
#include <common/utils.h>
#include <errno.h>
@ -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,

View File

@ -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), \