Commit 9e02685a authored by Rusty Russell's avatar Rusty Russell

ccan/io: flatten debug callchain.

Don't call from the plan-construction function, call after it returns.
Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
parent d4af94ec
...@@ -55,7 +55,7 @@ static inline void set_current(struct io_conn *conn) ...@@ -55,7 +55,7 @@ static inline void set_current(struct io_conn *conn)
} }
static inline bool doing_debug(void) static inline bool doing_debug(void)
{ {
return io_debug != NULL; return io_debug_conn != NULL;
} }
#else #else
static inline void set_current(struct io_conn *conn) static inline void set_current(struct io_conn *conn)
......
...@@ -13,42 +13,56 @@ ...@@ -13,42 +13,56 @@
void *io_loop_return; void *io_loop_return;
#ifdef DEBUG #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; 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; 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) { if (io_plan_nodebug) {
io_plan_for_other = false; io_plan_nodebug = false;
return; return plan;
} }
if (!io_debug || !current) if (!io_debug_conn || !current)
return; return plan;
if (!io_debug(current) && !io_debug_wakeup) if (!io_debug_conn(current) && !io_debug_wakeup)
return; return plan;
io_debug_wakeup = false; io_debug_wakeup = false;
current->plan = *plan; current->plan = plan;
backend_plan_changed(current); backend_plan_changed(current);
/* Call back into the loop immediately. */ /* Call back into the loop immediately. */
io_loop_return = io_loop(); io_loop_return = io_loop();
return plan;
} }
static void debug_io_wake(struct io_conn *conn) static void debug_io_wake(struct io_conn *conn)
{ {
/* We want linear if we wake a debugged connection, too. */ /* 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; 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 #else
static void debug_io_wake(struct io_conn *conn) static void debug_io_wake(struct io_conn *conn)
{ {
} }
static void io_plan_debug_again(void)
{
}
#endif #endif
struct io_listener *io_new_listener_(int fd, struct io_listener *io_new_listener_(int fd,
...@@ -82,6 +96,8 @@ struct io_conn *io_new_conn_(int fd, struct io_plan plan) ...@@ -82,6 +96,8 @@ struct io_conn *io_new_conn_(int fd, struct io_plan plan)
{ {
struct io_conn *conn = malloc(sizeof(*conn)); struct io_conn *conn = malloc(sizeof(*conn));
io_plan_debug_again();
if (!conn) if (!conn)
return NULL; return NULL;
...@@ -111,6 +127,8 @@ struct io_conn *io_duplex_(struct io_conn *old, struct io_plan plan) ...@@ -111,6 +127,8 @@ struct io_conn *io_duplex_(struct io_conn *old, struct io_plan plan)
{ {
struct io_conn *conn; struct io_conn *conn;
io_plan_debug_again();
assert(!old->duplex); assert(!old->duplex);
conn = malloc(sizeof(*conn)); conn = malloc(sizeof(*conn));
...@@ -177,7 +195,6 @@ struct io_plan io_write_(const void *data, size_t len, ...@@ -177,7 +195,6 @@ struct io_plan io_write_(const void *data, size_t len,
plan.next_arg = arg; plan.next_arg = arg;
plan.pollflag = POLLOUT; plan.pollflag = POLLOUT;
io_plan_debug(&plan);
return plan; return plan;
} }
...@@ -207,7 +224,6 @@ struct io_plan io_read_(void *data, size_t len, ...@@ -207,7 +224,6 @@ struct io_plan io_read_(void *data, size_t len,
plan.next_arg = arg; plan.next_arg = arg;
plan.pollflag = POLLIN; plan.pollflag = POLLIN;
io_plan_debug(&plan);
return plan; return plan;
} }
...@@ -236,7 +252,6 @@ struct io_plan io_read_partial_(void *data, size_t *len, ...@@ -236,7 +252,6 @@ struct io_plan io_read_partial_(void *data, size_t *len,
plan.next_arg = arg; plan.next_arg = arg;
plan.pollflag = POLLIN; plan.pollflag = POLLIN;
io_plan_debug(&plan);
return plan; return plan;
} }
...@@ -265,26 +280,26 @@ struct io_plan io_write_partial_(const void *data, size_t *len, ...@@ -265,26 +280,26 @@ struct io_plan io_write_partial_(const void *data, size_t *len,
plan.next_arg = arg; plan.next_arg = arg;
plan.pollflag = POLLOUT; plan.pollflag = POLLOUT;
io_plan_debug(&plan);
return plan; return plan;
} }
struct io_plan io_idle(void) struct io_plan io_idle_(void)
{ {
struct io_plan plan; struct io_plan plan;
plan.pollflag = 0; plan.pollflag = 0;
plan.io = NULL; plan.io = NULL;
/* Never called (overridden by io_wake), but NULL means closing */ /* 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; return plan;
} }
void io_wake_(struct io_conn *conn, struct io_plan 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. */ /* It might be closing, but we haven't called its finish() yet. */
if (!conn->plan.next) if (!conn->plan.next)
return; return;
...@@ -318,7 +333,7 @@ void io_ready(struct io_conn *conn) ...@@ -318,7 +333,7 @@ void io_ready(struct io_conn *conn)
} }
/* Close the connection, we're done. */ /* Close the connection, we're done. */
struct io_plan io_close(void) struct io_plan io_close_(void)
{ {
struct io_plan plan; struct io_plan plan;
...@@ -327,7 +342,6 @@ struct io_plan io_close(void) ...@@ -327,7 +342,6 @@ struct io_plan io_close(void)
plan.next = NULL; plan.next = NULL;
plan.u.close.saved_errno = errno; plan.u.close.saved_errno = errno;
io_plan_debug(&plan);
return plan; return plan;
} }
...@@ -339,6 +353,8 @@ struct io_plan io_close_cb(struct io_conn *conn, void *arg) ...@@ -339,6 +353,8 @@ struct io_plan io_close_cb(struct io_conn *conn, void *arg)
/* Exit the loop, returning this (non-NULL) arg. */ /* Exit the loop, returning this (non-NULL) arg. */
struct io_plan io_break_(void *ret, struct io_plan plan) struct io_plan io_break_(void *ret, struct io_plan plan)
{ {
io_plan_debug_again();
assert(ret); assert(ret);
io_loop_return = ret; io_loop_return = ret;
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
* Returns NULL on error (and sets errno). * Returns NULL on error (and sets errno).
*/ */
#define io_new_conn(fd, plan) \ #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); struct io_conn *io_new_conn_(int fd, struct io_plan plan);
/** /**
...@@ -83,10 +83,10 @@ void io_close_listener(struct io_listener *listener); ...@@ -83,10 +83,10 @@ void io_close_listener(struct io_listener *listener);
* Note that the I/O may actually be done immediately. * Note that the I/O may actually be done immediately.
*/ */
#define io_write(data, len, cb, arg) \ #define io_write(data, len, cb, arg) \
io_write_((data), (len), \ io_debug(io_write_((data), (len), \
typesafe_cb_preargs(struct io_plan, void *, \ typesafe_cb_preargs(struct io_plan, void *, \
(cb), (arg), struct io_conn *), \ (cb), (arg), struct io_conn *), \
(arg)) (arg)))
struct io_plan io_write_(const void *data, size_t len, struct io_plan io_write_(const void *data, size_t len,
struct io_plan (*cb)(struct io_conn *, void *), struct io_plan (*cb)(struct io_conn *, void *),
void *arg); void *arg);
...@@ -105,10 +105,10 @@ struct io_plan io_write_(const void *data, size_t len, ...@@ -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. * Note that the I/O may actually be done immediately.
*/ */
#define io_read(data, len, cb, arg) \ #define io_read(data, len, cb, arg) \
io_read_((data), (len), \ io_debug(io_read_((data), (len), \
typesafe_cb_preargs(struct io_plan, void *, \ typesafe_cb_preargs(struct io_plan, void *, \
(cb), (arg), struct io_conn *), \ (cb), (arg), struct io_conn *), \
(arg)) (arg)))
struct io_plan io_read_(void *data, size_t len, struct io_plan io_read_(void *data, size_t len,
struct io_plan (*cb)(struct io_conn *, void *), struct io_plan (*cb)(struct io_conn *, void *),
void *arg); void *arg);
...@@ -128,10 +128,11 @@ struct io_plan io_read_(void *data, size_t len, ...@@ -128,10 +128,11 @@ struct io_plan io_read_(void *data, size_t len,
* Note that the I/O may actually be done immediately. * Note that the I/O may actually be done immediately.
*/ */
#define io_read_partial(data, len, cb, arg) \ #define io_read_partial(data, len, cb, arg) \
io_read_partial_((data), (len), \ io_debug(io_read_partial_((data), (len), \
typesafe_cb_preargs(struct io_plan, void *, \ typesafe_cb_preargs(struct io_plan, void *, \
(cb), (arg), struct io_conn *), \ (cb), (arg), \
(arg)) struct io_conn *), \
(arg)))
struct io_plan io_read_partial_(void *data, size_t *len, struct io_plan io_read_partial_(void *data, size_t *len,
struct io_plan (*cb)(struct io_conn *, void *), struct io_plan (*cb)(struct io_conn *, void *),
void *arg); void *arg);
...@@ -150,10 +151,11 @@ struct io_plan io_read_partial_(void *data, size_t *len, ...@@ -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. * Note that the I/O may actually be done immediately.
*/ */
#define io_write_partial(data, len, cb, arg) \ #define io_write_partial(data, len, cb, arg) \
io_write_partial_((data), (len), \ io_debug(io_write_partial_((data), (len), \
typesafe_cb_preargs(struct io_plan, void *, \ typesafe_cb_preargs(struct io_plan, void *, \
(cb), (arg), struct io_conn *), \ (cb), (arg), \
(arg)) struct io_conn *), \
(arg)))
struct io_plan io_write_partial_(const void *data, size_t *len, struct io_plan io_write_partial_(const void *data, size_t *len,
struct io_plan (*cb)(struct io_conn *, void*), struct io_plan (*cb)(struct io_conn *, void*),
void *arg); void *arg);
...@@ -164,7 +166,8 @@ struct io_plan io_write_partial_(const void *data, size_t *len, ...@@ -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 * This indicates the connection is idle: io_wake() will be called later do
* give the connection a new plan. * 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. * 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, ...@@ -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. * You must io_close() both of them to close the fd.
*/ */
#define io_duplex(conn, plan) \ #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); 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); ...@@ -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(). * 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); 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); ...@@ -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. * 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); struct io_plan io_break_(void *ret, struct io_plan plan);
/* FIXME: io_recvfrom/io_sendto */ /* FIXME: io_recvfrom/io_sendto */
...@@ -236,7 +239,8 @@ struct io_plan io_break_(void *ret, struct io_plan plan); ...@@ -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. * 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. * io_close_cb - helper callback to close a connection.
......
...@@ -63,38 +63,43 @@ struct io_plan { ...@@ -63,38 +63,43 @@ struct io_plan {
#ifdef DEBUG #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 * 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 * debugging candidate. If so, the callchain for I/O operations on this
* connection will be linear, for easier use of a debugger. * 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 * This determines if we are debugging the current connection: if so,
* connection. We (ab)use this pattern for debugging: as soon as such a * it immediately applies the plan and calls back into io_loop() to
* plan is created, it is called, to create a linear call chain. * 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.
*/ */
#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 * Most routines which take a plan are about to apply it to the current
* debugged, then it will be immediately serviced with this plan. * 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); #define io_plan_no_debug() ((io_plan_nodebug = true))
extern bool io_plan_for_other;
extern bool io_plan_nodebug;
#else #else
#define io_plan_other() (void)0 static inline struct io_plan io_debug(struct io_plan plan)
static inline void io_plan_debug(struct io_plan *plan) { } {
return plan;
}
#define io_plan_no_debug() (void)0
#endif #endif
#endif /* CCAN_IO_PLAN_H */ #endif /* CCAN_IO_PLAN_H */
...@@ -5,4 +5,4 @@ int real_main(void); ...@@ -5,4 +5,4 @@ int real_main(void);
#include "run-01-start-finish.c" #include "run-01-start-finish.c"
#undef main #undef main
static bool always_debug(struct io_conn *conn) { return true; } 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(); }
...@@ -5,4 +5,4 @@ int real_main(void); ...@@ -5,4 +5,4 @@ int real_main(void);
#include "run-02-read.c" #include "run-02-read.c"
#undef main #undef main
static bool always_debug(struct io_conn *conn) { return true; } 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(); }
...@@ -5,4 +5,4 @@ int real_main(void); ...@@ -5,4 +5,4 @@ int real_main(void);
#include "run-03-readpartial.c" #include "run-03-readpartial.c"
#undef main #undef main
static bool always_debug(struct io_conn *conn) { return true; } 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(); }
...@@ -5,4 +5,4 @@ int real_main(void); ...@@ -5,4 +5,4 @@ int real_main(void);
#include "run-04-writepartial.c" #include "run-04-writepartial.c"
#undef main #undef main
static bool always_debug(struct io_conn *conn) { return true; } 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(); }
...@@ -5,4 +5,4 @@ int real_main(void); ...@@ -5,4 +5,4 @@ int real_main(void);
#include "run-05-write.c" #include "run-05-write.c"
#undef main #undef main
static bool always_debug(struct io_conn *conn) { return true; } 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(); }
...@@ -5,4 +5,4 @@ int real_main(void); ...@@ -5,4 +5,4 @@ int real_main(void);
#include "run-06-idle.c" #include "run-06-idle.c"
#undef main #undef main
static bool always_debug(struct io_conn *conn) { return true; } 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(); }
...@@ -5,4 +5,4 @@ int real_main(void); ...@@ -5,4 +5,4 @@ int real_main(void);
#include "run-07-break.c" #include "run-07-break.c"
#undef main #undef main
static bool always_debug(struct io_conn *conn) { return true; } 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(); }
...@@ -4,4 +4,4 @@ int real_main(void); ...@@ -4,4 +4,4 @@ int real_main(void);
#include "run-08-hangup-on-idle.c" #include "run-08-hangup-on-idle.c"
#undef main #undef main
static bool always_debug(struct io_conn *conn) { return true; } 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(); }
...@@ -4,4 +4,4 @@ int real_main(void); ...@@ -4,4 +4,4 @@ int real_main(void);
#include "run-08-read-after-hangup.c" #include "run-08-read-after-hangup.c"
#undef main #undef main
static bool always_debug(struct io_conn *conn) { return true; } 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(); }
...@@ -9,4 +9,4 @@ static bool debug_one(struct io_conn *conn) ...@@ -9,4 +9,4 @@ static bool debug_one(struct io_conn *conn)
{ {
return conn == buf[1].reader; 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(); }
...@@ -5,4 +5,4 @@ int real_main(void); ...@@ -5,4 +5,4 @@ int real_main(void);
#include "run-12-bidir.c" #include "run-12-bidir.c"
#undef main #undef main
static bool always_debug(struct io_conn *conn) { return true; } 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(); }
...@@ -5,4 +5,4 @@ int real_main(void); ...@@ -5,4 +5,4 @@ int real_main(void);
#include "run-13-all-idle.c" #include "run-13-all-idle.c"
#undef main #undef main
static bool always_debug(struct io_conn *conn) { return true; } 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(); }
...@@ -5,4 +5,4 @@ int real_main(void); ...@@ -5,4 +5,4 @@ int real_main(void);
#include "run-15-timeout.c" #include "run-15-timeout.c"
#undef main #undef main
static bool always_debug(struct io_conn *conn) { return true; } 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(); }
...@@ -5,4 +5,4 @@ int real_main(void); ...@@ -5,4 +5,4 @@ int real_main(void);
#include "run-17-homemade-io.c" #include "run-17-homemade-io.c"
#undef main #undef main
static bool always_debug(struct io_conn *conn) { return true; } 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(); }
...@@ -81,7 +81,6 @@ static struct io_plan io_read_packet(struct packet *pkt, ...@@ -81,7 +81,6 @@ static struct io_plan io_read_packet(struct packet *pkt,
plan.next_arg = arg; plan.next_arg = arg;
plan.pollflag = POLLIN; plan.pollflag = POLLIN;
io_plan_debug(&plan);
return plan; return plan;
} }
......
...@@ -5,4 +5,4 @@ int real_main(void); ...@@ -5,4 +5,4 @@ int real_main(void);
#include "run-18-errno.c" #include "run-18-errno.c"
#undef main #undef main
static bool always_debug(struct io_conn *conn) { return true; } 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(); }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment