From bfb80c566ab695b70a404a419f4b1450a2fcf27a Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 14 Oct 2013 21:28:35 +1030 Subject: [PATCH] ccan/io: use explicit IO callback functions, instead of io_state values. Explicit callbacks are slower, but more flexible. Signed-off-by: Rusty Russell --- ccan/io/backend.h | 17 +++--- ccan/io/io.c | 108 +++++++++++++++++++++--------------- ccan/io/test/run-06-idle.c | 4 +- ccan/io/test/run-07-break.c | 4 +- ccan/io/test/run-10-many.c | 12 ++-- 5 files changed, 82 insertions(+), 63 deletions(-) diff --git a/ccan/io/backend.h b/ccan/io/backend.h index bc88c289..86db8c3d 100644 --- a/ccan/io/backend.h +++ b/ccan/io/backend.h @@ -21,15 +21,14 @@ struct io_listener { void *conn_arg; }; -enum io_state { - /* These wait for something to input */ - READ, - READPART, - - /* These wait for room to output */ - WRITE, - WRITEPART, +enum io_result { + RESULT_AGAIN, + RESULT_FINISHED, + RESULT_CLOSE +}; +enum io_state { + IO, NEXT, /* eg starting, woken from idle, return from io_break. */ IDLE, FINISHED, @@ -82,6 +81,8 @@ struct io_conn { struct io_conn *duplex; struct io_timeout *timeout; + enum io_result (*io)(struct io_conn *conn); + int pollflag; /* 0, POLLIN or POLLOUT */ enum io_state state; union { diff --git a/ccan/io/io.c b/ccan/io/io.c index 150f7269..84be1758 100644 --- a/ccan/io/io.c +++ b/ccan/io/io.c @@ -119,6 +119,20 @@ bool io_timeout_(struct io_conn *conn, struct timespec ts, return true; } +static enum io_result do_write(struct io_conn *conn) +{ + ssize_t ret = write(conn->fd.fd, conn->u.write.buf, conn->u.write.len); + if (ret < 0) + return RESULT_CLOSE; + + conn->u.write.buf += ret; + conn->u.write.len -= ret; + if (conn->u.write.len == 0) + return RESULT_FINISHED; + else + return RESULT_AGAIN; +} + /* Queue some data to be written. */ struct io_plan *io_write_(struct io_conn *conn, const void *data, size_t len, struct io_plan *(*cb)(struct io_conn *, void *), @@ -126,10 +140,24 @@ struct io_plan *io_write_(struct io_conn *conn, const void *data, size_t len, { conn->u.write.buf = data; conn->u.write.len = len; + conn->io = do_write; conn->next = cb; conn->next_arg = arg; conn->pollflag = POLLOUT; - return to_ioplan(WRITE); + return to_ioplan(IO); +} + +static enum io_result do_read(struct io_conn *conn) +{ + ssize_t ret = read(conn->fd.fd, conn->u.read.buf, conn->u.read.len); + if (ret <= 0) + return RESULT_CLOSE; + conn->u.read.buf += ret; + conn->u.read.len -= ret; + if (conn->u.read.len == 0) + return RESULT_FINISHED; + else + return RESULT_AGAIN; } /* Queue a request to read into a buffer. */ @@ -139,10 +167,21 @@ struct io_plan *io_read_(struct io_conn *conn, void *data, size_t len, { conn->u.read.buf = data; conn->u.read.len = len; + conn->io = do_read; conn->next = cb; conn->next_arg = arg; conn->pollflag = POLLIN; - return to_ioplan(READ); + return to_ioplan(IO); +} + +static enum io_result do_read_partial(struct io_conn *conn) +{ + ssize_t ret = read(conn->fd.fd, conn->u.readpart.buf, + *conn->u.readpart.lenp); + if (ret <= 0) + return RESULT_CLOSE; + *conn->u.readpart.lenp = ret; + return RESULT_FINISHED; } /* Queue a partial request to read into a buffer. */ @@ -152,10 +191,21 @@ struct io_plan *io_read_partial_(struct io_conn *conn, void *data, size_t *len, { conn->u.readpart.buf = data; conn->u.readpart.lenp = len; + conn->io = do_read_partial; conn->next = cb; conn->next_arg = arg; conn->pollflag = POLLIN; - return to_ioplan(READPART); + return to_ioplan(IO); +} + +static enum io_result do_write_partial(struct io_conn *conn) +{ + ssize_t ret = write(conn->fd.fd, conn->u.writepart.buf, + *conn->u.writepart.lenp); + if (ret < 0) + return RESULT_CLOSE; + *conn->u.writepart.lenp = ret; + return RESULT_FINISHED; } /* Queue a partial write request. */ @@ -166,10 +216,11 @@ struct io_plan *io_write_partial_(struct io_conn *conn, { conn->u.writepart.buf = data; conn->u.writepart.lenp = len; + conn->io = do_write_partial; conn->next = cb; conn->next_arg = arg; conn->pollflag = POLLOUT; - return to_ioplan(WRITEPART); + return to_ioplan(IO); } struct io_plan *io_idle(struct io_conn *conn) @@ -200,50 +251,17 @@ static struct io_plan *do_next(struct io_conn *conn) struct io_plan *do_ready(struct io_conn *conn) { - ssize_t ret; - bool finished; - - switch (conn->state) { - case WRITE: - ret = write(conn->fd.fd, conn->u.write.buf, conn->u.write.len); - if (ret < 0) - return io_close(conn, NULL); - conn->u.write.buf += ret; - conn->u.write.len -= ret; - finished = (conn->u.write.len == 0); - break; - case WRITEPART: - ret = write(conn->fd.fd, conn->u.writepart.buf, - *conn->u.writepart.lenp); - if (ret < 0) - return io_close(conn, NULL); - *conn->u.writepart.lenp = ret; - finished = true; - break; - case READ: - ret = read(conn->fd.fd, conn->u.read.buf, conn->u.read.len); - if (ret <= 0) - return io_close(conn, NULL); - conn->u.read.buf += ret; - conn->u.read.len -= ret; - finished = (conn->u.read.len == 0); - break; - case READPART: - ret = read(conn->fd.fd, conn->u.readpart.buf, - *conn->u.readpart.lenp); - if (ret <= 0) - return io_close(conn, NULL); - *conn->u.readpart.lenp = ret; - finished = true; - break; + assert(conn->state == IO); + switch (conn->io(conn)) { + case RESULT_CLOSE: + return io_close(conn, NULL); + case RESULT_FINISHED: + return do_next(conn); + case RESULT_AGAIN: + return to_ioplan(conn->state); default: - /* Shouldn't happen. */ abort(); } - - if (finished) - return do_next(conn); - return to_ioplan(conn->state); } /* Useful next functions. */ diff --git a/ccan/io/test/run-06-idle.c b/ccan/io/test/run-06-idle.c index acf372f5..597060c2 100644 --- a/ccan/io/test/run-06-idle.c +++ b/ccan/io/test/run-06-idle.c @@ -16,7 +16,7 @@ struct data { char buf[4]; }; -static struct io_plan *do_read(struct io_conn *conn, struct data *d) +static struct io_plan *plan_read(struct io_conn *conn, struct data *d) { ok1(d->state == 2 || d->state == 3); d->state++; @@ -28,7 +28,7 @@ static struct io_plan *start_waker(struct io_conn *conn, struct data *d) ok1(d->state == 1); d->state++; - io_wake(idler, do_read, d); + io_wake(idler, plan_read, d); return io_close(conn, NULL); } diff --git a/ccan/io/test/run-07-break.c b/ccan/io/test/run-07-break.c index 327fa956..3dac4ece 100644 --- a/ccan/io/test/run-07-break.c +++ b/ccan/io/test/run-07-break.c @@ -11,7 +11,7 @@ struct data { char buf[4]; }; -static struct io_plan *do_read(struct io_conn *conn, struct data *d) +static struct io_plan *plan_read(struct io_conn *conn, struct data *d) { ok1(d->state == 1); d->state++; @@ -22,7 +22,7 @@ static struct io_plan *start_break(struct io_conn *conn, struct data *d) { ok1(d->state == 0); d->state++; - return io_break(conn, d, do_read, d); + return io_break(conn, d, plan_read, d); } static void finish_ok(struct io_conn *conn, struct data *d) diff --git a/ccan/io/test/run-10-many.c b/ccan/io/test/run-10-many.c index b20b2285..31369118 100644 --- a/ccan/io/test/run-10-many.c +++ b/ccan/io/test/run-10-many.c @@ -18,7 +18,7 @@ struct buffer { static struct io_plan *poke_writer(struct io_conn *conn, struct buffer *buf); static struct io_plan *poke_reader(struct io_conn *conn, struct buffer *buf); -static struct io_plan *do_read(struct io_conn *conn, struct buffer *buf) +static struct io_plan *plan_read(struct io_conn *conn, struct buffer *buf) { assert(conn == buf->reader); @@ -26,7 +26,7 @@ static struct io_plan *do_read(struct io_conn *conn, struct buffer *buf) poke_writer, buf); } -static struct io_plan *do_write(struct io_conn *conn, struct buffer *buf) +static struct io_plan *plan_write(struct io_conn *conn, struct buffer *buf) { assert(conn == buf->writer); @@ -42,7 +42,7 @@ static struct io_plan *poke_writer(struct io_conn *conn, struct buffer *buf) return io_close(conn, NULL); /* You write. */ - io_wake(buf->writer, do_write, buf); + io_wake(buf->writer, plan_write, buf); /* I'll wait until you wake me. */ return io_idle(conn); @@ -52,7 +52,7 @@ static struct io_plan *poke_reader(struct io_conn *conn, struct buffer *buf) { assert(conn == buf->writer); /* You read. */ - io_wake(buf->reader, do_read, buf); + io_wake(buf->reader, plan_read, buf); if (++buf->iters == NUM_ITERS) return io_close(conn, NULL); @@ -91,7 +91,7 @@ int main(void) buf[i].reader = io_new_conn(last_read, reader, NULL, &buf[i]); if (!buf[i].reader) break; - buf[i].writer = io_new_conn(fds[1], do_write, NULL, &buf[i]); + buf[i].writer = io_new_conn(fds[1], plan_write, NULL, &buf[i]); if (!buf[i].writer) break; last_read = fds[0]; @@ -104,7 +104,7 @@ int main(void) sprintf(buf[i].buf, "%i-%i", i, i); buf[i].reader = io_new_conn(last_read, reader, NULL, &buf[i]); ok1(buf[i].reader); - buf[i].writer = io_new_conn(last_write, do_write, NULL, &buf[i]); + buf[i].writer = io_new_conn(last_write, plan_write, NULL, &buf[i]); ok1(buf[i].writer); /* They should eventually exit */ -- 2.39.2