From d4af94ec86618e89b449a27590a7b4f8e4365943 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 14 Oct 2013 21:33:07 +1030 Subject: [PATCH] ccan/io: update and improve documentation. Signed-off-by: Rusty Russell --- ccan/io/_info | 18 +++++--- ccan/io/io.h | 102 +++++++++------------------------------------- ccan/io/io_plan.h | 100 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 132 insertions(+), 88 deletions(-) create mode 100644 ccan/io/io_plan.h diff --git a/ccan/io/_info b/ccan/io/_info index 8786272c..235e6ba3 100644 --- a/ccan/io/_info +++ b/ccan/io/_info @@ -3,12 +3,18 @@ #include "config.h" /** - * io - simple library for stateful io handling. - * - * io provides a simple mechanism to write I/O servers with multiple - * connections. Handling of connections is multiplexed, and function - * indicate what they want written or read, and what follow-on - * function to call on success (or failure). + * io - simple library for asynchronous io handling. + * + * io provides a mechanism to write I/O servers with multiple + * connections. Each callback indicates what I/O they plan next + * (eg. read, write). It is also possible to write custom I/O + * plans. + * + * When compiled with DEBUG, control flow is changed so that rather + * than returning to the main io_loop(), plans are executed sequentially + * providing a backtrace showing what has occurred on that connection. + * Which connection(s) do this depends on the user-specified io_debug + * function. * * Example: * // Given tr A-Z a-z outputs tr a-z a-z diff --git a/ccan/io/io.h b/ccan/io/io.h index 6553e7ab..828fb666 100644 --- a/ccan/io/io.h +++ b/ccan/io/io.h @@ -5,71 +5,12 @@ #include #include #include - -struct io_conn; - -/** - * struct io_plan - returned from a setup function. - * - * A plan of what IO to do, when. - */ -struct io_plan { - int pollflag; - /* Only NULL if idle. */ - int (*io)(int fd, struct io_plan *plan); - /* Only NULL if closing. */ - struct io_plan (*next)(struct io_conn *, void *arg); - void *next_arg; - - union { - struct { - char *buf; - size_t len; - } read; - struct { - const char *buf; - size_t len; - } write; - struct { - char *buf; - size_t *lenp; - } readpart; - struct { - const char *buf; - size_t *lenp; - } writepart; - struct { - int saved_errno; - } close; - struct { - void *p; - size_t len; - } ptr_len; - struct { - void *p1; - void *p2; - } ptr_ptr; - struct { - size_t len1; - size_t len2; - } len_len; - } u; -}; - -#ifdef DEBUG -extern bool io_plan_for_other; -extern bool (*io_debug)(struct io_conn *conn); -#define io_plan_other() ((io_plan_for_other = true)) -void io_plan_debug(struct io_plan *plan); -#else -#define io_plan_other() (void)0 -static inline void io_plan_debug(struct io_plan *plan) { } -#endif +#include "io_plan.h" /** * io_new_conn - create a new connection. * @fd: the file descriptor. - * @plan: the first I/O function. + * @plan: the first I/O to perform. * * This creates a connection which owns @fd. @plan will be called on the * next io_loop(). @@ -129,13 +70,13 @@ struct io_listener *io_new_listener_(int fd, void io_close_listener(struct io_listener *listener); /** - * io_write - queue data to be written. + * io_write - plan to write data. * @data: the data buffer. * @len: the length to write. * @cb: function to call once it's done. * @arg: @cb argument * - * This will queue the data buffer for writing. Once it's all + * This creates a plan write out a data buffer. Once it's all * written, the @cb function will be called: on an error, the finish * function is called instead. * @@ -151,15 +92,15 @@ struct io_plan io_write_(const void *data, size_t len, void *arg); /** - * io_read - queue buffer to be read. + * io_read - plan to read data. * @data: the data buffer. * @len: the length to read. * @cb: function to call once it's done. * @arg: @cb argument * - * This will queue the data buffer for reading. Once it's all read, - * the @cb function will be called: on an error, the finish function - * is called instead. + * This creates a plan to read data into a buffer. Once it's all + * read, the @cb function will be called: on an error, the finish + * function is called instead. * * Note that the I/O may actually be done immediately. */ @@ -174,13 +115,13 @@ struct io_plan io_read_(void *data, size_t len, /** - * io_read_partial - queue buffer to be read (partial OK). + * io_read_partial - plan to read some data. * @data: the data buffer. * @len: the maximum length to read, set to the length actually read. * @cb: function to call once it's done. * @arg: @cb argument * - * This will queue the data buffer for reading. Once any data is + * This creates a plan to read data into a buffer. Once any data is * read, @len is updated and the @cb function will be called: on an * error, the finish function is called instead. * @@ -196,13 +137,13 @@ struct io_plan io_read_partial_(void *data, size_t *len, void *arg); /** - * io_write_partial - queue data to be written (partial OK). + * io_write_partial - plan to write some data. * @data: the data buffer. * @len: the maximum length to write, set to the length actually written. * @cb: function to call once it's done. * @arg: @cb argument * - * This will queue the data buffer for writing. Once any data is + * This creates a plan to write data from a buffer. Once any data is * written, @len is updated and the @cb function will be called: on an * error, the finish function is called instead. * @@ -217,21 +158,19 @@ struct io_plan io_write_partial_(const void *data, size_t *len, struct io_plan (*cb)(struct io_conn *, void*), void *arg); - /** - * io_idle - explicitly note that this connection will do nothing. + * io_idle - plan to do nothing. * - * This indicates the connection is idle: some other function will - * later call io_read/io_write etc. (or io_close) on it, in which case - * it will do that. + * This indicates the connection is idle: io_wake() will be called later do + * give the connection a new plan. */ struct io_plan io_idle(void); /** - * io_timeout - set timeout function if the callback doesn't fire. + * io_timeout - set timeout function if the callback doesn't complete. * @conn: the current connection. * @ts: how long until the timeout should be called. - * @cb to call. + * @cb: callback to call. * @arg: argument to @cb. * * If the usual next callback is not called for this connection before @ts, @@ -256,7 +195,7 @@ bool io_timeout_(struct io_conn *conn, struct timespec ts, * @plan: the first I/O function to call. * * Sometimes you want to be able to simultaneously read and write on a - * single fd, but io forces a linear call sequence. The solition is + * single fd, but io forces a linear call sequence. The solution is * to have two connections for the same fd, and use one for read * operations and one for write. * @@ -264,15 +203,14 @@ bool io_timeout_(struct io_conn *conn, struct timespec ts, */ #define io_duplex(conn, plan) \ (io_plan_other(), io_duplex_((conn), (plan))) - 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 function for @conn. + * @plan: the next I/O plan for @conn. * - * This makes @conn do I/O the next time around the io_loop(). + * This makes @conn ready to do I/O the next time around the io_loop(). */ #define io_wake(conn, plan) (io_plan_other(), io_wake_((conn), (plan))) void io_wake_(struct io_conn *conn, struct io_plan plan); diff --git a/ccan/io/io_plan.h b/ccan/io/io_plan.h new file mode 100644 index 00000000..e87011e7 --- /dev/null +++ b/ccan/io/io_plan.h @@ -0,0 +1,100 @@ +/* Licensed under LGPLv2.1+ - see LICENSE file for details */ +#ifndef CCAN_IO_PLAN_H +#define CCAN_IO_PLAN_H +struct io_conn; + +/** + * struct io_plan - a plan of what I/O to do. + * @pollflag: POLLIN or POLLOUT. + * @io: function to call when fd is available for @pollflag. + * @next: function to call after @io returns true. + * @next_arg: argument to @next. + * @u: scratch area for I/O. + * + * When the fd is POLLIN or POLLOUT (according to @pollflag), @io is + * called. If it returns -1, io_close() becomed the new plan (and errno + * is saved). If it returns 1, @next is called, otherwise @io is + * called again when @pollflag is available. + * + * You can use this to write your own io_plan functions. + */ +struct io_plan { + int pollflag; + /* Only NULL if idle. */ + int (*io)(int fd, struct io_plan *plan); + /* Only NULL if closing. */ + struct io_plan (*next)(struct io_conn *, void *arg); + void *next_arg; + + union { + struct { + char *buf; + size_t len; + } read; + struct { + const char *buf; + size_t len; + } write; + struct { + char *buf; + size_t *lenp; + } readpart; + struct { + const char *buf; + size_t *lenp; + } writepart; + struct { + int saved_errno; + } close; + struct { + void *p; + size_t len; + } ptr_len; + struct { + void *p1; + void *p2; + } ptr_ptr; + struct { + size_t len1; + size_t len2; + } len_len; + } u; +}; + +#ifdef DEBUG +/** + * io_debug - routine to select connection(s) to debug. + * + * If this is set, the routine should return true if the connection is a + * debugging candidate. If so, the callchain for I/O operations on this + * connection will be linear, for easier use of a debugger. + */ +extern bool (*io_debug)(struct io_conn *conn); + +/** + * io_plan_other - mark the next plan not being for the current connection + * + * Most routines which take a plan are about to apply it to the current + * connection. We (ab)use this pattern for debugging: as soon as such a + * plan is created, it is called, to create a linear call chain. + * + * Some routines, like io_break() and io_wake() take an io_plan, but they + * must not be applied immediately to the current connection, so we call this + * first. + */ +#define io_plan_other() ((io_plan_for_other = true)) + +/** + * io_plan_debug - hook for debugging a plan. + * + * After constructing a plan, call this. If the current connection is being + * debugged, then it will be immediately serviced with this plan. + */ +void io_plan_debug(struct io_plan *plan); +extern bool io_plan_for_other; +#else +#define io_plan_other() (void)0 +static inline void io_plan_debug(struct io_plan *plan) { } +#endif + +#endif /* CCAN_IO_PLAN_H */ -- 2.39.2