ccan/io: implement timeouts.
authorRusty Russell <rusty@rustcorp.com.au>
Mon, 4 Aug 2014 08:13:21 +0000 (17:43 +0930)
committerRusty Russell <rusty@rustcorp.com.au>
Mon, 4 Aug 2014 08:13:21 +0000 (17:43 +0930)
We do this by the simplest method: return from io_loop() and let the caller
sort them out.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
22 files changed:
ccan/io/_info
ccan/io/io.h
ccan/io/poll.c
ccan/io/test/run-01-start-finish.c
ccan/io/test/run-02-read.c
ccan/io/test/run-03-readpartial.c
ccan/io/test/run-04-writepartial.c
ccan/io/test/run-05-write.c
ccan/io/test/run-06-idle.c
ccan/io/test/run-07-break.c
ccan/io/test/run-08-hangup-on-idle.c
ccan/io/test/run-08-read-after-hangup.c
ccan/io/test/run-09-connect.c
ccan/io/test/run-10-many.c
ccan/io/test/run-12-bidir.c
ccan/io/test/run-13-all-idle.c
ccan/io/test/run-14-duplex-both-read.c
ccan/io/test/run-15-timeout.c
ccan/io/test/run-16-duplex-test.c
ccan/io/test/run-17-homemade-io.c
ccan/io/test/run-18-errno.c
ccan/io/test/run-19-always.c

index 7fc6ac61c1e29a3800798315a73bce4b8d856d85..2e0018ad066ace8029873b42c4217aae8ee29b00 100644 (file)
  *     io_set_finish(reader, finish, &from);
  *     io_new_conn(NULL, STDOUT_FILENO, write_out, &from);
  *
- *     io_loop();
+ *     io_loop(NULL, NULL);
  *     wait(&status);
  *
  *     return WIFEXITED(status) ? WEXITSTATUS(status) : 2;
@@ -133,7 +133,10 @@ int main(int argc, char *argv[])
                return 1;
 
        if (strcmp(argv[1], "depends") == 0) {
+               printf("ccan/list\n");
                printf("ccan/tal\n");
+               printf("ccan/time\n");
+               printf("ccan/timer\n");
                printf("ccan/typesafe_cb\n");
                return 0;
        }
index d4ba2d87688e81143863e232d4c1eb34283ab602..165ff6f63361d395db25a4706d21eec51b5bbb1b 100644 (file)
@@ -6,6 +6,9 @@
 #include <stdbool.h>
 #include <unistd.h>
 
+struct timers;
+struct list_head;
+
 /**
  * struct io_plan - a plan for input or output.
  *
@@ -169,7 +172,7 @@ struct io_listener *io_new_listener_(const tal_t *ctx, int fd,
  * ...
  *     struct io_listener *l = do_listen("8111");
  *     if (l) {
- *             io_loop();
+ *             io_loop(NULL, NULL);
  *             io_close_listener(l);
  *     }
  */
@@ -553,14 +556,17 @@ struct io_plan *io_close_cb(struct io_conn *, void *unused);
 
 /**
  * io_loop - process fds until all closed on io_break.
+ * @timers - timers which are waiting to go off (or NULL for none)
+ * @expired - a list filled with expired timers (can be NULL if @timers is)
  *
  * This is the core loop; it exits with the io_break() arg, or NULL if
- * all connections and listeners are closed.
+ * all connections and listeners are closed, or with @expired set to a
+ * list of expired timers (if @timers isn't NULL).
  *
  * Example:
- *     io_loop();
+ *     io_loop(NULL, NULL);
  */
-void *io_loop(void);
+void *io_loop(struct timers *timers, struct list_head *expired);
 
 /**
  * io_conn_fd - get the fd from a connection.
index c1a624525e9185811ad9510eef555a4dd80bfb30..e4058766e9f6ed9661d992ed0a603af1b2ae9520 100644 (file)
@@ -8,6 +8,9 @@
 #include <sys/socket.h>
 #include <limits.h>
 #include <errno.h>
+#include <ccan/list/list.h>
+#include <ccan/time/time.h>
+#include <ccan/timer/timer.h>
 
 static size_t num_fds = 0, max_fds = 0, num_waiting = 0;
 static struct pollfd *pollfds = NULL;
@@ -223,12 +226,19 @@ static bool handle_always(void)
 }
 
 /* This is the main loop. */
