X-Git-Url: http://git.ozlabs.org/?a=blobdiff_plain;f=ccan%2Fio%2Fio.h;h=505c4c70a3fd5bc3f183a3927a2595d9776f9d2b;hb=f7ab2c65d40839a327e50876dc2708ab7b11aa52;hp=0318aef300873fa71104e0a2b630ad28e93e7065;hpb=83d4e1285dec87fa54043377eafd1b3bf9b0c53f;p=ccan diff --git a/ccan/io/io.h b/ccan/io/io.h index 0318aef3..505c4c70 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,19 +361,32 @@ 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. @@ -394,7 +432,7 @@ bool io_timeout_(struct io_conn *conn, struct timespec ts, * to have two connections for the same fd, and use one for read * operations and one for write. * - * Returning io_close() on one will close both fds! + * You must io_close() both of them to close the fd. * * Example: * static void setup_read_write(int fd, @@ -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. *