X-Git-Url: http://git.ozlabs.org/?p=ccan;a=blobdiff_plain;f=ccan%2Fio%2F_info;h=8f5c2adc3008fc58bfb4758331a9eb56e7812636;hp=d596b4deb11d401b40b3d2210eab80c8ceedff69;hb=b7e880755a5fad76f876bec31d6eabd0c5284151;hpb=1fe2db9cbe84812e1465db36f538a222e9984c93 diff --git a/ccan/io/_info b/ccan/io/_info index d596b4de..8f5c2adc 100644 --- a/ccan/io/_info +++ b/ccan/io/_info @@ -3,12 +3,18 @@ #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 @@ -19,104 +25,74 @@ * #include * #include * #include + * #include * * struct buffer { - * size_t max, off, rlen; - * char *buf; - * }; - * - * struct stdin_buffer { - * struct io_conn *reader, *writer; - * size_t len; - * char inbuf[4096]; + * bool finished; + * size_t start, end, rlen, wlen; + * char buf[4096]; * }; * - * // This reads from stdin. - * static struct io_op *wake_writer(struct io_conn *, struct stdin_buffer *); - * // This writes the stdin buffer to the child. - * static struct io_op *write_to_child(struct io_conn *c, - * struct stdin_buffer *b); - * static struct io_op *read_stdin(struct io_conn *c, struct stdin_buffer *b) + * static void finish(struct io_conn *c, struct buffer *b) * { - * assert(c == b->reader); - * b->len = sizeof(b->inbuf); - * return io_read_partial(b->inbuf, &b->len, - * io_next(c, wake_writer, b)); + * // Mark us finished. + * b->finished = true; + * // Wake writer just in case it's asleep. + * io_wake(b); * } * - * static struct io_op *wake_writer(struct io_conn *c, struct stdin_buffer *b) + * static struct io_plan read_in(struct io_conn *c, struct buffer *b) * { - * assert(c == b->reader); - * io_wake(b->writer, write_to_child, b); - * return io_idle(c); - * } + * // Add what we just read. + * b->end += b->rlen; + * assert(b->end <= sizeof(b->buf)); * - * static void reader_exit(struct io_conn *c, struct stdin_buffer *b) - * { - * assert(c == b->reader); - * io_wake(b->writer, write_to_child, b); - * b->reader = NULL; - * } + * // If we just read something, wake writer. + * if (b->rlen != 0) + * io_wake(b); * - * static struct io_op *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); - * } + * // If buffer is empty, return to start. + * if (b->start == b->end) + * b->start = b->end = 0; * - * static struct io_op *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(b->inbuf, b->len, io_next(conn, wake_reader, b)); - * } + * // Read in some of the rest. + * b->rlen = sizeof(b->buf) - b->end; * - * static struct io_op *start_writer(struct io_conn *conn, - * struct stdin_buffer *b) - * { - * assert(conn == b->writer); - * return io_idle(conn); - * } + * // No room? Wait for writer + * if (b->rlen == 0) + * return io_wait(b, read_in, b); * - * static void fail_child_write(struct io_conn *conn, struct stdin_buffer *b) - * { - * if (b->reader) - * err(1, "Failed writing to child."); + * return io_read_partial(b->buf + b->end, &b->rlen, read_in, b); * } * - * // This reads from the child and saves it into buffer. - * static struct io_op *read_from_child(struct io_conn *conn, - * struct buffer *b) + * static struct io_plan write_out(struct io_conn *c, struct 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); + * // Remove what we just wrote. + * b->start += b->wlen; + * assert(b->start <= sizeof(b->buf)); + * + * // If we wrote somthing, wake writer. + * if (b->wlen != 0) + * io_wake(b); + * + * b->wlen = b->end - b->start; + * // Nothing to write? Wait for reader. + * if (b->wlen == 0) { + * if (b->finished) + * return io_close(); + * return io_wait(b, write_out, b); * } * - * b->rlen = b->max - b->off; - * return io_read_partial(b->buf + b->off, &b->rlen, - * io_next(conn, read_from_child, b)); + * return io_write_partial(b->buf + b->start, &b->wlen, write_out, 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 stdin_buffer sbuf; + * struct buffer to, from; * int status; - * size_t off; - * ssize_t ret; + * struct io_conn *reader; * * if (argc == 1) * errx(1, "Usage: runner ..."); @@ -139,23 +115,20 @@ * 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)) - * err(1, "Allocating connections"); + * // Read from stdin, write to child. + * memset(&to, 0, sizeof(to)); + * reader = io_new_conn(STDIN_FILENO, read_in(NULL, &to)); + * io_set_finish(reader, finish, &to); + * io_new_conn(tochild[1], write_out(NULL, &to)); + * + * // Read from child, write to stdout. + * reader = io_new_conn(fromchild[0], read_in(NULL, &from)); + * io_set_finish(reader, finish, &from); + * io_new_conn(STDOUT_FILENO, write_out(NULL, &from)); * * io_loop(); * wait(&status); * - * for (off = 0; off < out.off; off += ret) { - * ret = write(STDOUT_FILENO, out.buf+off, out.off-off); - * if (ret < 0) - * err(1, "Writing stdout"); - * } - * free(out.buf); - * * return WIFEXITED(status) ? WEXITSTATUS(status) : 2; * } * @@ -168,6 +141,7 @@ int main(int argc, char *argv[]) return 1; if (strcmp(argv[1], "depends") == 0) { + printf("ccan/typesafe_cb\n"); printf("ccan/time\n"); printf("ccan/timer\n"); return 0;