-void *io_loop(void)
+void *io_loop(struct timers *timers, struct list_head *expired)
 {
        void *ret;
 
+       /* if timers is NULL, expired must be.  If not, not. */
+       assert(!timers == !expired);
+
+       /* Make sure this is empty if we exit for some other reason. */
+       if (expired)
+               list_head_init(expired);
+
        while (!io_loop_return) {
-               int i, r;
+               int i, r, ms_timeout = -1;
 
                if (close_conns()) {
                        /* Could have started/finished more. */
@@ -247,7 +257,28 @@ void *io_loop(void)
                /* You can't tell them all to go to sleep! */
                assert(num_waiting);
 
-               r = poll(pollfds, num_fds, -1);
+               if (timers) {
+                       struct timeabs now, first;
+
+                       now = time_now();
+
+                       /* Call functions for expired timers. */
+                       timers_expire(timers, now, expired);
+                       if (!list_empty(expired))
+                               break;
+
+                       /* Now figure out how long to wait for the next one. */
+                       if (timer_earliest(timers, &first)) {
+                               uint64_t next;
+                               next = time_to_msec(time_between(first, now));
+                               if (next < INT_MAX)
+                                       ms_timeout = next;
+                               else
+                                       ms_timeout = INT_MAX;
+                       }
+               }
+
+               r = poll(pollfds, num_fds, ms_timeout);
                if (r < 0)
                        break;
 
index b1ce78d3f293f0916b5265cb7a18411333a1ddba..eb2c90a68b77f21bab857d250085efa94baf14d2 100644 (file)
@@ -88,7 +88,7 @@ int main(void)
                exit(0);
        }
        freeaddrinfo(addrinfo);
-       ok1(io_loop() == &state + 1);
+       ok1(io_loop(NULL, NULL) == &state + 1);
        ok1(state == 2);
        io_close_listener(l);
        ok1(wait(&state));
index 4a04335941702df775931c685edcdd11494dfb4a..b43bb8bf1144af2b1bf1451f2e55d4ceba8bd1b3 100644 (file)
@@ -99,7 +99,7 @@ int main(void)
                exit(0);
        }
        freeaddrinfo(addrinfo);
-       ok1(io_loop() == d);
+       ok1(io_loop(NULL, NULL) == d);
        ok1(d->state == 2);
        ok1(memcmp(d->buf, "hellothere", sizeof(d->buf)) == 0);
        free(d);
index 7b3606385f8d0255635bc1128b5739deb880ec97..2d15c2f51c0fb9982d51d704a3411d0710ccf9d9 100644 (file)
@@ -106,7 +106,7 @@ int main(void)
                free(d);
                exit(0);
        }
-       ok1(io_loop() == d);
+       ok1(io_loop(NULL, NULL) == d);
        ok1(d->state == 2);
        ok1(d->bytes > 0);
        ok1(d->bytes <= sizeof(d->buf));
@@ -125,7 +125,7 @@ int main(void)
                exit(0);
        }
        d->state = 0;
-       ok1(io_loop() == d);
+       ok1(io_loop(NULL, NULL) == d);
        ok1(d->state == 2);
        ok1(d->bytes > 0);
        ok1(d->bytes <= strlen("hi"));
index 4ca21a32a25d141c42c82959efea06994e3430f3..011bbc894553b58699559655f6c37eeb7b6c2d1f 100644 (file)
@@ -109,7 +109,7 @@ int main(void)
                free(d);
                exit(0);
        }
-       ok1(io_loop() == d);
+       ok1(io_loop(NULL, NULL) == d);
        ok1(d->state == 2);
        ok1(d->bytes > 0);
        ok1(d->bytes <= 1024*1024);
