/* ========================================================================== * libevnet/src/bufio-drain.c - Network server library for libevent. * -------------------------------------------------------------------------- * Copyright (c) 2006 William Ahern * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to permit * persons to whom the Software is furnished to do so, subject to the * following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * USE OR OTHER DEALINGS IN THE SOFTWARE. * ========================================================================== */ #include /* size_t */ #include /* EAGAIN */ #include #include /* SLIST */ #include /* struct timeval */ #include "bufio.h" /* struct bufio_sink struct bufio_source */ #include "drain.h" #ifndef NULL #define NULL 0 #endif #define BUFIO_DRAIN_FRAME_PUSH(d, f) do { \ (f)->dp = &(d); \ SLIST_INSERT_HEAD(&(d)->stack, (f), sle); \ } while(0) #define BUFIO_DRAIN_FRAME_POP(d, f) do { \ if ((d) != 0) { \ assert((f) == SLIST_FIRST(&(d)->stack)); \ SLIST_REMOVE_HEAD(&(d)->stack, sle); \ } \ } while(0) #define BUFIO_DRAIN_FRAME_OKAY(f) ((f)->dp != 0) #define BUFIO_DRAIN_FRAME_KILL(f) (*(f)->dp = 0) #define BUFIO_DRAIN_FRAME_KILL_ALL(d) { \ struct bufio_drain_frame *f; \ \ while (SLIST_END(&d->stack) != (f = SLIST_FIRST(&(d)->stack))) { \ SLIST_REMOVE_HEAD(&(d)->stack, sle); \ \ BUFIO_DRAIN_FRAME_KILL(f); \ } \ } while(0) const struct bufio_drain_options bufio_drain_defaults; static void bufio_drain_try(struct bufio_drain *); static void bufio_drain_catch_source(struct bufio_source *src, enum bufio_errno ioe, void *arg) { bufio_drain_try(arg); return /* void */; } /* bufio_drain_catch_source() */ static void bufio_drain_catch_sink(struct bufio_sink *snk, enum bufio_errno ioe, void *arg) { bufio_drain_try(arg); return /* void */; } /* bufio_drain_catch_sink() */ static void bufio_drain_try(struct bufio_drain *d) { struct bufio_drain_frame f; size_t nbytes; enum bufio_errno ioe; BUFIO_DRAIN_FRAME_PUSH(d, &f); d->src->clearerr(d->src); d->snk->clearerr(d->snk); ioe = 0; do { nbytes = d->src->copyto(d->src, d->snk, d->opts.flags, &ioe); } while (nbytes > 0 && BUFIO_DRAIN_FRAME_OKAY(&f)); if (!BUFIO_DRAIN_FRAME_OKAY(&f)) return /* void */; BUFIO_DRAIN_FRAME_POP(d, &f); if (!BUFIO_WOULDBLOCK(ioe)) { if (d->cb.fn != 0) d->cb.fn(d, ioe, d->cb.arg); return /* void */; } if (ioe == d->src->lasterr(d->src)) { d->src->poll(d->src, &bufio_drain_catch_source, d, 0); } else { d->snk->poll(d->snk, &bufio_drain_catch_sink, d, 0); } return /* void */; } /* bufio_drain_try() */ struct bufio_drain *bufio_drain_init(struct bufio_drain *d, const struct bufio_drain_options *opts, struct bufio_sink *snk, struct bufio_source *src) { static const struct bufio_drain drain_initializer; *d = drain_initializer; d->opts = *((opts != 0)? opts : &bufio_drain_defaults); d->src = src; d->snk = snk; return d; } /* bufio_drain_init() */ void bufio_drain_destroy(struct bufio_drain *d) { BUFIO_DRAIN_FRAME_KILL_ALL(d); bufio_drain_stop(d); return /* void */; } /* bufio_drain_destroy() */ void bufio_drain_start(struct bufio_drain *d, void (*cb)(struct bufio_drain *, enum bufio_errno, void *)) { bufio_drain_try(d); return /* void */; } /* bufio_drain_start() */ void bufio_drain_stop(struct bufio_drain *d) { d->src->cancel(d->src, 0); d->snk->cancel(d->snk, 0); return /* void */; } /* bufio_drain_stop() */