X-Git-Url: http://git.ozlabs.org/?p=ccan;a=blobdiff_plain;f=ccan%2Fio%2Fio.h;h=d4ba2d87688e81143863e232d4c1eb34283ab602;hp=e2792844d885da16d5049514bc665ea0911519c1;hb=e92e2f65a9ae729a0c9805427da737ad936abddb;hpb=cdffdf5d61f8330cfc3467e73a84876eb3928e9b diff --git a/ccan/io/io.h b/ccan/io/io.h index e2792844..d4ba2d87 100644 --- a/ccan/io/io.h +++ b/ccan/io/io.h @@ -6,11 +6,6 @@ #include #include -enum io_direction { - IO_IN, - IO_OUT -}; - /** * struct io_plan - a plan for input or output. * @@ -340,7 +335,6 @@ struct io_plan *io_write_partial_(struct io_conn *conn, /** * io_always - plan to immediately call next callback * @conn: the connection that plan is for. - * @dir: IO_IN or IO_OUT * @next: function to call. * @arg: @next argument * @@ -352,16 +346,16 @@ struct io_plan *io_write_partial_(struct io_conn *conn, * void *unused) * { * // Silly example: close on next time around loop. - * return io_always(conn, IO_IN, io_close_cb, NULL); + * return io_always(conn, io_close_cb, NULL); * } */ -#define io_always(conn, dir, next, arg) \ - io_always_((conn), dir, typesafe_cb_preargs(struct io_plan *, void *, \ - (next), (arg), \ - struct io_conn *), \ +#define io_always(conn, next, arg) \ + io_always_((conn), typesafe_cb_preargs(struct io_plan *, void *, \ + (next), (arg), \ + struct io_conn *), \ (arg)) -struct io_plan *io_always_(struct io_conn *conn, enum io_direction dir, +struct io_plan *io_always_(struct io_conn *conn, struct io_plan *(*next)(struct io_conn *, void *), void *arg); @@ -409,11 +403,42 @@ struct io_plan *io_connect_(struct io_conn *conn, const struct addrinfo *addr, struct io_plan *(*next)(struct io_conn *, void *), void *arg); +/** + * io_duplex - set plans for both input and output. + * @conn: the connection that plan is for. + * @in: the input plan + * @out: the output plan + * + * Most plans are either for input or output; io_duplex creates a plan + * which does both. This is often used in the init function to create + * two independent streams, though it can be used once on any connection. + * + * Note that if either plan closes the connection, it will be closed. + * + * Note that if one plan is io_wait or io_always, that causes a problem: + * they look at the input and output plan slots to figure out which to + * use, but if the other plan hasn't been evaluated yet, that will fail. + * In this case, you'll need to ensure the other plan is evaluated first, + * eg. "struct io_plan *r = io_read(...); return io_duplex(r, io_always(...))" + * + * Example: + * struct buf { + * char in[100]; + * char out[100]; + * }; + * + * static struct io_plan *read_and_write(struct io_conn *conn, struct buf *b) + * { + * return io_duplex(io_read(conn, b->in, sizeof(b->in), io_close_cb, b), + * io_write(conn, b->out, sizeof(b->out), io_close_cb, b)); + * } + */ +struct io_plan *io_duplex(struct io_plan *in_plan, struct io_plan *out_plan); + /** * io_wait - leave a plan idle until something wakes us. * @conn: the connection that plan is for. * @waitaddr: the address to wait on. - * @dir: IO_IN or IO_OUT * @next: function to call after waiting. * @arg: @next argument * @@ -424,18 +449,18 @@ struct io_plan *io_connect_(struct io_conn *conn, const struct addrinfo *addr, * // Silly example to wait then close. * static struct io_plan *wait(struct io_conn *conn, void *b) * { - * return io_wait(conn, b, IO_IN, io_close_cb, NULL); + * return io_wait(conn, b, io_close_cb, NULL); * } */ -#define io_wait(conn, waitaddr, dir, next, arg) \ - io_wait_((conn), (waitaddr), (dir), \ +#define io_wait(conn, waitaddr, next, arg) \ + io_wait_((conn), (waitaddr), \ typesafe_cb_preargs(struct io_plan *, void *, \ (next), (arg), \ struct io_conn *), \ (arg)) struct io_plan *io_wait_(struct io_conn *conn, - const void *wait, enum io_direction dir, + const void *wait, struct io_plan *(*next)(struct io_conn *, void *), void *arg); @@ -478,6 +503,7 @@ void io_break(const void *ret); /** * io_never - assert if callback is called. * @conn: the connection that plan is for. + * @unused: an unused parameter to make this suitable for use as a callback. * * Sometimes you want to make it clear that a callback should never happen * (eg. for io_break). This will assert() if called. @@ -487,10 +513,10 @@ void io_break(const void *ret); * { * io_break(conn); * // We won't ever return from io_break - * return io_never(conn); + * return io_never(conn, NULL); * } */ -struct io_plan *io_never(struct io_conn *conn); +struct io_plan *io_never(struct io_conn *conn, void *unused); /* FIXME: io_recvfrom/io_sendto */