index 2e744cffd8fa5446c3ce18ded98f8ac6c65b1c02..b17ef83ab8026ca893ede4801a4709308ac09266 100644 (file)
@@ -110,7 +110,7 @@ int main(void)
                free(d);
                exit(0);
        }
-       ok1(io_loop() == d);
+       ok1(io_loop(NULL, NULL) == d);
        ok1(d->state == 2);
 
        ok1(wait(&status));
index d01cb31fff4da1393e6d4071bc5b059ad7ff0326..8f3d5410d7a9058c7da1faa12470767bc79378ca 100644 (file)
@@ -143,7 +143,7 @@ int main(void)
        }
        freeaddrinfo(addrinfo);
 
-       ok1(io_loop() == d);
+       ok1(io_loop(NULL, NULL) == d);
        ok1(d->state == 4);
        ok1(memcmp(d->buf, "hellothere", sizeof(d->buf)) == 0);
        free(d);
index 1f69e9f51bb17e3e2aae58075adf5d3a6c8d7d34..dd192c4d78e82e9230246708819b513734416411 100644 (file)
@@ -107,11 +107,11 @@ int main(void)
                exit(0);
        }
        freeaddrinfo(addrinfo);
-       ok1(io_loop() == d);
+       ok1(io_loop(NULL, NULL) == d);
        ok1(d->state == 1);
        io_close_listener(l);
 
-       ok1(io_loop() == NULL);
+       ok1(io_loop(NULL, NULL) == NULL);
        ok1(d->state == 3);
        ok1(memcmp(d->buf, "hellothere", sizeof(d->buf)) == 0);
        free(d);
index 52309b4bf018045830f6a5a7f02ef6abf0921151..eb3dab3d5fcf29188efb3d8e1351383de0b58110 100644 (file)
@@ -52,7 +52,7 @@ int main(void)
                exit(0);
        }
 
-       ok1(io_loop() == NULL);
+       ok1(io_loop(NULL, NULL) == NULL);
        ok1(memcmp(buf, "hello there world", 16) == 0);
 
        /* This exits depending on whether all tests passed */
index 7b6731ec9da2fa58fcffc242ca1214abe8d36e37..14af5ae6373a5afaac958b5b8376fab0c443f7fa 100644 (file)
@@ -41,7 +41,7 @@ int main(void)
        conn = io_new_conn(NULL, fds[0], init_waiter, NULL);
        io_new_conn(conn, fds[1], init_writer, conn);
 
-       ok1(io_loop() == NULL);
+       ok1(io_loop(NULL, NULL) == NULL);
        ok1(memcmp(inbuf, "EASYTEST", sizeof(inbuf)) == 0);
 
        /* This exits depending on whether all tests passed */
index 8f57f00d8e0f4a6474f63280b20f3b3b6946883d..09b33387590f78808e6a3ef67de08ffc184a7367 100644 (file)
@@ -99,7 +99,7 @@ int main(void)
                    addrinfo->ai_protocol);
        ok1(io_new_conn(NULL, fd, setup_connect, addrinfo));
 
-       ok1(io_loop() == NULL);
+       ok1(io_loop(NULL, NULL) == NULL);
        ok1(d->state == 2);
        ok1(d2->state == 2);
 
index fc48ecb56cf7d75ba3f65750ed4c08849db53b6e..3339a335ff2c707453ba7d5fa03c8694a0aa13e0 100644 (file)
@@ -101,7 +101,7 @@ int main(void)
        ok1(buf[i].writer);
 
        /* They should eventually exit */
-       ok1(io_loop() == NULL);
+       ok1(io_loop(NULL, NULL) == NULL);
 
        for (i = 0; i < NUM; i++) {
                char b[sizeof(buf[0].buf)];
index 0329b81f6755e63f338de1f1890bb803d72b422e..bddd7fbe9ed6a533d88998cb181e70a245279013 100644 (file)
@@ -119,7 +119,7 @@ int main(void)
                exit(0);
        }
        freeaddrinfo(addrinfo);
