+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 {
+ * 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.
+ * @waitaddr: the address to wait on.
+ * @next: function to call after waiting.
+ * @arg: @next argument
+ *
+ * This leaves the input or output idle: io_wake(@waitaddr) will be
+ * called later to restart the connection.
+ *
+ * Example:
+ * // Silly example to wait then close.
+ * static struct io_plan *wait(struct io_conn *conn, void *b)
+ * {
+ * return io_wait(conn, b, io_close_cb, NULL);
+ * }
+ */
+#define io_wait(conn, waitaddr, next, arg) \
+ io_wait_((conn), (waitaddr), \
+ typesafe_cb_preargs(struct io_plan *, void *, \
+ (next), (arg), \
+ struct io_conn *), \
+ (arg))
+
+struct io_plan *io_wait_(struct io_conn *conn,
+ const void *wait,
+ struct io_plan *(*next)(struct io_conn *, void *),
+ void *arg);