X-Git-Url: http://git.ozlabs.org/?p=ccan;a=blobdiff_plain;f=ccan%2Fio%2Fio.h;h=9316dd180a9895adc2f60fdb6cdaeff6d77deb4a;hp=1341b6f209010861958dda6de1335e4e8518e161;hb=aae40e493625a07f4ac95476664447546b28661a;hpb=318f717e34e4735e5397bee24dbbee69205be82b diff --git a/ccan/io/io.h b/ccan/io/io.h index 1341b6f2..9316dd18 100644 --- a/ccan/io/io.h +++ b/ccan/io/io.h @@ -7,6 +7,7 @@ #include struct timers; +struct timer; struct list_head; /** @@ -362,6 +363,27 @@ struct io_plan *io_always_(struct io_conn *conn, struct io_plan *(*next)(struct io_conn *, void *), void *arg); +/** + * io_out_always - output plan to immediately call next callback + * @conn: the connection that plan is for. + * @next: function to call. + * @arg: @next argument + * + * This is a variant of io_always() which uses the output plan; it only + * matters if you are using io_duplex, and thus have two plans running at + * once. + */ +#define io_out_always(conn, next, arg) \ + io_out_always_((conn), typesafe_cb_preargs(struct io_plan *, void *, \ + (next), (arg), \ + struct io_conn *), \ + (arg)) + +struct io_plan *io_out_always_(struct io_conn *conn, + struct io_plan *(*next)(struct io_conn *, + void *), + void *arg); + /** * io_connect - create an asynchronous connection to a listening socket. * @conn: the connection that plan is for. @@ -418,12 +440,6 @@ struct io_plan *io_connect_(struct io_conn *conn, const struct addrinfo *addr, * * 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]; @@ -443,6 +459,34 @@ struct io_plan *io_connect_(struct io_conn *conn, const struct addrinfo *addr, struct io_plan *io_duplex_(struct io_plan *in_plan, struct io_plan *out_plan); void io_duplex_prepare(struct io_conn *conn); +/** + * io_halfclose - close half of an io_duplex connection. + * @conn: the connection that plan is for. + * + * It's common to want to close a duplex connection after both input and + * output plans have completed. If either calls io_close() the connection + * closes immediately. Instead, io_halfclose() needs to be called twice. + * + * Example: + * struct buf { + * char in[100]; + * char out[100]; + * }; + * + * static struct io_plan *finish(struct io_conn *conn, struct buf *b) + * { + * return io_halfclose(conn); + * } + * + * static struct io_plan *read_and_write(struct io_conn *conn, struct buf *b) + * { + * return io_duplex(conn, + * io_read(conn, b->in, sizeof(b->in), finish, b), + * io_write(conn, b->out, sizeof(b->out), finish, b)); + * } + */ +struct io_plan *io_halfclose(struct io_conn *conn); + /** * io_wait - leave a plan idle until something wakes us. * @conn: the connection that plan is for. @@ -473,6 +517,30 @@ struct io_plan *io_wait_(struct io_conn *conn, void *arg); +/** + * io_out_wait - leave the output plan idle until something wakes us. + * @conn: the connection that plan is for. + * @waitaddr: the address to wait on. + * @next: function to call after waiting. + * @arg: @next argument + * + * io_wait() makes the input plan idle: if you're not using io_duplex it + * doesn't matter which plan is waiting. Otherwise, you may need to use + * io_out_wait() instead, to specify explicitly that the output plan is + * waiting. + */ +#define io_out_wait(conn, waitaddr, next, arg) \ + io_out_wait_((conn), (waitaddr), \ + typesafe_cb_preargs(struct io_plan *, void *, \ + (next), (arg), \ + struct io_conn *), \ + (arg)) + +struct io_plan *io_out_wait_(struct io_conn *conn, + const void *wait, + struct io_plan *(*next)(struct io_conn *, void *), + void *arg); + /** * io_wake - wake up any connections waiting on @wait * @waitaddr: the address to trigger. @@ -562,16 +630,16 @@ 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) + * @expired - an expired timer (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, or with @expired set to a - * list of expired timers (if @timers isn't NULL). + * all connections and listeners are closed, or with @expired set to an + * expired timer (if @timers isn't NULL). * * Example: * io_loop(NULL, NULL); */ -void *io_loop(struct timers *timers, struct list_head *expired); +void *io_loop(struct timers *timers, struct timer **expired); /** * io_conn_fd - get the fd from a connection. @@ -581,6 +649,16 @@ void *io_loop(struct timers *timers, struct list_head *expired); */ int io_conn_fd(const struct io_conn *conn); +/** + * io_time_override - override the normal call for time. + * @nowfn: the function to call. + * + * io usually uses time_now() internally, but this forces it + * to use your function (eg. for debugging). Returns the old + * one. + */ +struct timeabs (*io_time_override(struct timeabs (*now)(void)))(void); + /** * io_set_debug - set synchronous mode on a connection. * @conn: the connection.