From aae40e493625a07f4ac95476664447546b28661a Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 19 Jan 2016 06:17:13 +1030 Subject: [PATCH 1/1] io: io_time_override to insert fake times. Signed-off-by: Rusty Russell --- ccan/io/io.h | 10 +++ ccan/io/poll.c | 10 ++- ccan/io/test/run-20-io_time_override.c | 92 ++++++++++++++++++++++++++ 3 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 ccan/io/test/run-20-io_time_override.c diff --git a/ccan/io/io.h b/ccan/io/io.h index ac5a6b07..9316dd18 100644 --- a/ccan/io/io.h +++ b/ccan/io/io.h @@ -649,6 +649,16 @@ void *io_loop(struct timers *timers, struct timer **expired); */ int io_conn_fd(const struct io_conn *conn); +/** + * io_time_override - override the normal call for time. + * @nowfn: the function to call. + * + * io usually uses time_now() internally, but this forces it + * to use your function (eg. for debugging). Returns the old + * one. + */ +struct timeabs (*io_time_override(struct timeabs (*now)(void)))(void); + /** * io_set_debug - set synchronous mode on a connection. * @conn: the connection. diff --git a/ccan/io/poll.c b/ccan/io/poll.c index b1a28fdb..cddc3cac 100644 --- a/ccan/io/poll.c +++ b/ccan/io/poll.c @@ -16,6 +16,14 @@ static struct pollfd *pollfds = NULL; static struct fd **fds = NULL; static LIST_HEAD(closing); static LIST_HEAD(always); +static struct timeabs (*nowfn)(void) = time_now; + +struct timeabs (*io_time_override(struct timeabs (*now)(void)))(void) +{ + struct timeabs (*old)(void) = nowfn; + nowfn = now; + return old; +} static bool add_fd(struct fd *fd, short events) { @@ -256,7 +264,7 @@ void *io_loop(struct timers *timers, struct timer **expired) if (timers) { struct timeabs now, first; - now = time_now(); + now = nowfn(); /* Call functions for expired timers. */ *expired = timers_expire(timers, now); diff --git a/ccan/io/test/run-20-io_time_override.c b/ccan/io/test/run-20-io_time_override.c new file mode 100644 index 00000000..bf493c99 --- /dev/null +++ b/ccan/io/test/run-20-io_time_override.c @@ -0,0 +1,92 @@ +#include +/* Include the C files directly. */ +#include +#include +#include +#include +#include + +#define PORT "65020" + +static struct io_plan *init_conn(struct io_conn *conn, void *unused) +{ + return io_close(conn); +} + +static int make_listen_fd(const char *port, struct addrinfo **info) +{ + int fd, on = 1; + struct addrinfo *addrinfo, hints; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + hints.ai_protocol = 0; + + if (getaddrinfo(NULL, port, &hints, &addrinfo) != 0) + return -1; + + fd = socket(addrinfo->ai_family, addrinfo->ai_socktype, + addrinfo->ai_protocol); + if (fd < 0) + return -1; + + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + if (bind(fd, addrinfo->ai_addr, addrinfo->ai_addrlen) != 0) { + close(fd); + return -1; + } + if (listen(fd, 1) != 0) { + close(fd); + return -1; + } + *info = addrinfo; + return fd; +} + +static struct timeabs fake_time; + +static struct timeabs get_fake_time(void) +{ + return fake_time; +} + +int main(void) +{ + struct io_listener *l; + int fd; + struct timers timers; + struct timer timer, *expired; + struct addrinfo *addrinfo; + + /* This is how many tests you plan to run */ + plan_tests(7); + + fake_time = time_now(); + + timers_init(&timers, fake_time); + timer_init(&timer); + timer_add(&timers, &timer, + timeabs_add(fake_time, time_from_sec(1000))); + + fd = make_listen_fd(PORT, &addrinfo); + freeaddrinfo(addrinfo); + ok1(fd >= 0); + l = io_new_listener(NULL, fd, init_conn, NULL); + ok1(l); + + fake_time.ts.tv_sec += 1000; + ok1(io_time_override(get_fake_time) == time_now); + ok1(io_loop(&timers, &expired) == NULL); + + ok1(expired == &timer); + ok1(!timers_expire(&timers, fake_time)); + ok1(io_time_override(time_now) == get_fake_time); + io_close_listener(l); + + timers_cleanup(&timers); + + /* This exits depending on whether all tests passed */ + return exit_status(); +} -- 2.39.2