X-Git-Url: http://git.ozlabs.org/?p=ccan;a=blobdiff_plain;f=ccan%2Fio%2Fio_plan.h;h=1d503133b6ddb24f4f50cb2e4d12c4fb3e9732d3;hp=e87011e7d6a193e7591f2cdc44b400cb11b5ef0d;hb=b089d462e533d2b304cc28b9ad277cbfa53f12ce;hpb=d4af94ec86618e89b449a27590a7b4f8e4365943 diff --git a/ccan/io/io_plan.h b/ccan/io/io_plan.h index e87011e7..1d503133 100644 --- a/ccan/io/io_plan.h +++ b/ccan/io/io_plan.h @@ -4,97 +4,75 @@ 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. + * union io_plan_union - type for struct io_plan read/write fns. */ -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; +union io_plan_union { + char *cp; + void *vp; + const void *const_vp; + size_t s; + char c[sizeof(size_t)]; }; -#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. + * struct io_plan_arg - scratch space for struct io_plan read/write fns. */ -extern bool (*io_debug)(struct io_conn *conn); +struct io_plan_arg { + union io_plan_union u1, u2; +}; + +enum io_direction { + IO_IN, + IO_OUT +}; /** - * io_plan_other - mark the next plan not being for the current connection + * io_plan_arg - get a conn's io_plan_arg for a given direction. + * @conn: the connection. + * @dir: IO_IN or IO_OUT. * - * 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. + * This is how an io helper gets scratch space to store into; you must call + * io_set_plan() when you've initialized it. * - * 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. + * Example: + * #include + * + * // Simple helper to read a single char. + * static int do_readchar(int fd, struct io_plan_arg *arg) + * { + * return read(fd, arg->u1.cp, 1) <= 0 ? -1 : 1; + * } + * + * static struct io_plan *io_read_char_(struct io_conn *conn, char *in, + * struct io_plan *(*next)(struct io_conn*,void*), + * void *next_arg) + * { + * struct io_plan_arg *arg = io_plan_arg(conn, IO_IN); + * + * // Store information we need in the plan unions u1 and u2. + * arg->u1.cp = in; + * + * return io_set_plan(conn, IO_IN, do_readchar, next, next_arg); + * } */ -#define io_plan_other() ((io_plan_for_other = true)) +struct io_plan_arg *io_plan_arg(struct io_conn *conn, enum io_direction dir); /** - * io_plan_debug - hook for debugging a plan. + * io_set_plan - set a conn's io_plan. + * @conn: the connection. + * @dir: IO_IN or IO_OUT. + * @io: the IO function to call when the fd is ready. + * @next: the next callback when @io returns 1. + * @next_arg: the argument to @next. + * + * If @conn has debug set, the io function will be called immediately, + * so it's important that this be the last thing in your function! * - * After constructing a plan, call this. If the current connection is being - * debugged, then it will be immediately serviced with this plan. + * See also: + * io_get_plan_arg() */ -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 - +struct io_plan *io_set_plan(struct io_conn *conn, enum io_direction dir, + int (*io)(int fd, struct io_plan_arg *arg), + struct io_plan *(*next)(struct io_conn *, void *), + void *next_arg); #endif /* CCAN_IO_PLAN_H */