X-Git-Url: http://git.ozlabs.org/?p=ccan;a=blobdiff_plain;f=ccan%2Fio%2Fio.h;h=fe42b53736005c4459c3b56afbbaa87ffe46f04a;hp=d4ba2d87688e81143863e232d4c1eb34283ab602;hb=4f6d604ce616e70659b8494fd41ecd41e8fca30a;hpb=e92e2f65a9ae729a0c9805427da737ad936abddb diff --git a/ccan/io/io.h b/ccan/io/io.h index d4ba2d87..fe42b537 100644 --- a/ccan/io/io.h +++ b/ccan/io/io.h @@ -6,6 +6,10 @@ #include #include +struct timers; +struct timer; +struct list_head; + /** * struct io_plan - a plan for input or output. * @@ -43,7 +47,8 @@ struct io_conn; * int fd[2]; * struct io_conn *conn; * - * pipe(fd); + * if (pipe(fd) != 0) + * exit(1); * conn = io_new_conn(NULL, fd[0], conn_init, (const char *)"hi!"); * if (!conn) * exit(1); @@ -104,7 +109,8 @@ void io_set_finish_(struct io_conn *conn, * @arg: the argument to @init. * * When @fd becomes readable, we accept(), create a new connection, - * (tal'ocated off @ctx) and pass that to init(). + * (tal'ocated off @ctx) and pass that to init(). Note that if there is + * an error on this file descriptor, it will be freed. * * Returns NULL on error (and sets errno). * @@ -169,7 +175,7 @@ struct io_listener *io_new_listener_(const tal_t *ctx, int fd, * ... * struct io_listener *l = do_listen("8111"); * if (l) { - * io_loop(); + * io_loop(NULL, NULL); * io_close_listener(l); * } */ @@ -359,6 +365,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. @@ -415,11 +442,29 @@ 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]; + * char out[100]; + * }; + * + * 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), io_close_cb, b), + * io_write(conn, b->out, sizeof(b->out), io_close_cb,b)); + * } + */ +struct io_plan *io_duplex(struct io_conn *conn, + struct io_plan *in_plan, struct io_plan *out_plan); + +/** + * 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 { @@ -427,13 +472,19 @@ struct io_plan *io_connect_(struct io_conn *conn, const struct addrinfo *addr, * 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(io_read(conn, b->in, sizeof(b->in), io_close_cb, b), - * io_write(conn, b->out, sizeof(b->out), io_close_cb, 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_duplex(struct io_plan *in_plan, struct io_plan *out_plan); +struct io_plan *io_halfclose(struct io_conn *conn); /** * io_wait - leave a plan idle until something wakes us. @@ -465,6 +516,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. @@ -521,14 +596,16 @@ struct io_plan *io_never(struct io_conn *conn, void *unused); /* FIXME: io_recvfrom/io_sendto */ /** - * io_close - plan to close a connection. + * io_close - close a connection. * @conn: the connection to close. * - * On return to io_loop, the connection will be closed. It doesn't have - * to be the current connection and it doesn't need to be idle. No more - * IO or callbacks will occur. + * The connection is immediately freed: it doesn't have to be the + * current connection and it doesn't need to be idle. No more IO or + * callbacks will occur, but if a function was added by io_set_finish() + * it will be called with the current errno preserved. * - * You can close a connection twice without harmful effects. + * This is equivalent to tal_free(io_conn), except it returns an io_plan + * for use in an io callback. * * Example: * static struct io_plan *close_on_timeout(struct io_conn *conn, const char *msg) @@ -543,30 +620,85 @@ struct io_plan *io_close(struct io_conn *conn); * io_close_cb - helper callback to close a connection. * @conn: the connection. * - * This schedules a connection to be closed; designed to be used as - * a callback function. + * This is closes a connection; designed to be used as a callback + * function. * * Example: * #define close_on_timeout io_close_cb */ struct io_plan *io_close_cb(struct io_conn *, void *unused); +/** + * io_close_taken_fd - close a connection, but remove the filedescriptor first. + * @conn: the connection to take the file descriptor from and close. + * + * io_close closes the file descriptor underlying the io_conn; this version does + * not. Presumably you have used io_conn_fd() on it beforehand and will take + * care of the fd yourself. + * + * Note that this also turns off O_NONBLOCK on the fd. + * + * Example: + * static struct io_plan *steal_fd(struct io_conn *conn, int *fd) + * { + * *fd = io_conn_fd(conn); + * printf("stealing fd %i and closing\n", *fd); + * return io_close_taken_fd(conn); + * } + */ +struct io_plan *io_close_taken_fd(struct io_conn *conn); + /** * io_loop - process fds until all closed on io_break. + * @timers - timers which are waiting to go off (or NULL for none) + * @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. + * all connections and listeners are closed, or with @expired set to an + * expired timer (if @timers isn't NULL). * * Example: - * io_loop(); + * io_loop(NULL, NULL); */ -void *io_loop(void); +void *io_loop(struct timers *timers, struct timer **expired); /** * io_conn_fd - get the fd from a connection. * @conn: the connection. * - * Sometimes useful, eg for getsockname(). + * Sometimes useful, eg for getsockname(). Note that the fd is O_NONBLOCK. + * + * See Also: + * io_close_taken_fd */ int io_conn_fd(const struct io_conn *conn); + +/** + * io_flush_sync - (synchronously) complete any outstanding output. + * @conn: the connection. + * + * This is generally used as an emergency escape, for example when we + * want to write an error message on a socket before terminating, but it may + * be in the middle of existing I/O. We don't want to service any other + * IO, either. + * + * This returns true if all pending output is complete, false on error. + * The next callback is not called on the conn, but will be as soon as + * io_loop() is called. + * + * See Also: + * io_close_taken_fd + */ +bool io_flush_sync(struct io_conn *conn); + +/** + * io_time_override - override the normal call for time. + * @nowfn: the function to call. + * + * io usually uses time_mono() internally, but this forces it + * to use your function (eg. for debugging). Returns the old + * one. + */ +struct timemono (*io_time_override(struct timemono (*now)(void)))(void); + #endif /* CCAN_IO_H */