]> git.ozlabs.org Git - ccan/blobdiff - ccan/io/io.c
io: don't do wakeup immediately.
[ccan] / ccan / io / io.c
index 6d1c0522d131c8e15809b8deb2e84ba752710302..7dbb9c5a3962d3a802bf1aae502ceeda4bb1b685 100644 (file)
@@ -125,16 +125,28 @@ static struct io_plan *set_always(struct io_conn *conn,
        return io_set_plan(conn, dir, NULL, next, arg);
 }
 
+static struct io_plan *io_always_dir(struct io_conn *conn,
+                                    enum io_direction dir,
+                                    struct io_plan *(*next)(struct io_conn *,
+                                                            void *),
+                                    void *arg)
+{
+       return set_always(conn, dir, next, arg);
+}
+
 struct io_plan *io_always_(struct io_conn *conn,
                           struct io_plan *(*next)(struct io_conn *, void *),
                           void *arg)
 {
-       /* If we're duplex, we want this on the current plan.  Otherwise,
-        * doesn't matter. */
-       if (conn->plan[IO_IN].status == IO_UNSET)
-               return set_always(conn, IO_IN, next, arg);
-       else
-               return set_always(conn, IO_OUT, next, arg);
+       return io_always_dir(conn, IO_IN, next, arg);
+}
+
+struct io_plan *io_out_always_(struct io_conn *conn,
+                              struct io_plan *(*next)(struct io_conn *,
+                                                      void *),
+                              void *arg)
+{
+       return io_always_dir(conn, IO_OUT, next, arg);
 }
 
 static int do_write(int fd, struct io_plan_arg *arg)
@@ -294,22 +306,14 @@ struct io_plan *io_connect_(struct io_conn *conn, const struct addrinfo *addr,
        return io_set_plan(conn, IO_IN, do_connect, next, next_arg);
 }
 
-struct io_plan *io_wait_(struct io_conn *conn,
-                        const void *wait,
-                        struct io_plan *(*next)(struct io_conn *, void *),
-                        void *next_arg)
+static struct io_plan *io_wait_dir(struct io_conn *conn,
+                                  const void *wait,
+                                  enum io_direction dir,
+                                  struct io_plan *(*next)(struct io_conn *,
+                                                          void *),
+                                  void *next_arg)
 {
-       enum io_direction dir;
-       struct io_plan_arg *arg;
-
-       /* If we're duplex, we want this on the current plan.  Otherwise,
-        * doesn't matter. */
-       if (conn->plan[IO_IN].status == IO_UNSET)
-               dir = IO_IN;
-       else
-               dir = IO_OUT;
-
-       arg = io_plan_arg(conn, dir);
+       struct io_plan_arg *arg = io_plan_arg(conn, dir);
        arg->u1.const_vp = wait;
 
        conn->plan[dir].status = IO_WAITING;
@@ -317,6 +321,22 @@ struct io_plan *io_wait_(struct io_conn *conn,
        return io_set_plan(conn, dir, NULL, next, next_arg);
 }
 
+struct io_plan *io_wait_(struct io_conn *conn,
+                        const void *wait,
+                        struct io_plan *(*next)(struct io_conn *, void *),
+                        void *next_arg)
+{
+       return io_wait_dir(conn, wait, IO_IN, next, next_arg);
+}
+
+struct io_plan *io_out_wait_(struct io_conn *conn,
+                            const void *wait,
+                            struct io_plan *(*next)(struct io_conn *, void *),
+                            void *next_arg)
+{
+       return io_wait_dir(conn, wait, IO_OUT, next, next_arg);
+}
+
 void io_wake(const void *wait)
 {
        backend_wake(wait);
@@ -364,10 +384,13 @@ void io_do_always(struct io_conn *conn)
                next_plan(conn, &conn->plan[IO_OUT]);
 }
 
-void io_do_wakeup(struct io_conn *conn, struct io_plan *plan)
+void io_do_wakeup(struct io_conn *conn, enum io_direction dir)
 {
+       struct io_plan *plan = &conn->plan[dir];
+
        assert(plan->status == IO_WAITING);
-       next_plan(conn, plan);
+
+       set_always(conn, dir, plan->next, plan->next_arg);
 }
 
 /* Close the connection, we're done. */
@@ -437,6 +460,24 @@ struct io_plan *io_duplex_(struct io_plan *in_plan, struct io_plan *out_plan)
        return out_plan + 1;
 }
 
+struct io_plan *io_halfclose(struct io_conn *conn)
+{
+       /* Already closing?  Don't close twice. */
+       if (conn->plan[IO_IN].status == IO_CLOSING)
+               return &conn->plan[IO_IN];
+
+       /* Both unset?  OK. */
+       if (conn->plan[IO_IN].status == IO_UNSET
+           && conn->plan[IO_OUT].status == IO_UNSET)
+               return io_close(conn);
+
+       /* We leave this unset then. */
+       if (conn->plan[IO_IN].status == IO_UNSET)
+               return &conn->plan[IO_IN];
+       else
+               return &conn->plan[IO_OUT];
+}
+
 struct io_plan *io_set_plan(struct io_conn *conn, enum io_direction dir,
                            int (*io)(int fd, struct io_plan_arg *arg),
                            struct io_plan *(*next)(struct io_conn *, void *),