ccan/io: pass struct io_plan explicitly.
authorRusty Russell <rusty@rustcorp.com.au>
Mon, 14 Oct 2013 10:58:35 +0000 (21:28 +1030)
committerRusty Russell <rusty@rustcorp.com.au>
Mon, 14 Oct 2013 10:58:35 +0000 (21:28 +1030)
This simplifies some things: in particular, we can construct an
io_plan without needing the current io_conn.

On the other hand, we need to expose the structure now.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
19 files changed:
ccan/io/_info
ccan/io/backend.h
ccan/io/benchmarks/run-different-speed.c
ccan/io/benchmarks/run-length-prefix.c
ccan/io/benchmarks/run-loop.c
ccan/io/io.c
ccan/io/io.h
ccan/io/poll.c
ccan/io/test/run-01-start-finish.c
ccan/io/test/run-02-read.c
ccan/io/test/run-03-readpartial.c
ccan/io/test/run-04-writepartial.c
ccan/io/test/run-05-write.c
ccan/io/test/run-06-idle.c
ccan/io/test/run-07-break.c
ccan/io/test/run-10-many.c
ccan/io/test/run-12-bidir.c
ccan/io/test/run-13-all-idle.c
ccan/io/test/run-15-timeout.c

index affd97b430a6ee5d070b4d91e9d2262a3f8177af..e7dfe9da7b817190ab1c97ab3fb2578b6bde07e5 100644 (file)
  * };
  *
  * // This reads from stdin.
- * static struct io_plan *wake_writer(struct io_conn *, struct stdin_buffer *);
+ * 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)
+ * 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_writer(struct io_conn *c, struct stdin_buffer *b)
+ * 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);
  *     b->reader = NULL;
  * }
  *
- * static struct io_plan *wake_reader(struct io_conn *c, struct stdin_buffer *b)
+ * 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,
+ * static struct io_plan write_to_child(struct io_conn *conn,
  *                                     struct stdin_buffer *b)
  * {
  *     assert(conn == b->writer);
@@ -73,8 +73,8 @@
  *     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)
+ * static struct io_plan start_writer(struct io_conn *conn,
+ *                                   struct stdin_buffer *b)
  * {
  *     assert(conn == b->writer);
  *     return io_idle(conn);
@@ -87,8 +87,8 @@
  * }
  *
  * // This reads from the child and saves it into buffer.
