ccan/io: flatten debug callchain.
authorRusty Russell <rusty@rustcorp.com.au>
Mon, 14 Oct 2013 11:03:07 +0000 (21:33 +1030)
committerRusty Russell <rusty@rustcorp.com.au>
Mon, 14 Oct 2013 11:03:07 +0000 (21:33 +1030)
Don't call from the plan-construction function, call after it returns.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
20 files changed:
ccan/io/backend.h
ccan/io/io.c
ccan/io/io.h
ccan/io/io_plan.h
ccan/io/test/run-01-start-finish-DEBUG.c
ccan/io/test/run-02-read-DEBUG.c
ccan/io/test/run-03-readpartial-DEBUG.c
ccan/io/test/run-04-writepartial-DEBUG.c
ccan/io/test/run-05-write-DEBUG.c
ccan/io/test/run-06-idle-DEBUG.c
ccan/io/test/run-07-break-DEBUG.c
ccan/io/test/run-08-hangup-on-idle-DEBUG.c
ccan/io/test/run-08-read-after-hangup-DEBUG.c
ccan/io/test/run-10-many-DEBUG.c
ccan/io/test/run-12-bidir-DEBUG.c
ccan/io/test/run-13-all-idle-DEBUG.c
ccan/io/test/run-15-timeout-DEBUG.c
ccan/io/test/run-17-homemade-io-DEBUG.c
ccan/io/test/run-17-homemade-io.c
ccan/io/test/run-18-errno-DEBUG.c

index fa4cf8ee9f638ec5a32f9d671b7a9ffe0d649d10..df168d9f2b696202265de7bec1c96f35e1b65bca 100644 (file)
@@ -55,7 +55,7 @@ static inline void set_current(struct io_conn *conn)
 }
 static inline bool doing_debug(void)
 {
-       return io_debug != NULL;
+       return io_debug_conn != NULL;
 }
 #else
 static inline void set_current(struct io_conn *conn)
index b6ae56acf027a7c0a46b3a2c9027d07d7bd9617b..a4489ee8855c5a67fce5d746672342b345c72dc5 100644 (file)
 void *io_loop_return;
 
 #ifdef DEBUG
-bool io_plan_for_other;
+/* Set to skip the next plan. */
+bool io_plan_nodebug;
+/* The current connection to apply plan to. */
 struct io_conn *current;
-bool (*io_debug)(struct io_conn *conn);
+/* User-defined function to select which connection(s) to debug. */
+bool (*io_debug_conn)(struct io_conn *conn);
+/* Set when we wake up an connection we are debugging. */
 bool io_debug_wakeup;
 