-       ok1(io_loop() == NULL);
+       ok1(io_loop(NULL, NULL) == NULL);
        ok1(d->state == 4);
        ok1(d->done == 2);
        ok1(memcmp(d->buf, "hellothere", sizeof(d->buf)) == 0);
index 3701472b18258b74a0a0d02626c61efdd395e374..7896b14f4e036913f2ae67feca4f3903e580b024 100644 (file)
@@ -23,7 +23,7 @@ int main(void)
 
                ok1(pipe(fds) == 0);
                io_new_conn(NULL, fds[0], setup_waiter, &status);
-               io_loop();
+               io_loop(NULL, NULL);
                exit(1);
        }
 
index b52553aaf5be7235015d51c38b51e07a54241d54..8cf22aa16cfc6a5febe0fef0e4c2342dcb190340 100644 (file)
@@ -125,7 +125,7 @@ int main(void)
                exit(0);
        }
        freeaddrinfo(addrinfo);
-       ok1(io_loop() == NULL);
+       ok1(io_loop(NULL, NULL) == NULL);
        ok1(d->state == 5);
        ok1(memcmp(d->buf, "hellothere", sizeof(d->buf)) == 0);
        free(d);
index 9224b0a96003d30315e80008df5b6eb76ddc1a5e..e0a3b05ebdf4ca19b61ccd3982f58ff9c8e40489 100644 (file)
@@ -3,55 +3,49 @@
 #include <ccan/io/poll.c>
 #include <ccan/io/io.c>
 #include <ccan/tap/tap.h>
+#include <ccan/time/time.h>
 #include <sys/wait.h>
 #include <stdio.h>
 #include <unistd.h>
 
-#if 0
 #ifndef PORT
 #define PORT "65015"
 #endif
 
 struct data {
+       struct timers timers;
        int state;
+       struct io_conn *conn;
+       struct timer timer;
        int timeout_usec;
-       bool timed_out;
        char buf[4];
 };
 
-
-static struct io_plan no_timeout(struct io_conn *conn, struct data *d)
+static void finish_ok(struct io_conn *conn, struct data *d)
 {
-       ok1(d->state == 1);
        d->state++;
-       return io_close();
+       io_break(d);
 }
 
-static struct io_plan timeout(struct io_conn *conn, struct data *d)
+static struct io_plan *no_timeout(struct io_conn *conn, struct data *d)
 {
        ok1(d->state == 1);
        d->state++;
-       d->timed_out = true;
-       return io_close();
-}
-
-static void finish_ok(struct io_conn *conn, struct data *d)
-{
-       ok1(d->state == 2);
-       d->state++;
-       io_break(d);
+       return io_close(conn);
 }
 
-static void init_conn(int fd, struct data *d)
+static struct io_plan *init_conn(struct io_conn *conn, struct data *d)
 {
-       struct io_conn *conn;
-
        ok1(d->state == 0);
        d->state++;
 
-       conn = io_new_conn(fd, io_read(d->buf, sizeof(d->buf), no_timeout, d));
+       d->conn = conn;
        io_set_finish(conn, finish_ok, d);
-       io_timeout(conn, time_from_usec(d->timeout_usec), timeout, d);
+
+       timer_add(&d->timers, &d->timer,
+                 timeabs_add(time_now(), time_from_usec(d->timeout_usec)));
+
+       return io_read(conn, d->buf, sizeof(d->buf), no_timeout, d);
 }
 
 static int make_listen_fd(const char *port, struct addrinfo **info)
@@ -91,16 +85,17 @@ int main(void)
        struct data *d = malloc(sizeof(*d));
        struct addrinfo *addrinfo;
        struct io_listener *l;
+       struct list_head expired;
        int fd, status;
 
        /* This is how many tests you plan to run */
-       plan_tests(20);
+       plan_tests(21);
        d->state = 0;
-       d->timed_out = false;
        d->timeout_usec = 100000;
+       timers_init(&d->timers, time_now());
        fd = make_listen_fd(PORT, &addrinfo);
        ok1(fd >= 0);
