/* ==========================================================================
* 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 <stddef.h> /* size_t */
#include <errno.h> /* EAGAIN */
#include <assert.h>
#include <sys/queue.h> /* SLIST */
#include <sys/time.h> /* 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() */
syntax highlighted by Code2HTML, v. 0.9.1