- * static struct io_plan *read_from_child(struct io_conn *conn,
- *                                       struct buffer *b)
+ * static struct io_plan read_from_child(struct io_conn *conn,
+ *                                      struct buffer *b)
  * {
  *     b->off += b->rlen;
  *
index 765e920ea9158d149eead5e5bb5d371d2d6f4531..c03ce2dc5f07e2709fa59744f2d0774d2f608551 100644 (file)
@@ -10,60 +10,21 @@ struct fd {
        size_t backend_info;
 };
 
-
 /* Listeners create connections. */
 struct io_listener {
        struct fd fd;
 
        /* These are for connections we create. */
-       struct io_plan *(*next)(struct io_conn *, void *arg);
+       struct io_plan (*next)(struct io_conn *, void *arg);
        void (*finish)(struct io_conn *, void *arg);
        void *conn_arg;
 };
 
-enum io_result {
-       RESULT_AGAIN,
-       RESULT_FINISHED,
-       RESULT_CLOSE
-};
-
-enum io_state {
-       IO_IO,
-       IO_NEXT, /* eg starting, woken from idle, return from io_break. */
-       IO_IDLE,
-       IO_FINISHED
-};
-
-static inline enum io_state from_ioplan(struct io_plan *op)
-{
-       return (enum io_state)(long)op;
-}
-
-struct io_state_read {
-       char *buf;
-       size_t len;
-};
-
-struct io_state_write {
-       const char *buf;
-       size_t len;
-};
-
-struct io_state_readpart {
-       char *buf;
-       size_t *lenp;
-};
-
-struct io_state_writepart {
-       const char *buf;
-       size_t *lenp;
-};
-
 struct io_timeout {
        struct timer timer;
        struct io_conn *conn;
 
-       struct io_plan *(*next)(struct io_conn *, void *arg);
+       struct io_plan (*next)(struct io_conn *, void *arg);
        void *next_arg;
 };
 
@@ -71,25 +32,13 @@ struct io_timeout {
 struct io_conn {
        struct fd fd;
 
-       struct io_plan *(*next)(struct io_conn *, void *arg);
-       void *next_arg;
-
        void (*finish)(struct io_conn *, void *arg);
        void *finish_arg;
 
        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 {
-               struct io_state_read read;
-               struct io_state_write write;
-               struct io_state_readpart readpart;
-               struct io_state_writepart writepart;
-       } u;
+       struct io_plan plan;
 };
 
 static inline bool timeout_active(const struct io_conn *conn)
@@ -107,5 +56,5 @@ void backend_wakeup(struct io_conn *conn);
 void backend_add_timeout(struct io_conn *conn, struct timespec ts);
 void backend_del_timeout(struct io_conn *conn);
 
-struct io_plan *do_ready(struct io_conn *conn);
+struct io_plan do_ready(struct io_conn *conn);
 #endif /* CCAN_IO_BACKEND_H */
index 10fa0b96ea2d1011a6e9d941ba76c5cedf194e61..537a67bbc01b5de934f63db04612e27d276f9415 100644 (file)
@@ -25,21 +25,21 @@ struct client {
        char reply_buffer[REPLY_SIZE];
 };
 
-static struct io_plan *write_reply(struct io_conn *conn, struct client *client);
-static struct io_plan *read_request(struct io_conn *conn, struct client *client)
+static struct io_plan write_reply(struct io_conn *conn, struct client *client);
+static struct io_plan read_request(struct io_conn *conn, struct client *client)
 {
        return io_read(conn, client->request_buffer, REQUEST_SIZE,
                       write_reply, client);
 }
 
 /* once we're done, loop again. */
-static struct io_plan *write_complete(struct io_conn *conn, struct client *client)
+static struct io_plan write_complete(struct io_conn *conn, struct client *client)
 {
        completed++;
        return read_request(conn, client);
 }
 
-static struct io_plan *write_reply(struct io_conn *conn, struct client *client)
+static struct io_plan write_reply(struct io_conn *conn, struct client *client)
 {
        return io_write(conn, client->reply_buffer, REPLY_SIZE,
                        write_complete, client);
@@ -106,12 +106,12 @@ static void sigalarm(int sig)
        write(timeout[1], "1", 1);
 }
 
-static struct io_plan *do_timeout(struct io_conn *conn, char *buf)
+static struct io_plan do_timeout(struct io_conn *conn, char *buf)
 {
        return io_break(conn, buf, NULL, NULL);
 }
 
-static struct io_plan *do_timeout_read(struct io_conn *conn, char *buf)
+static struct io_plan do_timeout_read(struct io_conn *conn, char *buf)
 {
        return io_read(conn, buf, 1, do_timeout, buf);
 }
index 74290fd8079ed8dfdbf79c137f393cef82ca4735..2ed9c72933f18d9a15a01f2c711752d0a103e61e 100644 (file)
@@ -25,28 +25,28 @@ struct client {
        char *request_buffer;
 };
 
-static struct io_plan *write_reply(struct io_conn *conn, struct client *client);
-static struct io_plan *read_body(struct io_conn *conn, struct client *client)
+static struct io_plan write_reply(struct io_conn *conn, struct client *client);
+static struct io_plan read_body(struct io_conn *conn, struct client *client)
 {
        assert(client->len <= REQUEST_MAX);
        return io_read(conn, client->request_buffer, client->len,
                       write_reply, client);
 }
 
-static struct io_plan *read_header(struct io_conn *conn, struct client *client)
+static struct io_plan read_header(struct io_conn *conn, struct client *client)
 {
        return io_read(conn, &client->len, sizeof(client->len),
                       read_body, client);
 }
 
 /* once we're done, loop again. */
-static struct io_plan *write_complete(struct io_conn *conn, struct client *client)
+static struct io_plan write_complete(struct io_conn *conn, struct client *client)
 {
        completed++;
        return read_header(conn, client);
 }
 
-static struct io_plan *write_reply(struct io_conn *conn, struct client *client)
+static struct io_plan write_reply(struct io_conn *conn, struct client *client)
 {
        return io_write(conn, &client->len, sizeof(client->len),
                        write_complete, client);
@@ -112,12 +112,12 @@ static void sigalarm(int sig)
        write(timeout[1], "1", 1);
 }
 
-static struct io_plan *do_timeout(struct io_conn *conn, char *buf)
+static struct io_plan do_timeout(struct io_conn *conn, char *buf)
 {
        return io_break(conn, buf, NULL, NULL);
 }
 
-static struct io_plan *do_timeout_read(struct io_conn *conn, char *buf)
+static struct io_plan do_timeout_read(struct io_conn *conn, char *buf)
 {
        return io_read(conn, buf, 1, do_timeout, buf);
 }
index 5dc1c3e11b628743165c0b2f160a04cd2fee976b..a2898e13e255f6b76e647df1d10aa603a1dfac6e 100644 (file)
@@ -16,24 +16,24 @@ struct buffer {
        char buf[32];
 };
 
-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 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 do_read(struct io_conn *conn, struct buffer *buf)
 {
        assert(conn == buf->reader);
 
        return io_read(conn, &buf->buf, sizeof(buf->buf), poke_writer, buf);
 }
 
-static struct io_plan *do_write(struct io_conn *conn, struct buffer *buf)
+static struct io_plan do_write(struct io_conn *conn, struct buffer *buf)
 {
        assert(conn == buf->writer);
 
        return io_write(conn, &buf->buf, sizeof(buf->buf), poke_reader, buf);
 }
 
-static struct io_plan *poke_writer(struct io_conn *conn, struct buffer *buf)
+static struct io_plan poke_writer(struct io_conn *conn, struct buffer *buf)
 {
        assert(conn == buf->reader);
 
@@ -47,7 +47,7 @@ static struct io_plan *poke_writer(struct io_conn *conn, struct buffer *buf)
        return io_idle(conn);
 }
 
-static struct io_plan *poke_reader(struct io_conn *conn, struct buffer *buf)
+static struct io_plan poke_reader(struct io_conn *conn, struct buffer *buf)
 {
        assert(conn == buf->writer);
        /* You read. */
@@ -60,7 +60,7 @@ static struct io_plan *poke_reader(struct io_conn *conn, struct buffer *buf)
        return io_idle(conn);
 }
 
-static struct io_plan *reader(struct io_conn *conn, struct buffer *buf)
+static struct io_plan reader(struct io_conn *conn, struct buffer *buf)
 {
        assert(conn == buf->reader);
 
index f7b46faaa5f8a5da64a07a9dc60caa67dd78d8fc..fe9fed4fc2350fef5ea28a46f6a0c162f1c2078e 100644 (file)
@@ -13,8 +13,8 @@
 void *io_loop_return;
 
 struct io_listener *io_new_listener_(int fd,
-                                    struct io_plan *(*start)(struct io_conn *,
-                                                             void *arg),
+                                    struct io_plan (*start)(struct io_conn *,
+                                                            void *arg),
                                     void (*finish)(struct io_conn *, void *),
                                     void *arg)
 {
@@ -43,7 +43,7 @@ void io_close_listener(struct io_listener *l)
 }
 
 struct io_conn *io_new_conn_(int fd,
-                            struct io_plan *(*start)(struct io_conn *, void *),
+                            struct io_plan (*start)(struct io_conn *, void *),
                             void (*finish)(struct io_conn *, void *),
                             void *arg)
 {
@@ -54,11 +54,11 @@ struct io_conn *io_new_conn_(int fd,
 
        conn->fd.listener = false;
        conn->fd.fd = fd;
-       conn->next = start;
+       conn->plan.next = start;
        conn->finish = finish;
-       conn->finish_arg = conn->next_arg = arg;
-       conn->pollflag = 0;
-       conn->state = IO_NEXT;
+       conn->finish_arg = conn->plan.next_arg = arg;
+       conn->plan.pollflag = 0;
+       conn->plan.state = IO_NEXT;
        conn->duplex = NULL;
        conn->timeout = NULL;
        if (!add_conn(conn)) {
@@ -69,7 +69,7 @@ struct io_conn *io_new_conn_(int fd,
 }
 
 struct io_conn *io_duplex_(struct io_conn *old,
-                            struct io_plan *(*start)(struct io_conn *, void *),
+                            struct io_plan (*start)(struct io_conn *, void *),
                             void (*finish)(struct io_conn *, void *),
                             void *arg)
 {
@@ -83,11 +83,11 @@ struct io_conn *io_duplex_(struct io_conn *old,
 
        conn->fd.listener = false;
        conn->fd.fd = old->fd.fd;
-       conn->next = start;
+       conn->plan.next = start;
        conn->finish = finish;
-       conn->finish_arg = conn->next_arg = arg;
-       conn->pollflag = 0;
-       conn->state = IO_NEXT;
+       conn->finish_arg = conn->plan.next_arg = arg;
+       conn->plan.pollflag = 0;
+       conn->plan.state = IO_NEXT;
        conn->duplex = old;
        conn->timeout = NULL;
        if (!add_duplex(conn)) {
@@ -98,13 +98,8 @@ struct io_conn *io_duplex_(struct io_conn *old,
        return conn;
 }
 
-static inline struct io_plan *to_ioplan(enum io_state state)
-{
-       return (struct io_plan *)(long)state;
-}
-
 bool io_timeout_(struct io_conn *conn, struct timespec ts,
-                struct io_plan *(*cb)(struct io_conn *, void *), void *arg)
+                struct io_plan (*cb)(struct io_conn *, void *), void *arg)
 {
        if (!conn->timeout) {
                conn->timeout = malloc(sizeof(*conn->timeout));
@@ -121,145 +116,165 @@ bool io_timeout_(struct io_conn *conn, struct timespec ts,
 
 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);
+       ssize_t ret = write(conn->fd.fd, conn->plan.u.write.buf, conn->plan.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)
+       conn->plan.u.write.buf += ret;
+       conn->plan.u.write.len -= ret;
+       if (conn->plan.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 *),
-                         void *arg)
+struct io_plan io_write_(struct io_conn *conn, const void *data, size_t len,
+                        struct io_plan (*cb)(struct io_conn *, void *),
+                        void *arg)
 {
-       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(IO_IO);
+       struct io_plan plan;
+
+       plan.u.write.buf = data;
+       plan.u.write.len = len;
+       plan.io = do_write;
+       plan.next = cb;
+       plan.next_arg = arg;
+       plan.pollflag = POLLOUT;
+       plan.state = IO_IO;
+       return plan;
 }
 
 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);
+       ssize_t ret = read(conn->fd.fd, conn->plan.u.read.buf,
+                          conn->plan.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)
+       conn->plan.u.read.buf += ret;
+       conn->plan.u.read.len -= ret;
+       if (conn->plan.u.read.len == 0)
                return RESULT_FINISHED;
        else
                return RESULT_AGAIN;
 }
 
 /* Queue a request to read into a buffer. */
-struct io_plan *io_read_(struct io_conn *conn, void *data, size_t len,
-                        struct io_plan *(*cb)(struct io_conn *, void *),
-                        void *arg)
+struct io_plan io_read_(struct io_conn *conn, void *data, size_t len,
+                       struct io_plan (*cb)(struct io_conn *, void *),
+                       void *arg)
 {
-       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(IO_IO);
+       struct io_plan plan;
+
+       plan.u.read.buf = data;
+       plan.u.read.len = len;
+       plan.io = do_read;
+       plan.next = cb;
+       plan.next_arg = arg;
+       plan.pollflag = POLLIN;
+       plan.state = IO_IO;
+       return plan;
 }
 
 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);
+       ssize_t ret = read(conn->fd.fd, conn->plan.u.readpart.buf,
+                          *conn->plan.u.readpart.lenp);
        if (ret <= 0)
                return RESULT_CLOSE;
-       *conn->u.readpart.lenp = ret;
+       *conn->plan.u.readpart.lenp = ret;
        return RESULT_FINISHED;
 }
 
 /* Queue a partial request to read into a buffer. */
-struct io_plan *io_read_partial_(struct io_conn *conn, void *data, size_t *len,
-                                struct io_plan *(*cb)(struct io_conn *, void *),
-                                void *arg)
+struct io_plan io_read_partial_(struct io_conn *conn, void *data, size_t *len,
+                               struct io_plan (*cb)(struct io_conn *, void *),
+                               void *arg)
 {
-       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(IO_IO);
+       struct io_plan plan;
+
+       plan.u.readpart.buf = data;
+       plan.u.readpart.lenp = len;
+       plan.io = do_read_partial;
+       plan.next = cb;
+       plan.next_arg = arg;
+       plan.pollflag = POLLIN;
+       plan.state = IO_IO;
+
+       return plan;
 }
 
 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);
+       ssize_t ret = write(conn->fd.fd, conn->plan.u.writepart.buf,
+                           *conn->plan.u.writepart.lenp);
        if (ret < 0)
                return RESULT_CLOSE;
-       *conn->u.writepart.lenp = ret;
+       *conn->plan.u.writepart.lenp = ret;
        return RESULT_FINISHED;
 }
 
 /* Queue a partial write request. */
-struct io_plan *io_write_partial_(struct io_conn *conn,
-                                 const void *data, size_t *len,
-                                 struct io_plan *(*cb)(struct io_conn*, void *),
-                                 void *arg)
+struct io_plan io_write_partial_(struct io_conn *conn,
+                                const void *data, size_t *len,
+                                struct io_plan (*cb)(struct io_conn*, void *),
+                                void *arg)
 {
-       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(IO_IO);
+       struct io_plan plan;
+
+       plan.u.writepart.buf = data;
+       plan.u.writepart.lenp = len;
+       plan.io = do_write_partial;
+       plan.next = cb;
+       plan.next_arg = arg;
+       plan.pollflag = POLLOUT;
+       plan.state = IO_IO;
+
+       return plan;
 }
 
-struct io_plan *io_idle(struct io_conn *conn)
+struct io_plan io_idle(struct io_conn *conn)
 {
-       conn->pollflag = 0;
-       return to_ioplan(IO_IDLE);
+       struct io_plan plan;
+
+       plan.pollflag = 0;
+       plan.state = IO_IDLE;
+
+       return plan;
 }
 
 void io_wake_(struct io_conn *conn,
-             struct io_plan *(*fn)(struct io_conn *, void *), void *arg)
+             struct io_plan (*fn)(struct io_conn *, void *), void *arg)
 
 {
        /* It might have finished, but we haven't called its finish() yet. */
-       if (conn->state == IO_FINISHED)
+       if (conn->plan.state == IO_FINISHED)
                return;
-       assert(conn->state == IO_IDLE);
-       conn->next = fn;
-       conn->next_arg = arg;
-       conn->state = IO_NEXT;
+       assert(conn->plan.state == IO_IDLE);
+       conn->plan.next = fn;
+       conn->plan.next_arg = arg;
+       conn->plan.pollflag = 0;
+       conn->plan.state = IO_NEXT;
        backend_wakeup(conn);
 }
 
-static struct io_plan *do_next(struct io_conn *conn)
+static struct io_plan do_next(struct io_conn *conn)
 {
        if (timeout_active(conn))
                backend_del_timeout(conn);
-       return conn->next(conn, conn->next_arg);
+       return conn->plan.next(conn, conn->plan.next_arg);
 }
 
-struct io_plan *do_ready(struct io_conn *conn)
+struct io_plan do_ready(struct io_conn *conn)
 {
-       assert(conn->state == IO_IO);
-       switch (conn->io(conn)) {
+       assert(conn->plan.state == IO_IO);
+       switch (conn->plan.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);
+               return conn->plan;
        default:
                abort();
        }
@@ -267,19 +282,29 @@ struct io_plan *do_ready(struct io_conn *conn)
 
 /* Useful next functions. */
 /* Close the connection, we're done. */
-struct io_plan *io_close(struct io_conn *conn, void *arg)
+struct io_plan io_close(struct io_conn *conn, void *arg)
 {
-       return to_ioplan(IO_FINISHED);
+       struct io_plan plan;
+
+       plan.state = IO_FINISHED;
+       plan.pollflag = 0;
+
+       return plan;
 }
 
 /* Exit the loop, returning this (non-NULL) arg. */
-struct io_plan *io_break_(struct io_conn *conn, void *ret,
-                         struct io_plan *(*fn)(struct io_conn *, void *),
-                         void *arg)
+struct io_plan io_break_(struct io_conn *conn, void *ret,
+                        struct io_plan (*fn)(struct io_conn *, void *),
+                        void *arg)
 {
+       struct io_plan plan;
+
        io_loop_return = ret;
-       conn->next = fn;
-       conn->next_arg = arg;
 
-       return to_ioplan(IO_NEXT);
+       plan.state = IO_NEXT;
+       plan.pollflag = 0;
+       plan.next = fn;
+       plan.next_arg = arg;
+
+       return plan;
 }
index 9b4797a558c241d43f2cf7723ed0b917997d195b..a027fe714aa5dc5c26432c44f327c486ec0e9831 100644 (file)
@@ -6,12 +6,60 @@
 #include <stdbool.h>
 #include <unistd.h>
 
+struct io_conn;
+
+struct io_state_read {
+       char *buf;
+       size_t len;
+};
+
+struct io_state_write {
+       const char *buf;
+       size_t len;
+};
+
+struct io_state_readpart {
+       char *buf;
+       size_t *lenp;
+};
+
+struct io_state_writepart {
+       const char *buf;
+       size_t *lenp;
+};
+
+enum io_result {
+       RESULT_AGAIN,
+       RESULT_FINISHED,
+       RESULT_CLOSE
+};
+
+enum io_state {
+       IO_IO,
+       IO_NEXT, /* eg starting, woken from idle, return from io_break. */
+       IO_IDLE,
+       IO_FINISHED
+};
+
 /**
- * struct io_plan - pointer to return from a setup function.
+ * struct io_plan - returned from a setup function.
  *
  * A plan of what IO to do, when.
  */
-struct io_plan;
+struct io_plan {
+       int pollflag;
+       enum io_state state;
+       enum io_result (*io)(struct io_conn *conn);
+       struct io_plan (*next)(struct io_conn *, void *arg);
+       void *next_arg;
+
+       union {
+               struct io_state_read read;
+               struct io_state_write write;
+               struct io_state_readpart readpart;
+               struct io_state_writepart writepart;
+       } u;
+};
 
 /**
  * io_new_conn - create a new connection.
@@ -32,13 +80,13 @@ struct io_plan;
  */
 #define io_new_conn(fd, start, finish, arg)                            \
        io_new_conn_((fd),                                              \
-                    typesafe_cb_preargs(struct io_plan *, void *,      \
+                    typesafe_cb_preargs(struct io_plan, void *,        \
                                         (start), (arg), struct io_conn *), \
                     typesafe_cb_preargs(void, void *, (finish), (arg), \
                                         struct io_conn *),             \
                     (arg))
 struct io_conn *io_new_conn_(int fd,
-                            struct io_plan *(*start)(struct io_conn *, void *),
+                            struct io_plan (*start)(struct io_conn *, void *),
                             void (*finish)(struct io_conn *, void *),
                             void *arg);
 
@@ -56,14 +104,14 @@ struct io_conn *io_new_conn_(int fd,
  */
 #define io_new_listener(fd, start, finish, arg)                                \
        io_new_listener_((fd),                                          \
-                        typesafe_cb_preargs(struct io_plan *, void *,  \
+                        typesafe_cb_preargs(struct io_plan, void *,    \
                                             (start), (arg),            \
                                             struct io_conn *),         \
                         typesafe_cb_preargs(void, void *, (finish),    \
                                             (arg), struct io_conn *),  \
                         (arg))
 struct io_listener *io_new_listener_(int fd,
-                                    struct io_plan *(*start)(struct io_conn *,
+                                    struct io_plan (*start)(struct io_conn *,
                                                              void *arg),
                                     void (*finish)(struct io_conn *,
                                                    void *arg),
@@ -93,12 +141,12 @@ void io_close_listener(struct io_listener *listener);
  */
 #define io_write(conn, data, len, cb, arg)                             \
        io_write_((conn), (data), (len),                                \
-                 typesafe_cb_preargs(struct io_plan *, void *,         \
+                 typesafe_cb_preargs(struct io_plan, void *,           \
                                      (cb), (arg), struct io_conn *),   \
                  (arg))
-struct io_plan *io_write_(struct io_conn *conn, const void *data, size_t len,
-                         struct io_plan *(*cb)(struct io_conn *, void *),
-                         void *arg);
+struct io_plan io_write_(struct io_conn *conn, const void *data, size_t len,
+                        struct io_plan (*cb)(struct io_conn *, void *),
+                        void *arg);
 
 /**
  * io_read - queue buffer to be read.
@@ -116,12 +164,12 @@ struct io_plan *io_write_(struct io_conn *conn, const void *data, size_t len,
  */
 #define io_read(conn, data, len, cb, arg)                              \
        io_read_((conn), (data), (len),                                 \
-                typesafe_cb_preargs(struct io_plan *, void *,          \
+                typesafe_cb_preargs(struct io_plan, void *,            \
                                     (cb), (arg), struct io_conn *),    \
                 (arg))
-struct io_plan *io_read_(struct io_conn *conn, void *data, size_t len,
-                        struct io_plan *(*cb)(struct io_conn *, void *),
-                        void *arg);
+struct io_plan io_read_(struct io_conn *conn, void *data, size_t len,
+                       struct io_plan (*cb)(struct io_conn *, void *),
+                       void *arg);
 
 
 /**
@@ -140,12 +188,12 @@ struct io_plan *io_read_(struct io_conn *conn, void *data, size_t len,
  */
 #define io_read_partial(conn, data, len, cb, arg)                      \
        io_read_partial_((conn), (data), (len),                         \
-                        typesafe_cb_preargs(struct io_plan *, void *,  \
+                        typesafe_cb_preargs(struct io_plan, void *,    \
                                             (cb), (arg), struct io_conn *), \
                         (arg))
-struct io_plan *io_read_partial_(struct io_conn *conn, void *data, size_t *len,
-                                struct io_plan *(*cb)(struct io_conn *, void *),
-                                void *arg);
+struct io_plan io_read_partial_(struct io_conn *conn, void *data, size_t *len,
+                               struct io_plan (*cb)(struct io_conn *, void *),
+                               void *arg);
 
 /**
  * io_write_partial - queue data to be written (partial OK).
@@ -163,13 +211,13 @@ struct io_plan *io_read_partial_(struct io_conn *conn, void *data, size_t *len,
  */
 #define io_write_partial(conn, data, len, cb, arg)                     \
        io_write_partial_((conn), (data), (len),                        \
-                         typesafe_cb_preargs(struct io_plan *, void *, \
+                         typesafe_cb_preargs(struct io_plan, void *,   \
                                              (cb), (arg), struct io_conn *), \
                          (arg))
-struct io_plan *io_write_partial_(struct io_conn *conn,
-                                 const void *data, size_t *len,
-                                 struct io_plan *(*cb)(struct io_conn *, void*),
-                                 void *arg);
+struct io_plan io_write_partial_(struct io_conn *conn,
+                                const void *data, size_t *len,
+                                struct io_plan (*cb)(struct io_conn *, void*),
+                                void *arg);
 
 
 /**
@@ -180,7 +228,7 @@ struct io_plan *io_write_partial_(struct io_conn *conn,
  * later call io_read/io_write etc. (or io_close) on it, in which case
  * it will do that.
  */
-struct io_plan *io_idle(struct io_conn *conn);
+struct io_plan io_idle(struct io_conn *conn);
 
 /**
  * io_timeout - set timeout function if the callback doesn't fire.
@@ -198,12 +246,12 @@ struct io_plan *io_idle(struct io_conn *conn);
  */
 #define io_timeout(conn, ts, fn, arg)                                  \
        io_timeout_((conn), (ts),                                       \
-                   typesafe_cb_preargs(struct io_plan *, void *,       \
+                   typesafe_cb_preargs(struct io_plan, void *,         \
                                        (fn), (arg),                    \
                                        struct io_conn *),              \
                    (arg))
 bool io_timeout_(struct io_conn *conn, struct timespec ts,
-                struct io_plan *(*fn)(struct io_conn *, void *), void *arg);
+                struct io_plan (*fn)(struct io_conn *, void *), void *arg);
 
 /**
  * io_duplex - split an fd into two connections.
@@ -221,14 +269,14 @@ bool io_timeout_(struct io_conn *conn, struct timespec ts,
  */
 #define io_duplex(conn, start, finish, arg)                            \
        io_duplex_((conn),                                              \
-                  typesafe_cb_preargs(struct io_plan *, void *,        \
+                  typesafe_cb_preargs(struct io_plan, void *,          \
                                       (start), (arg), struct io_conn *), \
                   typesafe_cb_preargs(void, void *, (finish), (arg),   \
                                       struct io_conn *),               \
                   (arg))
 
 struct io_conn *io_duplex_(struct io_conn *conn,
-                          struct io_plan *(*start)(struct io_conn *, void *),
+                          struct io_plan (*start)(struct io_conn *, void *),
                           void (*finish)(struct io_conn *, void *),
                           void *arg);
 
@@ -243,11 +291,11 @@ struct io_conn *io_duplex_(struct io_conn *conn,
  */
 #define io_wake(conn, fn, arg)                                         \
        io_wake_((conn),                                                \
-                typesafe_cb_preargs(struct io_plan *, void *,          \
+                typesafe_cb_preargs(struct io_plan, void *,            \
                                     (fn), (arg), struct io_conn *),    \
                 (arg))
 void io_wake_(struct io_conn *conn,
-             struct io_plan *(*fn)(struct io_conn *, void *), void *arg);
+             struct io_plan (*fn)(struct io_conn *, void *), void *arg);
 
 /**
  * io_break - return from io_loop()
@@ -264,12 +312,12 @@ void io_wake_(struct io_conn *conn,
  */
 #define io_break(conn, ret, fn, arg)                                   \
        io_break_((conn), (ret),                                        \
-                 typesafe_cb_preargs(struct io_plan *, void *,         \
+                 typesafe_cb_preargs(struct io_plan, void *,           \
                                      (fn), (arg), struct io_conn *),   \
                  (arg))
-struct io_plan *io_break_(struct io_conn *conn, void *ret,
-                         struct io_plan *(*fn)(struct io_conn *, void *),
-                         void *arg);
+struct io_plan io_break_(struct io_conn *conn, void *ret,
+                        struct io_plan (*fn)(struct io_conn *, void *),
+                        void *arg);
 
 /* FIXME: io_recvfrom/io_sendto */
 
@@ -284,7 +332,7 @@ struct io_plan *io_break_(struct io_conn *conn, void *ret,
  * It's common to 'return io_close(...)' from a @next function, but
  * io_close can also be used as an argument to io_next().
  */
-struct io_plan *io_close(struct io_conn *, void *unused);
+struct io_plan io_close(struct io_conn *, void *unused);
 
 /**
  * io_loop - process fds until all closed on io_break.
index 0cc84ad913bce7f2b58987407188b38fd0e7f9f9..adf7bb0c048ebfd94ce49edbbf73bd72e9855ebb 100644 (file)
@@ -101,9 +101,9 @@ static void del_conn(struct io_conn *conn)
                conn->duplex->duplex = NULL;
        } else
                del_fd(&conn->fd);
-       if (conn->state == IO_FINISHED)
+       if (conn->plan.state == IO_FINISHED)
                num_finished--;
-       else if (conn->state == IO_NEXT)
+       else if (conn->plan.state == IO_NEXT)
                num_next--;
 }
 
@@ -112,17 +112,16 @@ void del_listener(struct io_listener *l)
        del_fd(&l->fd);
 }
 
-static void backend_set_state(struct io_conn *conn, struct io_plan *plan)
+static void backend_set_state(struct io_conn *conn, struct io_plan plan)
 {
-       enum io_state state = from_ioplan(plan);
        struct pollfd *pfd = &pollfds[conn->fd.backend_info];
 
        if (pfd->events)
                num_waiting--;
 
-       pfd->events = conn->pollflag;
+       pfd->events = plan.pollflag;
        if (conn->duplex) {
-               int mask = conn->duplex->pollflag;
+               int mask = conn->duplex->plan.pollflag;
                /* You can't *both* read/write. */
                assert(!mask || pfd->events != mask);
                pfd->events |= mask;
@@ -130,12 +129,12 @@ static void backend_set_state(struct io_conn *conn, struct io_plan *plan)
        if (pfd->events)
                num_waiting++;
 
-       if (state == IO_NEXT)
+       if (plan.state == IO_NEXT)
                num_next++;
-       else if (state == IO_FINISHED)
+       else if (plan.state == IO_FINISHED)
                num_finished++;
 
-       conn->state = state;
+       conn->plan = plan;
 }
 
 void backend_wakeup(struct io_conn *conn)
@@ -174,12 +173,12 @@ static void finish_and_next(bool finished_only)
                        continue;
                c = (void *)fds[i];
                for (duplex = c->duplex; c; c = duplex, duplex = NULL) {
-                       if (c->state == IO_FINISHED) {
+                       if (c->plan.state == IO_FINISHED) {
                                del_conn(c);
                                free(c);
                                i--;
-                       } else if (!finished_only && c->state == IO_NEXT) {
-                               backend_set_state(c, c->next(c, c->next_arg));
+                       } else if (!finished_only && c->plan.state == IO_NEXT) {
+                               backend_set_state(c, c->plan.next(c, c->plan.next_arg));
                                num_next--;
                        }
                }
@@ -271,7 +270,7 @@ void *io_loop(void)
                        } else if (events & (POLLIN|POLLOUT)) {
                                r--;
                                if (c->duplex) {
-                                       int mask = c->duplex->pollflag;
+                                       int mask = c->duplex->plan.pollflag;
                                        if (events & mask) {
                                                ready(c->duplex);
                                                events &= ~mask;
index a2393d9fa2005cb58e244cc99ebf40974fbc16ce..7c6ae4155f3b052202d6dfb55f02c0b77f28479d 100644 (file)
@@ -6,7 +6,7 @@
 #include <sys/wait.h>
 #include <stdio.h>
 
-static struct io_plan *start_ok(struct io_conn *conn, int *state)
+static struct io_plan start_ok(struct io_conn *conn, int *state)
 {
        ok1(*state == 0);
        (*state)++;
index 4e1849096d98f1b36435c81a42437632ae160fd6..8b96f029825cdfc6490f3470593d448f2d7922dd 100644 (file)
@@ -11,7 +11,7 @@ struct data {
        char buf[4];
 };
 
-static struct io_plan *start_ok(struct io_conn *conn, struct data *d)
+static struct io_plan start_ok(struct io_conn *conn, struct data *d)
 {
        ok1(d->state == 0);
        d->state++;
index 9e97f49ac936892a076ddf4cd42c840090f6dcb6..e6e33e3d4baad6d6733bdac2a30de25af35bcb4a 100644 (file)
@@ -12,7 +12,7 @@ struct data {
        char buf[4];
 };
 
-static struct io_plan *start_ok(struct io_conn *conn, struct data *d)
+static struct io_plan start_ok(struct io_conn *conn, struct data *d)
 {
        ok1(d->state == 0);
        d->state++;
index 87fa8d9d0b22fef5b01da4d9d51473e602b4fada..d4e33c9674ecf625edfedd42d703302bc14d85b9 100644 (file)
@@ -12,7 +12,7 @@ struct data {
        char *buf;
 };
 
-static struct io_plan *start_ok(struct io_conn *conn, struct data *d)
+static struct io_plan start_ok(struct io_conn *conn, struct data *d)
 {
        ok1(d->state == 0);
        d->state++;
index 1181bec02fdaf612151691d5a05cd856acd2bb98..ad6760e4f09a465baffc241f4bc3a67658497016 100644 (file)
@@ -12,7 +12,7 @@ struct data {
        char *buf;
 };
 
-static struct io_plan *start_ok(struct io_conn *conn, struct data *d)
+static struct io_plan start_ok(struct io_conn *conn, struct data *d)
 {
        ok1(d->state == 0);
        d->state++;
index 597060c2b596f80b5a3b5a43e3539f3371a7fa01..19d0f8b1a682ddf33f0d9331cb8be8a41d77cfcd 100644 (file)
@@ -16,14 +16,14 @@ struct data {
        char buf[4];
 };
 
-static struct io_plan *plan_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++;
        return io_read(conn, d->buf, sizeof(d->buf), io_close, d);
 }
 
-static struct io_plan *start_waker(struct io_conn *conn, struct data *d)
+static struct io_plan start_waker(struct io_conn *conn, struct data *d)
 {
        ok1(d->state == 1);
        d->state++;
@@ -38,7 +38,7 @@ static void finish_waker(struct io_conn *conn, struct data *d)
        d->state++;
 }
 
-static struct io_plan *start_idle(struct io_conn *conn, struct data *d)
+static struct io_plan start_idle(struct io_conn *conn, struct data *d)
 {
        int fd;
 
index 3dac4ecee2d9e6c0af85c07ce5eb3f1322cae67c..5bc0e8c68be8ac4a89debb5f44e67ea3d0a47274 100644 (file)
@@ -11,14 +11,14 @@ struct data {
        char buf[4];
 };
 
-static struct io_plan *plan_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++;
        return io_read(conn, d->buf, sizeof(d->buf), io_close, d);
 }
 
-static struct io_plan *start_break(struct io_conn *conn, struct data *d)
+static struct io_plan start_break(struct io_conn *conn, struct data *d)
 {
        ok1(d->state == 0);
        d->state++;
index 313691187f6c63d059f03f0144e5a1fa6f2c48be..91b335e103216a4b371233d266a36cb0c8216e5f 100644 (file)
@@ -15,10 +15,10 @@ struct buffer {
        char buf[32];
 };
 
-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 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 *plan_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 *plan_read(struct io_conn *conn, struct buffer *buf)
                       poke_writer, buf);
 }
 
-static struct io_plan *plan_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);
 
@@ -34,7 +34,7 @@ static struct io_plan *plan_write(struct io_conn *conn, struct buffer *buf)
                        poke_reader, buf);
 }
 
-static struct io_plan *poke_writer(struct io_conn *conn, struct buffer *buf)
+static struct io_plan poke_writer(struct io_conn *conn, struct buffer *buf)
 {
        assert(conn == buf->reader);
 
@@ -48,7 +48,7 @@ static struct io_plan *poke_writer(struct io_conn *conn, struct buffer *buf)
        return io_idle(conn);
 }
 
-static struct io_plan *poke_reader(struct io_conn *conn, struct buffer *buf)
+static struct io_plan poke_reader(struct io_conn *conn, struct buffer *buf)
 {
        assert(conn == buf->writer);
        /* You read. */
@@ -61,7 +61,7 @@ static struct io_plan *poke_reader(struct io_conn *conn, struct buffer *buf)
        return io_idle(conn);
 }
 
-static struct io_plan *reader(struct io_conn *conn, struct buffer *buf)
+static struct io_plan reader(struct io_conn *conn, struct buffer *buf)
 {
        assert(conn == buf->reader);
 
index eb4f4f0551f71804396131ae23f148a87699770d..0cafb4f2454ac0f17bf489dc974129db82a96bca 100644 (file)
@@ -18,13 +18,13 @@ static void finish_ok(struct io_conn *conn, struct data *d)
        d->state++;
 }
 
-static struct io_plan *write_out(struct io_conn *conn, struct data *d)
+static struct io_plan write_out(struct io_conn *conn, struct data *d)
 {
        d->state++;
        return io_write(conn, d->wbuf, sizeof(d->wbuf), io_close, d);
 }
 
-static struct io_plan *start_ok(struct io_conn *conn, struct data *d)
+static struct io_plan start_ok(struct io_conn *conn, struct data *d)
 {
        ok1(d->state == 0);
        d->state++;
index 48be71dda7340a0671436aa101bd80edf6fddf4f..178b68a8fc3e045eae109102e41c4552a4b6700a 100644 (file)
@@ -7,7 +7,7 @@
 #include <stdio.h>
 #include <signal.h>
 
-static struct io_plan *start(struct io_conn *conn, void *unused)
+static struct io_plan start(struct io_conn *conn, void *unused)
 {
        return io_idle(conn);
 }
index 510a97203865af538352ef233d0486f8562d5c60..5e94b8c0168cc22cac6d36c9b4b4e7dc2a6524d1 100644 (file)
@@ -15,14 +15,14 @@ struct data {
 };
 
 
-static struct io_plan *no_timeout(struct io_conn *conn, struct data *d)
+static struct io_plan no_timeout(struct io_conn *conn, struct data *d)
 {
        ok1(d->state == 1);
        d->state++;
        return io_close(conn, d);
 }
 
-static struct io_plan *timeout(struct io_conn *conn, struct data *d)
+static struct io_plan timeout(struct io_conn *conn, struct data *d)
 {
        ok1(d->state == 1);
        d->state++;
@@ -30,7 +30,7 @@ static struct io_plan *timeout(struct io_conn *conn, struct data *d)
        return io_close(conn, d);
 }
 
-static struct io_plan *start_ok(struct io_conn *conn, struct data *d)
+static struct io_plan start_ok(struct io_conn *conn, struct data *d)
 {
        ok1(d->state == 0);
        d->state++;