-       l = io_new_listener(fd, init_conn, d);
+       l = io_new_listener(NULL, fd, init_conn, d);
        ok1(l);
        fflush(stdout);
 
@@ -122,19 +117,31 @@ int main(void)
                }
                close(fd);
                freeaddrinfo(addrinfo);
+               timers_cleanup(&d->timers);
                free(d);
                exit(i);
        }
-       ok1(io_loop() == d);
-       ok1(d->state == 3);
-       ok1(d->timed_out == true);
+       ok1(io_loop(&d->timers, &expired) == NULL);
+
+       /* One element, d->timer. */
+       ok1(list_pop(&expired, struct timer, list) == &d->timer);
+       ok1(list_empty(&expired));
+       ok1(d->state == 1);
+
+       io_close(d->conn);
+
+       /* Finished will be called, d will be returned */
+       ok1(io_loop(&d->timers, &expired) == d);
+       ok1(list_empty(&expired));
+       ok1(d->state == 2);
+
+       /* It should have died. */
        ok1(wait(&status));
        ok1(WIFEXITED(status));
        ok1(WEXITSTATUS(status) < sizeof(d->buf));
 
        /* This one shouldn't time out. */
        d->state = 0;
-       d->timed_out = false;
        d->timeout_usec = 500000;
        fflush(stdout);
 
@@ -156,26 +163,22 @@ int main(void)
                }
                close(fd);
                freeaddrinfo(addrinfo);
+               timers_cleanup(&d->timers);
                free(d);
                exit(i);
        }
-       ok1(io_loop() == d);
+       ok1(io_loop(&d->timers, &expired) == d);
        ok1(d->state == 3);
-       ok1(d->timed_out == false);
+       ok1(list_empty(&expired));
        ok1(wait(&status));
        ok1(WIFEXITED(status));
        ok1(WEXITSTATUS(status) >= sizeof(d->buf));
 
        io_close_listener(l);
        freeaddrinfo(addrinfo);
+       timers_cleanup(&d->timers);
        free(d);
 
        /* This exits depending on whether all tests passed */
        return exit_status();
 }
-#else
-int main(void)
-{
-       return 0;
-}
-#endif
index 9d939c58aa422dc09be1a4057fc0d0e9cb4ad0d9..ea588661f7f091f2532da8fc717fb50dcf54cced 100644 (file)
@@ -119,7 +119,7 @@ int main(void)
                exit(0);
        }
        freeaddrinfo(addrinfo);
-       ok1(io_loop() == NULL);
+       ok1(io_loop(NULL, NULL) == NULL);
        ok1(d->state == 4);
        ok1(memcmp(d->buf, "hellothere", sizeof(d->buf)) == 0);
        free(d);
index a868b2132783401941e54bdf3734b9e3c923bd60..1087e2509871347ad0c809abad92d40b6e7b4c11 100644 (file)
@@ -166,7 +166,7 @@ int main(void)
                exit(0);
        }
        freeaddrinfo(addrinfo);
-       ok1(io_loop() == pkt);
+       ok1(io_loop(NULL, NULL) == pkt);
        ok1(pkt->state == 4);
        ok1(pkt->len == 8);
        ok1(memcmp(pkt->contents, "hithere!", 8) == 0);
index f67c0eb02996cfac59b81640b8be3bd875a5537e..c19ab375e01d081b8c4bac86c89a54c0285316b9 100644 (file)
@@ -109,7 +109,7 @@ int main(void)
                exit(0);
        }
        freeaddrinfo(addrinfo);
-       ok1(io_loop() == &state + 1);
+       ok1(io_loop(NULL, NULL) == &state + 1);
        ok1(state == 4);
        io_close_listener(l);
        ok1(wait(&state));
index 2477196971e948a418c8b154678815b0fe9ad466..63eb34e61fb4ec443be0c88977acaea55402f52e 100644 (file)
@@ -117,7 +117,7 @@ int main(void)
                free(d);
                exit(0);
        }
-       ok1(io_loop() == d);
+       ok1(io_loop(NULL, NULL) == d);
        ok1(d->state == 2);
 
        ok1(wait(&status));