* 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;
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;
}
#include <stdbool.h>
#include <unistd.h>
+struct timers;
+struct list_head;
+
/**
* struct io_plan - a plan for input or output.
*
* ...
* struct io_listener *l = do_listen("8111");
* if (l) {
- * io_loop();
+ * io_loop(NULL, NULL);
* io_close_listener(l);
* }
*/
/**
* 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.
#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;
}
/* 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. */
/* 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;
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));
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);
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));
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"));
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);
free(d);
exit(0);
}
- ok1(io_loop() == d);
+ ok1(io_loop(NULL, NULL) == d);
ok1(d->state == 2);
ok1(wait(&status));
}
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);
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);
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 */
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 */
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);
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)];
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);
ok1(pipe(fds) == 0);
io_new_conn(NULL, fds[0], setup_waiter, &status);
- io_loop();
+ io_loop(NULL, NULL);
exit(1);
}
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);
#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)
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);
}
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);
}
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
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);
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);
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));
free(d);
exit(0);
}
- ok1(io_loop() == d);
+ ok1(io_loop(NULL, NULL) == d);
ok1(d->state == 2);
ok1(wait(&status));