#include #include #include "config.h" /** * io - simple library for asynchronous io handling. * * 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 * #include * #include * #include * #include * #include * #include * #include * #include * * struct buffer { * bool finished; * size_t start, end, rlen, wlen; * char buf[4096]; * }; * * static void finish(struct io_conn *c, struct buffer *b) * { * // Mark us finished. * b->finished = true; * // Wake writer just in case it's asleep. * io_wake(b); * } * * static struct io_plan read_in(struct io_conn *c, struct buffer *b) * { * // Add what we just read. * b->end += b->rlen; * assert(b->end <= sizeof(b->buf)); * * // If we just read something, wake writer. * if (b->rlen != 0) * io_wake(b); * * // If buffer is empty, return to start. * if (b->start == b->end) * b->start = b->end = 0; * * // Read in some of the rest. * b->rlen = sizeof(b->buf) - b->end; * * // No room? Wait for writer * if (b->rlen == 0) * return io_wait(b, read_in, b); * * return io_read_partial(b->buf + b->end, &b->rlen, read_in, b); * } * * static struct io_plan write_out(struct io_conn *c, struct buffer *b) * { * // 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); * } * * 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 to, from; * int status; * struct io_conn *reader; * * if (argc == 1) * errx(1, "Usage: runner ..."); * * if (pipe(tochild) != 0 || pipe(fromchild) != 0) * err(1, "Creating pipes"); * * if (!fork()) { * // Child runs command. * close(tochild[1]); * close(fromchild[0]); * * dup2(tochild[0], STDIN_FILENO); * dup2(fromchild[1], STDOUT_FILENO); * execvp(argv[1], argv + 1); * exit(127); * } * * close(tochild[0]); * close(fromchild[1]); * signal(SIGPIPE, SIG_IGN); * * // 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); * * return WIFEXITED(status) ? WEXITSTATUS(status) : 2; * } * * License: LGPL (v2.1 or any later version) * Author: Rusty Russell */ int main(int argc, char *argv[]) { if (argc != 2) return 1; if (strcmp(argv[1], "depends") == 0) { printf("ccan/typesafe_cb\n"); printf("ccan/time\n"); printf("ccan/timer\n"); return 0; } return 1; }