-void io_plan_debug(struct io_plan *plan)
+struct io_plan io_debug(struct io_plan plan)
 {
-       if (io_plan_for_other) {
-               io_plan_for_other = false;
-               return;
+       if (io_plan_nodebug) {
+               io_plan_nodebug = false;
+               return plan;
        }
 
-       if (!io_debug || !current)
-               return;
+       if (!io_debug_conn || !current)
+               return plan;
 
-       if (!io_debug(current) && !io_debug_wakeup)
-               return;
+       if (!io_debug_conn(current) && !io_debug_wakeup)
+               return plan;
 
        io_debug_wakeup = false;
-       current->plan = *plan;
+       current->plan = plan;
        backend_plan_changed(current);
 
        /* Call back into the loop immediately. */
        io_loop_return = io_loop();
+       return plan;
 }
 
 static void debug_io_wake(struct io_conn *conn)
 {
        /* We want linear if we wake a debugged connection, too. */
-       if (io_debug && io_debug(conn))
+       if (io_debug_conn && io_debug_conn(conn))
                io_debug_wakeup = true;
 }
+
+/* Counterpart to io_plan_no_debug(), called in macros in io.h */
+static void io_plan_debug_again(void)
+{
+       io_plan_nodebug = false;
+}
 #else
 static void debug_io_wake(struct io_conn *conn)
 {
 }
+static void io_plan_debug_again(void)
+{
+}
 #endif
 
 struct io_listener *io_new_listener_(int fd,
@@ -82,6 +96,8 @@ struct io_conn *io_new_conn_(int fd, struct io_plan plan)
 {
        struct io_conn *conn = malloc(sizeof(*conn));
 
+       io_plan_debug_again();
+
        if (!conn)
                return NULL;
 
@@ -111,6 +127,8 @@ struct io_conn *io_duplex_(struct io_conn *old, struct io_plan plan)
 {
        struct io_conn *conn;
 
+       io_plan_debug_again();
+
        assert(!old->duplex);
 
        conn = malloc(sizeof(*conn));
@@ -177,7 +195,6 @@ struct io_plan io_write_(const void *data, size_t len,
        plan.next_arg = arg;
        plan.pollflag = POLLOUT;
 
-       io_plan_debug(&plan);
        return plan;
 }
 
@@ -207,7 +224,6 @@ struct io_plan io_read_(void *data, size_t len,
        plan.next_arg = arg;
        plan.pollflag = POLLIN;
 
-       io_plan_debug(&plan);
        return plan;
 }
 
@@ -236,7 +252,6 @@ struct io_plan io_read_partial_(void *data, size_t *len,
        plan.next_arg = arg;
        plan.pollflag = POLLIN;
 
-       io_plan_debug(&plan);
        return plan;
 }
 
@@ -265,26 +280,26 @@ struct io_plan io_write_partial_(const void *data, size_t *len,
        plan.next_arg = arg;
        plan.pollflag = POLLOUT;
 
-       io_plan_debug(&plan);
        return plan;
 }
 
-struct io_plan io_idle(void)
+struct io_plan io_idle_(void)
 {
        struct io_plan plan;
 
        plan.pollflag = 0;
        plan.io = NULL;
        /* Never called (overridden by io_wake), but NULL means closing */
-       plan.next = (void *)io_idle;
+       plan.next = (void *)io_idle_;
 
-       io_plan_debug(&plan);
        return plan;
 }
 
 void io_wake_(struct io_conn *conn, struct io_plan plan)
 
 {
+       io_plan_debug_again();
+
        /* It might be closing, but we haven't called its finish() yet. */
        if (!conn->plan.next)
                return;
@@ -318,7 +333,7 @@ void io_ready(struct io_conn *conn)
 }
 
 /* Close the connection, we're done. */
-struct io_plan io_close(void)
+struct io_plan io_close_(void)
 {
        struct io_plan plan;
 
@@ -327,7 +342,6 @@ struct io_plan io_close(void)
        plan.next = NULL;
        plan.u.close.saved_errno = errno;
 
-       io_plan_debug(&plan);
        return plan;
 }
 
@@ -339,6 +353,8 @@ struct io_plan io_close_cb(struct io_conn *conn, void *arg)
 /* Exit the loop, returning this (non-NULL) arg. */
 struct io_plan io_break_(void *ret, struct io_plan plan)
 {
+       io_plan_debug_again();
+
        assert(ret);
        io_loop_return = ret;
 
index 828fb666f50fcde0acdfbe107467c000ecedd2ba..c85a5b8c5abda95afae4463574f0c648a60a6b3d 100644 (file)
@@ -18,7 +18,7 @@
  * Returns NULL on error (and sets errno).
  */
 #define io_new_conn(fd, plan)                          \
-       (io_plan_other(), io_new_conn_((fd), (plan)))
+       (io_plan_no_debug(), io_new_conn_((fd), (plan)))
 struct io_conn *io_new_conn_(int fd, struct io_plan plan);
 
 /**
@@ -83,10 +83,10 @@ void io_close_listener(struct io_listener *listener);
  * Note that the I/O may actually be done immediately.
  */
 #define io_write(data, len, cb, arg)                                   \
-       io_write_((data), (len),                                        \
-                 typesafe_cb_preargs(struct io_plan, void *,           \
-                                     (cb), (arg), struct io_conn *),   \
-                 (arg))
+       io_debug(io_write_((data), (len),                               \
+                          typesafe_cb_preargs(struct io_plan, void *,  \
+                                              (cb), (arg), struct io_conn *), \
+                          (arg)))
 struct io_plan io_write_(const void *data, size_t len,
                         struct io_plan (*cb)(struct io_conn *, void *),
                         void *arg);
@@ -105,10 +105,10 @@ struct io_plan io_write_(const void *data, size_t len,
  * Note that the I/O may actually be done immediately.
  */
 #define io_read(data, len, cb, arg)                                    \
-       io_read_((data), (len),                                         \
-                typesafe_cb_preargs(struct io_plan, void *,            \
-                                    (cb), (arg), struct io_conn *),    \
-                (arg))
+       io_debug(io_read_((data), (len),                                \
+                         typesafe_cb_preargs(struct io_plan, void *,   \
+                                             (cb), (arg), struct io_conn *), \
+                         (arg)))
 struct io_plan io_read_(void *data, size_t len,
                        struct io_plan (*cb)(struct io_conn *, void *),
                        void *arg);
@@ -128,10 +128,11 @@ struct io_plan io_read_(void *data, size_t len,
  * Note that the I/O may actually be done immediately.
  */
 #define io_read_partial(data, len, cb, arg)                            \
-       io_read_partial_((data), (len),                                 \
-                        typesafe_cb_preargs(struct io_plan, void *,    \
-                                            (cb), (arg), struct io_conn *), \
-                        (arg))
+       io_debug(io_read_partial_((data), (len),                        \
+                                 typesafe_cb_preargs(struct io_plan, void *, \
+                                                     (cb), (arg),      \
+                                                     struct io_conn *), \
+                                 (arg)))
 struct io_plan io_read_partial_(void *data, size_t *len,
                                struct io_plan (*cb)(struct io_conn *, void *),
                                void *arg);
@@ -150,10 +151,11 @@ struct io_plan io_read_partial_(void *data, size_t *len,
  * Note that the I/O may actually be done immediately.
  */
 #define io_write_partial(data, len, cb, arg)                           \
-       io_write_partial_((data), (len),                                \
-                         typesafe_cb_preargs(struct io_plan, void *,   \
-                                             (cb), (arg), struct io_conn *), \
-                         (arg))
+       io_debug(io_write_partial_((data), (len),                       \
+                                  typesafe_cb_preargs(struct io_plan, void *, \
+                                                      (cb), (arg),     \
+                                                      struct io_conn *), \
+                                  (arg)))
 struct io_plan io_write_partial_(const void *data, size_t *len,
                                 struct io_plan (*cb)(struct io_conn *, void*),
                                 void *arg);
@@ -164,7 +166,8 @@ struct io_plan io_write_partial_(const void *data, size_t *len,
  * This indicates the connection is idle: io_wake() will be called later do
  * give the connection a new plan.
  */
-struct io_plan io_idle(void);
+#define io_idle() io_debug(io_idle_())
+struct io_plan io_idle_(void);
 
 /**
  * io_timeout - set timeout function if the callback doesn't complete.
@@ -202,7 +205,7 @@ bool io_timeout_(struct io_conn *conn, struct timespec ts,
  * You must io_close() both of them to close the fd.
  */
 #define io_duplex(conn, plan)                          \
-       (io_plan_other(), io_duplex_((conn), (plan)))
+       (io_plan_no_debug(), io_duplex_((conn), (plan)))
 struct io_conn *io_duplex_(struct io_conn *conn, struct io_plan plan);
 
 /**
@@ -212,7 +215,7 @@ struct io_conn *io_duplex_(struct io_conn *conn, struct io_plan plan);
  *
  * This makes @conn ready to do I/O the next time around the io_loop().
  */
-#define io_wake(conn, plan) (io_plan_other(), io_wake_((conn), (plan)))
+#define io_wake(conn, plan) (io_plan_no_debug(), io_wake_((conn), (plan)))
 void io_wake_(struct io_conn *conn, struct io_plan plan);
 
 /**
@@ -226,7 +229,7 @@ void io_wake_(struct io_conn *conn, struct io_plan plan);
  *
  * If io_loop() is called again, then @plan will be carried out.
  */
-#define io_break(ret, plan) (io_plan_other(), io_break_((ret), (plan)))
+#define io_break(ret, plan) (io_plan_no_debug(), io_break_((ret), (plan)))
 struct io_plan io_break_(void *ret, struct io_plan plan);
 
 /* FIXME: io_recvfrom/io_sendto */
@@ -236,7 +239,8 @@ struct io_plan io_break_(void *ret, struct io_plan plan);
  *
  * On return to io_loop, the connection will be closed.
  */
-struct io_plan io_close(void);
+#define io_close() io_debug(io_close_())
+struct io_plan io_close_(void);
 
 /**
  * io_close_cb - helper callback to close a connection.
index e87011e7d6a193e7591f2cdc44b400cb11b5ef0d..86be1d70d080721c1d490ae9c0e680e242470918 100644 (file)
@@ -63,38 +63,43 @@ struct io_plan {
 
 #ifdef DEBUG
 /**
- * io_debug - routine to select connection(s) to debug.
+ * io_debug_conn - routine to select connection(s) to debug.
  *
  * If this is set, the routine should return true if the connection is a
  * debugging candidate.  If so, the callchain for I/O operations on this
  * connection will be linear, for easier use of a debugger.
  */
-extern bool (*io_debug)(struct io_conn *conn);
+extern bool (*io_debug_conn)(struct io_conn *conn);
 
 /**
- * io_plan_other - mark the next plan not being for the current connection
+ * io_debug - if we're debugging the current connection, call immediately.
  *
- * Most routines which take a plan are about to apply it to the current
- * connection.  We (ab)use this pattern for debugging: as soon as such a
- * plan is created, it is called, to create a linear call chain.
- *
- * Some routines, like io_break() and io_wake() take an io_plan, but they
- * must not be applied immediately to the current connection, so we call this
- * first.
+ * This determines if we are debugging the current connection: if so,
+ * it immediately applies the plan and calls back into io_loop() to
+ * create a linear call chain.
  */
-#define io_plan_other() ((io_plan_for_other = true))
+struct io_plan io_debug(struct io_plan plan);
 
 /**
- * io_plan_debug - hook for debugging a plan.
+ * io_plan_no_debug - mark the next plan not to be called immediately.
  *
- * After constructing a plan, call this.  If the current connection is being
- * debugged, then it will be immediately serviced with this plan.
+ * Most routines which take a plan are about to apply it to the current
+ * connection.  We (ab)use this pattern for debugging: as soon as such a
+ * plan is created it is called, to create a linear call chain.
+ *
+ * Some routines, like io_break(), io_duplex() and io_wake() take an
+ * io_plan, but they must not be applied immediately to the current
+ * connection, so we call this first.
  */
-void io_plan_debug(struct io_plan *plan);
-extern bool io_plan_for_other;
+#define io_plan_no_debug() ((io_plan_nodebug = true))
+
+extern bool io_plan_nodebug;
 #else
-#define io_plan_other() (void)0
-static inline void io_plan_debug(struct io_plan *plan) { }
+static inline struct io_plan io_debug(struct io_plan plan)
+{
+       return plan;
+}
+#define io_plan_no_debug() (void)0
 #endif
 
 #endif /* CCAN_IO_PLAN_H */
index 48f0f3e53f1924574c020b9f3a4e16cf34e1f015..9e33f2bc5080b76c18994846d0655bc0d252cc30 100644 (file)
@@ -5,4 +5,4 @@ int real_main(void);
 #include "run-01-start-finish.c"
 #undef main
 static bool always_debug(struct io_conn *conn) { return true; }
-int main(void) { io_debug = always_debug; return real_main(); }
+int main(void) { io_debug_conn = always_debug; return real_main(); }
index d48260cfc5686cf0ed282df6cddd658f170cb231..5ca278187983a5ed091241212ebd22098c91153c 100644 (file)
@@ -5,4 +5,4 @@ int real_main(void);
 #include "run-02-read.c"
 #undef main
 static bool always_debug(struct io_conn *conn) { return true; }
-int main(void) { io_debug = always_debug; return real_main(); }
+int main(void) { io_debug_conn = always_debug; return real_main(); }
index f23cc312f44a67bcd572ada7016e416d042ecf9d..c473b65c75aaaaaa9fe34c4fced2d31dc4a290c7 100644 (file)
@@ -5,4 +5,4 @@ int real_main(void);
 #include "run-03-readpartial.c"
 #undef main
 static bool always_debug(struct io_conn *conn) { return true; }
-int main(void) { io_debug = always_debug; return real_main(); }
+int main(void) { io_debug_conn = always_debug; return real_main(); }
index 515bd466c5fe6405548274a36422b6f2698d2635..fa65bcf568147e3350c5996b30d8b67cef1a3bb0 100644 (file)
@@ -5,4 +5,4 @@ int real_main(void);
 #include "run-04-writepartial.c"
 #undef main
 static bool always_debug(struct io_conn *conn) { return true; }
-int main(void) { io_debug = always_debug; return real_main(); }
+int main(void) { io_debug_conn = always_debug; return real_main(); }
index ae5eb1077942fbc57be0d363be9f8ba9aca945ff..831e6719bb54d00c5a2bd8b73637af0b17d89866 100644 (file)
@@ -5,4 +5,4 @@ int real_main(void);
 #include "run-05-write.c"
 #undef main
 static bool always_debug(struct io_conn *conn) { return true; }
-int main(void) { io_debug = always_debug; return real_main(); }
+int main(void) { io_debug_conn = always_debug; return real_main(); }
index f2ed1d4753dfb52acc4d1c7adf5944a3db42b0dd..298ce2346d7509156101e874fd3e41f9fd90eb1f 100644 (file)
@@ -5,4 +5,4 @@ int real_main(void);
 #include "run-06-idle.c"
 #undef main
 static bool always_debug(struct io_conn *conn) { return true; }
-int main(void) { io_debug = always_debug; return real_main(); }
+int main(void) { io_debug_conn = always_debug; return real_main(); }
index 7309594ed9f6e7892324aac5e29de384a6335397..602d7c2ffa1272866cf681c77f89489d71e61b92 100644 (file)
@@ -5,4 +5,4 @@ int real_main(void);
 #include "run-07-break.c"
 #undef main
 static bool always_debug(struct io_conn *conn) { return true; }
-int main(void) { io_debug = always_debug; return real_main(); }
+int main(void) { io_debug_conn = always_debug; return real_main(); }
index 589dc26709d40153e9976d3d79fcf9f129d95396..f916b8e14df06f9e3ab31ff0a2f9de1a4085bacf 100644 (file)
@@ -4,4 +4,4 @@ int real_main(void);
 #include "run-08-hangup-on-idle.c"
 #undef main
 static bool always_debug(struct io_conn *conn) { return true; }
-int main(void) { io_debug = always_debug; return real_main(); }
+int main(void) { io_debug_conn = always_debug; return real_main(); }
index 189a3eafe5f6285a9f01dc505862517bc97a2f20..8c602891be2994ab24f47d94d2ceabd602ccef0e 100644 (file)
@@ -4,4 +4,4 @@ int real_main(void);
 #include "run-08-read-after-hangup.c"
 #undef main
 static bool always_debug(struct io_conn *conn) { return true; }
-int main(void) { io_debug = always_debug; return real_main(); }
+int main(void) { io_debug_conn = always_debug; return real_main(); }
index 3b18596e4ff88998ff04e50b5cee4f449ee55557..675c7952d81d58262aa8a253f00744b2fa2a3dd4 100644 (file)
@@ -9,4 +9,4 @@ static bool debug_one(struct io_conn *conn)
 {
        return conn == buf[1].reader;
 }
-int main(void) { io_debug = debug_one; return real_main(); }
+int main(void) { io_debug_conn = debug_one; return real_main(); }
index d2c886d5ddbfe4d365bd4b15efde410ecef9ea90..55c4cf72ff336e3a386d84ac0423374262b7afec 100644 (file)
@@ -5,4 +5,4 @@ int real_main(void);
 #include "run-12-bidir.c"
 #undef main
 static bool always_debug(struct io_conn *conn) { return true; }
-int main(void) { io_debug = always_debug; return real_main(); }
+int main(void) { io_debug_conn = always_debug; return real_main(); }
index 1ef1db6d97203bdaf8d1fc0d4041093dc5148902..2969a13b965f2facaa34832709d2ab829899e80b 100644 (file)
@@ -5,4 +5,4 @@ int real_main(void);
 #include "run-13-all-idle.c"
 #undef main
 static bool always_debug(struct io_conn *conn) { return true; }
-int main(void) { io_debug = always_debug; return real_main(); }
+int main(void) { io_debug_conn = always_debug; return real_main(); }
index 8ada4c006d01f8e3a9316960b6f3880d1b31c657..d511486271251ee03e86de7ecd715b9537f63d84 100644 (file)
@@ -5,4 +5,4 @@ int real_main(void);
 #include "run-15-timeout.c"
 #undef main
 static bool always_debug(struct io_conn *conn) { return true; }
-int main(void) { io_debug = always_debug; return real_main(); }
+int main(void) { io_debug_conn = always_debug; return real_main(); }
index 40105d6ffc296f2c3b34bad1eddbcbf4b96d8b1e..5c44ce08463c6e7b078503ddf31617ee99db1ef6 100644 (file)
@@ -5,4 +5,4 @@ int real_main(void);
 #include "run-17-homemade-io.c"
 #undef main
 static bool always_debug(struct io_conn *conn) { return true; }
-int main(void) { io_debug = always_debug; return real_main(); }
+int main(void) { io_debug_conn = always_debug; return real_main(); }
index 07794fa98e125d66480af8e8be62d3f9a7b0e16c..00fbf2233c59c9132c3f1c74a40e630429a64bf5 100644 (file)
@@ -81,7 +81,6 @@ static struct io_plan io_read_packet(struct packet *pkt,
        plan.next_arg = arg;
        plan.pollflag = POLLIN;
 
-       io_plan_debug(&plan);
        return plan;
 }
 
index bfa661578837058bf62eb00dc5cacea7f8c605b0..863d1ae1e2c42fda62651fadb93a2e641df1c1df 100644 (file)
@@ -5,4 +5,4 @@ int real_main(void);
 #include "run-18-errno.c"
 #undef main
 static bool always_debug(struct io_conn *conn) { return true; }
-int main(void) { io_debug = always_debug; return real_main(); }
+int main(void) { io_debug_conn = always_debug; return real_main(); }