X-Git-Url: https://git.ozlabs.org/?p=ccan;a=blobdiff_plain;f=ccan%2Fio%2Fio_plan.h;h=21a1921734f41e83d2ed836e157e4849496fb8ad;hp=57c7b976bdaee4d07fb76057d38afd02875c4ce5;hb=6109a0a6140acbbfe5e998f7d7ea1215f035cb90;hpb=cece098555b7138082373d5c0ddfa8074da18dda diff --git a/ccan/io/io_plan.h b/ccan/io/io_plan.h index 57c7b976..21a19217 100644 --- a/ccan/io/io_plan.h +++ b/ccan/io/io_plan.h @@ -4,147 +4,55 @@ 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_arg - scratch space 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 io_plan_arg { + char *cp; + void *vp; + const void *const_vp; + size_t s; + char c[sizeof(size_t)]; +}; - 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; +enum io_plan_status { + /* As before calling next function. */ + IO_UNSET, + /* Normal. */ + IO_POLLING, + /* Waiting for io_wake */ + IO_WAITING, + /* Always do this. */ + IO_ALWAYS, + /* Closing (both plans will be the same). */ + IO_CLOSING }; -#ifdef DEBUG -/** - * io_debug_conn - 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. - * - * You will also see calls to any callbacks which wake the connection - * which is being debugged. - * - * Example: - * static bool debug_all(struct io_conn *conn) - * { - * return true(); - * } - * ... - * io_debug_conn = debug_all; - */ -extern bool (*io_debug_conn)(struct io_conn *conn); +enum io_direction { + IO_IN, + IO_OUT +}; /** - * io_debug - if we're debugging the current connection, call immediately. - * - * This determines if we are debugging the current connection: if so, - * it immediately applies the plan and calls back into io_loop() to - * create a linear call chain. - * - * Example: - * #define io_idle() io_debug(io_idle_()) - * struct io_plan io_idle_(void); + * struct io_plan - one half of I/O to do + * @status: the status of this plan. + * @io: function to call when fd becomes read/writable, returns 0 to be + * called again, 1 if it's finished, and -1 on error (fd will be closed) + * @next: the next function which is called if io returns 1. + * @next_arg: the argument to @next + * @u1, @u2: scratch space for @io. */ -struct io_plan io_debug(struct io_plan plan); +struct io_plan { + enum io_plan_status status; -/** - * io_debug_io - return from function which actually does I/O. - * - * This determines if we are debugging the current connection: if so, - * it immediately sets the next function and calls into io_loop() to - * create a linear call chain. - * - * Example: - * - * static int do_write(int fd, struct io_plan *plan) - * { - * ssize_t ret = write(fd, plan->u.write.buf, plan->u.write.len); - * if (ret < 0) - * return io_debug_io(-1); - * - * plan->u.write.buf += ret; - * plan->u.write.len -= ret; - * return io_debug_io(plan->u.write.len == 0); - * } - */ -int io_debug_io(int ret); + int (*io)(int fd, struct io_plan *plan); -/** - * io_plan_no_debug - mark the next plan not to be called immediately. - * - * 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(), io_duplex() and io_wake() take an - * io_plan, but they must not be applied immediately to the current - * connection, so we call this first. - * - * Example: - * #define io_break(ret, plan) (io_plan_no_debug(), io_break_((ret), (plan))) - * struct io_plan io_break_(void *ret, struct io_plan plan); - */ -#define io_plan_no_debug() ((io_plan_nodebug = true)) + struct io_plan *(*next)(struct io_conn *, void *arg); + void *next_arg; + + union io_plan_arg u1, u2; +}; -extern bool io_plan_nodebug; -#else -static inline struct io_plan io_debug(struct io_plan plan) -{ - return plan; -} -static inline int io_debug_io(int ret) -{ - return ret; -} -#define io_plan_no_debug() (void)0 -#endif +/* Helper to get a conn's io_plan. */ +struct io_plan *io_get_plan(struct io_conn *conn, enum io_direction dir); #endif /* CCAN_IO_PLAN_H */