Browse Source

ccan/io: use explicit IO callback functions, instead of io_state values.

Explicit callbacks are slower, but more flexible.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Rusty Russell 12 years ago
parent
commit
bfb80c566a
5 changed files with 82 additions and 63 deletions
  1. 9 8
      ccan/io/backend.h
  2. 63 45
      ccan/io/io.c
  3. 2 2
      ccan/io/test/run-06-idle.c
  4. 2 2
      ccan/io/test/run-07-break.c
  5. 6 6
      ccan/io/test/run-10-many.c

+ 9 - 8
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 {

+ 63 - 45
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. */

+ 2 - 2
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);
 }
 

+ 2 - 2
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)

+ 6 - 6
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 */