-struct io_alloc io_alloc = {
- malloc, realloc, free
-};
-
-#ifdef DEBUG
-/* Set to skip the next plan. */
-bool io_plan_nodebug;
-/* The current connection to apply plan to. */
-struct io_conn *current;
-/* 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;
-
-struct io_plan io_debug(struct io_plan plan)
-{
- struct io_conn *ready = NULL;
-
- if (io_plan_nodebug) {
- io_plan_nodebug = false;
- return plan;
- }
-
- if (!current || !doing_debug_on(current)) {
- if (!io_debug_wakeup)
- return plan;
- }
-
- io_debug_wakeup = false;
- current->plan = plan;
- backend_plan_changed(current);
-
- /* Call back into the loop immediately. */
- io_loop_return = do_io_loop(&ready);
-
- if (ready) {
- set_current(ready);
- if (!ready->plan.next) {
- /* Call finish function immediately. */
- if (ready->finish) {
- errno = ready->plan.u1.s;
- ready->finish(ready, ready->finish_arg);
- ready->finish = NULL;
- }
- backend_del_conn(ready);
- } else {
- /* Calls back in itself, via io_debug_io(). */
- if (ready->plan.io(ready->fd.fd, &ready->plan) != 2)
- abort();
- }
- set_current(NULL);
- }
-
- /* Return a do-nothing plan, so backend_plan_changed in
- * io_ready doesn't do anything (it's already been called). */
- return io_idle_();
-}
-
-int io_debug_io(int ret)
-{
- /* Cache it for debugging; current changes. */
- struct io_conn *conn = current;
- int saved_errno = errno;
-
- if (!doing_debug_on(conn))
- return ret;
-
- /* These will all go linearly through the io_debug() path above. */
- switch (ret) {
- case -1:
- /* This will call io_debug above. */
- errno = saved_errno;
- io_close();
- break;
- case 0: /* Keep going with plan. */
- io_debug(conn->plan);
- break;
- case 1: /* Done: get next plan. */
- if (timeout_active(conn))
- backend_del_timeout(conn);
- /* In case they call io_duplex, clear our poll flags so
- * both sides don't seem to be both doing read or write
- * (See assert(!mask || pfd->events != mask) in poll.c) */
- conn->plan.pollflag = 0;
- conn->plan.next(conn, conn->plan.next_arg);
- break;
- default:
- abort();
- }
-
- /* Normally-invalid value, used for sanity check. */
- return 2;
-}
-
-static void debug_io_wake(struct io_conn *conn)
-{
- /* We want linear if we wake a debugged connection, too. */
- 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,
- void (*init)(int fd, void *arg),