#include "config.h"
/**
- * io - simple library for stateful io handling.
+ * io - simple library for asynchronous 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 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
* // This reads from stdin.
* static struct io_plan wake_writer(struct io_conn *, struct stdin_buffer *);
* // This writes the stdin buffer to the child.
- * static struct io_plan write_to_child(struct io_conn *c,
- * struct stdin_buffer *b);
- * static struct io_plan read_stdin(struct io_conn *c, struct stdin_buffer *b)
- * {
- * assert(c == b->reader);
- * b->len = sizeof(b->inbuf);
- * return io_read_partial(c, b->inbuf, &b->len, wake_writer, b);
- * }
+ * static struct io_plan wake_reader(struct io_conn *, struct stdin_buffer *);
*
* static struct io_plan wake_writer(struct io_conn *c, struct stdin_buffer *b)
* {
* assert(c == b->reader);
- * io_wake(b->writer, write_to_child, b);
- * return io_idle(c);
+ * io_wake(b->writer, io_write(b->inbuf, b->len, wake_reader, b));
+ * return io_idle();
* }
*
* static void reader_exit(struct io_conn *c, struct stdin_buffer *b)
* {
* assert(c == b->reader);
- * io_wake(b->writer, write_to_child, b);
+ * io_wake(b->writer, io_close());
* b->reader = NULL;
* }
*
* static struct io_plan wake_reader(struct io_conn *c, struct stdin_buffer *b)
* {
* assert(c == b->writer);
- * io_wake(b->reader, read_stdin, b);
- * return io_idle(c);
- * }
- *
- * static struct io_plan write_to_child(struct io_conn *conn,
- * struct stdin_buffer *b)
- * {
- * assert(conn == b->writer);
- * if (!b->reader)
- * return io_close(conn, NULL);
- * return io_write(conn, b->inbuf, b->len, wake_reader, b);
- * }
- *
- * static struct io_plan start_writer(struct io_conn *conn,
- * struct stdin_buffer *b)
- * {
- * assert(conn == b->writer);
- * return io_idle(conn);
+ * if (!b->reader)
+ * return io_close();
+ * b->len = sizeof(b->inbuf);
+ * io_wake(b->reader, io_read_partial(b->inbuf, &b->len, wake_writer, b));
+ * return io_idle();
* }
*
* static void fail_child_write(struct io_conn *conn, struct stdin_buffer *b)
* {
* b->off += b->rlen;
*
- * if (b->off == b->max) {
- * if (b->max == 0)
- * b->max = 128;
- * else if (b->max >= 1024*1024)
- * b->max += 1024*1024;
- * else
- * b->max *= 2;
- * b->buf = realloc(b->buf, b->max);
- * }
+ * if (b->off == b->max)
+ * b->buf = realloc(b->buf, b->max *= 2);
*
* b->rlen = b->max - b->off;
- * return io_read_partial(conn, b->buf + b->off, &b->rlen,
- * read_from_child, b);
+ * return io_read_partial(b->buf + b->off, &b->rlen, read_from_child, b);
* }
*
* // Feed a program our stdin, gather its stdout, print that at end.
* int main(int argc, char *argv[])
* {
* int tochild[2], fromchild[2];
- * struct buffer out = { 0, 0, 0, NULL };
+ * struct buffer out;
* struct stdin_buffer sbuf;
* int status;
* size_t off;
* ssize_t ret;
+ * struct io_conn *from_child;
*
* if (argc == 1)
* errx(1, "Usage: runner <cmdline>...");
* close(fromchild[1]);
* signal(SIGPIPE, SIG_IGN);
*
- * sbuf.reader = io_new_conn(STDIN_FILENO, read_stdin, reader_exit, &sbuf);
- * sbuf.writer = io_new_conn(tochild[1], start_writer, fail_child_write,
- * &sbuf);
- * if (!sbuf.reader || !sbuf.writer
- * || !io_new_conn(fromchild[0], read_from_child, NULL, &out))
+ * sbuf.len = sizeof(sbuf.inbuf);
+ * sbuf.reader = io_new_conn(STDIN_FILENO,
+ * io_read_partial(sbuf.inbuf, &sbuf.len,
+ * wake_writer, &sbuf));
+ * sbuf.writer = io_new_conn(tochild[1], io_idle());
+ *
+ * out.max = 128;
+ * out.off = 0;
+ * out.rlen = 128;
+ * out.buf = malloc(out.max);
+ * from_child = io_new_conn(fromchild[0],
+ * io_read_partial(out.buf, &out.rlen,
+ * read_from_child, &out));
+ * if (!sbuf.reader || !sbuf.writer || !from_child)
* err(1, "Allocating connections");
*
+ * io_set_finish(sbuf.reader, reader_exit, &sbuf);
+ * io_set_finish(sbuf.writer, fail_child_write, &sbuf);
+ *
* io_loop();
* wait(&status);
*