X-Git-Url: http://git.ozlabs.org/?p=ccan;a=blobdiff_plain;f=ccan%2Fio%2Fio.h;h=3bc1c1fae0b0f3a8bfdd0a588b19847a0fcbcd07;hp=6248fec02c2e5c5ae3d42e65d80eb8483af1d5aa;hb=daf9ee7d8e2b683ff05283beb1843611ad8c9e8a;hpb=96a1ebd3354ef6250e94b509b4e0c0f1ea7e67bb diff --git a/ccan/io/io.h b/ccan/io/io.h index 6248fec0..3bc1c1fa 100644 --- a/ccan/io/io.h +++ b/ccan/io/io.h @@ -39,7 +39,8 @@ struct io_conn *io_new_conn_(int fd, struct io_plan plan); * * @finish will be called when an I/O operation fails, or you call * io_close() on the connection. errno will be set to the value - * after the failed I/O, or at the call to io_close(). + * after the failed I/O, or at the call to io_close(). The fd + * will be closed (unless a duplex) before @finish is called. * * Example: * static void finish(struct io_conn *conn, void *unused) @@ -290,6 +291,30 @@ struct io_plan io_write_partial_(const void *data, size_t *len, struct io_plan (*cb)(struct io_conn *, void*), void *arg); +/** + * io_always - plan to immediately call next callback. + * @cb: function to call. + * @arg: @cb argument + * + * Sometimes it's neater to plan a callback rather than call it directly; + * for example, if you only need to read data for one path and not another. + * + * Example: + * static void start_conn_with_nothing(int fd) + * { + * // Silly example: close on next time around loop. + * io_new_conn(fd, io_always(io_close_cb, NULL)); + * } + */ +#define io_always(cb, arg) \ + io_debug(io_always_(typesafe_cb_preargs(struct io_plan, void *, \ + (cb), (arg), \ + struct io_conn *), \ + (arg))) +struct io_plan io_always_(struct io_plan (*cb)(struct io_conn *, void *), + void *arg); + + /** * io_connect - plan to connect to a listening socket. * @fd: file descriptor. @@ -336,24 +361,37 @@ struct io_plan io_connect_(int fd, const struct addrinfo *addr, void *arg); /** - * io_idle - plan to do nothing. + * io_wait - plan to wait for something. + * @wait: the address to wait on. + * @cb: function to call after waiting. + * @arg: @cb argument * - * This indicates the connection is idle: io_wake() will be called later do - * give the connection a new plan. + * This indicates the connection is idle: io_wake() will be called later to + * restart the connection. * * Example: * struct io_conn *sleeper; - * sleeper = io_new_conn(open("/dev/null", O_RDONLY), io_idle()); + * unsigned int counter = 0; + * sleeper = io_new_conn(open("/dev/null", O_RDONLY), + * io_wait(&counter, io_close_cb, NULL)); * if (!sleeper) * exit(1); */ -#define io_idle() io_debug(io_idle_()) -struct io_plan io_idle_(void); +#define io_wait(wait, cb, arg) \ + io_debug(io_wait_(wait, \ + typesafe_cb_preargs(struct io_plan, void *, \ + (cb), (arg), \ + struct io_conn *), \ + (arg))) + +struct io_plan io_wait_(const void *wait, + struct io_plan (*cb)(struct io_conn *, void *), + void *arg); /** * io_timeout - set timeout function if the callback doesn't complete. * @conn: the current connection. - * @ts: how long until the timeout should be called. + * @t: how long until the timeout should be called. * @cb: callback to call. * @arg: argument to @cb. * @@ -381,7 +419,7 @@ struct io_plan io_idle_(void); (fn), (arg), \ struct io_conn *), \ (arg)) -bool io_timeout_(struct io_conn *conn, struct timespec ts, +bool io_timeout_(struct io_conn *conn, struct timerel t, struct io_plan (*fn)(struct io_conn *, void *), void *arg); /** @@ -416,20 +454,18 @@ bool io_timeout_(struct io_conn *conn, struct timespec ts, struct io_conn *io_duplex_(struct io_conn *conn, struct io_plan plan); /** - * io_wake - wake up an idle connection. - * @conn: an idle connection. - * @plan: the next I/O plan for @conn. - * - * This makes @conn ready to do I/O the next time around the io_loop(). + * io_wake - wake up any connections waiting on @wait + * @wait: the address to trigger. * * Example: - * struct io_conn *sleeper; - * sleeper = io_new_conn(open("/dev/null", O_RDONLY), io_idle()); + * unsigned int wait; * - * io_wake(sleeper, io_write("junk", 4, io_close_cb, NULL)); + * io_new_conn(open("/dev/null", O_RDONLY), + * io_wait(&wait, io_close_cb, NULL)); + * + * io_wake(&wait); */ -#define io_wake(conn, plan) (io_plan_no_debug(), io_wake_((conn), (plan))) -void io_wake_(struct io_conn *conn, struct io_plan plan); +void io_wake(const void *wait); /** * io_break - return from io_loop() @@ -451,6 +487,21 @@ void io_wake_(struct io_conn *conn, struct io_plan plan); #define io_break(ret, plan) (io_plan_no_debug(), io_break_((ret), (plan))) struct io_plan io_break_(void *ret, struct io_plan plan); +/** + * io_never - assert if callback is called. + * + * Sometimes you want to make it clear that a callback should never happen + * (eg. for io_break). This will assert() if called. + * + * Example: + * static struct io_plan break_out(struct io_conn *conn, void *unused) + * { + * // We won't ever return from io_break + * return io_break(conn, io_never()); + * } + */ +struct io_plan io_never(void); + /* FIXME: io_recvfrom/io_sendto */ /** @@ -480,6 +531,24 @@ struct io_plan io_close_(void); */ struct io_plan io_close_cb(struct io_conn *, void *unused); +/** + * io_close_other - close different connection next time around the I/O loop. + * @conn: the connection to close. + * + * This is used to force a different connection to close: no more I/O will + * happen on @conn, even if it's pending. + * + * It's a bug to use this on the current connection! + * + * Example: + * static void stop_connection(struct io_conn *conn) + * { + * printf("forcing stop on connection\n"); + * io_close_other(conn); + * } + */ +void io_close_other(struct io_conn *conn); + /** * io_loop - process fds until all closed on io_break. *