]> git.ozlabs.org Git - ccan/blobdiff - ccan/io/io.h
ccan/io: implement timeouts.
[ccan] / ccan / io / io.h
index e2792844d885da16d5049514bc665ea0911519c1..165ff6f63361d395db25a4706d21eec51b5bbb1b 100644 (file)
@@ -6,10 +6,8 @@
 #include <stdbool.h>
 #include <unistd.h>
 
-enum io_direction {
-       IO_IN,
-       IO_OUT
-};
+struct timers;
+struct list_head;
 
 /**
  * struct io_plan - a plan for input or output.
@@ -174,7 +172,7 @@ struct io_listener *io_new_listener_(const tal_t *ctx, int fd,
  * ...
  *     struct io_listener *l = do_listen("8111");
  *     if (l) {
- *             io_loop();
+ *             io_loop(NULL, NULL);
  *             io_close_listener(l);
  *     }
  */
@@ -340,7 +338,6 @@ struct io_plan *io_write_partial_(struct io_conn *conn,
 /**
  * io_always - plan to immediately call next callback
  * @conn: the connection that plan is for.
- * @dir: IO_IN or IO_OUT
  * @next: function to call.
  * @arg: @next argument
  *
@@ -352,16 +349,16 @@ struct io_plan *io_write_partial_(struct io_conn *conn,
  *                                              void *unused)
  * {
  *     // Silly example: close on next time around loop.
- *     return io_always(conn, IO_IN, io_close_cb, NULL);
+ *     return io_always(conn, io_close_cb, NULL);
  * }
  */
-#define io_always(conn, dir, next, arg)                                        \
-       io_always_((conn), dir, typesafe_cb_preargs(struct io_plan *, void *, \
-                                                   (next), (arg),      \
-                                                   struct io_conn *),  \
+#define io_always(conn, next, arg)                                     \
+       io_always_((conn), typesafe_cb_preargs(struct io_plan *, void *, \
+                                              (next), (arg),           \
+                                              struct io_conn *),       \
                   (arg))
 
-struct io_plan *io_always_(struct io_conn *conn, enum io_direction dir,
+struct io_plan *io_always_(struct io_conn *conn,
                           struct io_plan *(*next)(struct io_conn *, void *),
                           void *arg);
 
@@ -409,11 +406,42 @@ struct io_plan *io_connect_(struct io_conn *conn, const struct addrinfo *addr,
                            struct io_plan *(*next)(struct io_conn *, void *),
                            void *arg);
 
+/**
+ * io_duplex - set plans for both input and output.
+ * @conn: the connection that plan is for.
+ * @in: the input plan
+ * @out: the output plan
+ *
+ * Most plans are either for input or output; io_duplex creates a plan
+ * which does both.  This is often used in the init function to create
+ * two independent streams, though it can be used once on any connection.
+ *
+ * Note that if either plan closes the connection, it will be closed.
+ *
+ * Note that if one plan is io_wait or io_always, that causes a problem:
+ * they look at the input and output plan slots to figure out which to
+ * use, but if the other plan hasn't been evaluated yet, that will fail.
+ * In this case, you'll need to ensure the other plan is evaluated first,
+ * eg. "struct io_plan *r = io_read(...); return io_duplex(r, io_always(...))"
+ *
+ * Example:
+ * struct buf {
+ *     char in[100];
+ *     char out[100];
+ * };
+ *
+ * static struct io_plan *read_and_write(struct io_conn *conn, struct buf *b)
+ * {
+ *     return io_duplex(io_read(conn, b->in, sizeof(b->in), io_close_cb, b),
+ *                      io_write(conn, b->out, sizeof(b->out), io_close_cb, b));
+ * }
+ */
+struct io_plan *io_duplex(struct io_plan *in_plan, struct io_plan *out_plan);
+
 /**
  * io_wait - leave a plan idle until something wakes us.
  * @conn: the connection that plan is for.
  * @waitaddr: the address to wait on.
- * @dir: IO_IN or IO_OUT
  * @next: function to call after waiting.
  * @arg: @next argument
  *
@@ -424,18 +452,18 @@ struct io_plan *io_connect_(struct io_conn *conn, const struct addrinfo *addr,
  * // Silly example to wait then close.
  * static struct io_plan *wait(struct io_conn *conn, void *b)
  * {
- *     return io_wait(conn, b, IO_IN, io_close_cb, NULL);
+ *     return io_wait(conn, b, io_close_cb, NULL);
  * }
  */
-#define io_wait(conn, waitaddr, dir, next, arg)                                \
-       io_wait_((conn), (waitaddr), (dir),                             \
+#define io_wait(conn, waitaddr, next, arg)                             \
+       io_wait_((conn), (waitaddr),                                    \
                 typesafe_cb_preargs(struct io_plan *, void *,          \
                                     (next), (arg),                     \
                                     struct io_conn *),                 \
                 (arg))
 
 struct io_plan *io_wait_(struct io_conn *conn,
-                        const void *wait, enum io_direction dir,
+                        const void *wait,
                         struct io_plan *(*next)(struct io_conn *, void *),
                         void *arg);
 
@@ -478,6 +506,7 @@ void io_break(const void *ret);
 /**
  * io_never - assert if callback is called.
  * @conn: the connection that plan is for.
+ * @unused: an unused parameter to make this suitable for use as a callback.
  *
  * Sometimes you want to make it clear that a callback should never happen
  * (eg. for io_break).  This will assert() if called.
@@ -487,10 +516,10 @@ void io_break(const void *ret);
  * {
  *     io_break(conn);
  *     // We won't ever return from io_break
- *     return io_never(conn);
+ *     return io_never(conn, NULL);
  * }
  */
-struct io_plan *io_never(struct io_conn *conn);
+struct io_plan *io_never(struct io_conn *conn, void *unused);
 
 /* FIXME: io_recvfrom/io_sendto */
 
@@ -527,14 +556,17 @@ struct io_plan *io_close_cb(struct io_conn *, void *unused);
 
 /**
  * io_loop - process fds until all closed on io_break.
+ * @timers - timers which are waiting to go off (or NULL for none)
+ * @expired - a list filled with expired timers (can be NULL if @timers is)
  *
  * This is the core loop; it exits with the io_break() arg, or NULL if
- * all connections and listeners are closed.
+ * all connections and listeners are closed, or with @expired set to a
+ * list of expired timers (if @timers isn't NULL).
  *
  * Example:
- *     io_loop();
+ *     io_loop(NULL, NULL);
  */
-void *io_loop(void);
+void *io_loop(struct timers *timers, struct list_head *expired);
 
 /**
  * io_conn_fd - get the fd from a connection.