+ * Note that if either plan closes the connection, it will be closed.
+ *
+ * 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));
+ * }
+ */
+#define io_duplex(conn, in_plan, out_plan) \
+ (io_duplex_prepare(conn), io_duplex_(in_plan, out_plan))
+
+struct io_plan *io_duplex_(struct io_plan *in_plan, struct io_plan *out_plan);
+void io_duplex_prepare(struct io_conn *conn);
+
+/**
+ * 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);
+ * }