Refactor new elements of bufferevent into bufferevent_private structure

This way we don't expose more of a bufferevent than we need to.  One
motivation is to make it easier to automatically get deferred callbacks
with a bufferevent without exposing the deferred_cb structure.

svn:r1169
This commit is contained in:
Nick Mathewson 2009-04-13 03:08:11 +00:00
parent 6567ecd4c5
commit 1becc4c4e6
6 changed files with 87 additions and 60 deletions

View File

@ -32,6 +32,22 @@ extern "C" {
#include "event-config.h" #include "event-config.h"
#include "evutil.h" #include "evutil.h"
#include "defer-internal.h"
struct bufferevent_private {
struct bufferevent bev;
/** Evbuffer callback to enforce watermarks on input. */
struct evbuffer_cb_entry *read_watermarks_cb;
/** If set, read is suspended until evbuffer some. */
unsigned read_suspended : 1;
enum bufferevent_options options;
int refcnt;
void *lock;
};
/** /**
Implementation table for a bufferevent: holds function pointers and other Implementation table for a bufferevent: holds function pointers and other
@ -81,7 +97,7 @@ extern const struct bufferevent_ops bufferevent_ops_filter;
extern const struct bufferevent_ops bufferevent_ops_pair; extern const struct bufferevent_ops bufferevent_ops_pair;
/** Initialize the shared parts of a bufferevent. */ /** Initialize the shared parts of a bufferevent. */
int bufferevent_init_common(struct bufferevent *, struct event_base *, const struct bufferevent_ops *, enum bufferevent_options options); int bufferevent_init_common(struct bufferevent_private *, struct event_base *, const struct bufferevent_ops *, enum bufferevent_options options);
/** For internal use: temporarily stop all reads on bufev, because its /** For internal use: temporarily stop all reads on bufev, because its
* read buffer is too full. */ * read buffer is too full. */

View File

@ -63,17 +63,21 @@
void void
bufferevent_wm_suspend_read(struct bufferevent *bufev) bufferevent_wm_suspend_read(struct bufferevent *bufev)
{ {
if (!bufev->read_suspended) { struct bufferevent_private *bufev_private =
EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
if (!bufev_private->read_suspended) {
bufev->be_ops->disable(bufev, EV_READ); bufev->be_ops->disable(bufev, EV_READ);
bufev->read_suspended = 1; bufev_private->read_suspended = 1;
} }
} }
void void
bufferevent_wm_unsuspend_read(struct bufferevent *bufev) bufferevent_wm_unsuspend_read(struct bufferevent *bufev)
{ {
if (bufev->read_suspended) { struct bufferevent_private *bufev_private =
bufev->read_suspended = 0; EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
if (bufev_private->read_suspended) {
bufev_private->read_suspended = 0;
if (bufev->enabled & EV_READ) if (bufev->enabled & EV_READ)
bufev->be_ops->enable(bufev, EV_READ); bufev->be_ops->enable(bufev, EV_READ);
} }
@ -103,10 +107,13 @@ bufferevent_inbuf_wm_cb(struct evbuffer *buf,
} }
int int
bufferevent_init_common(struct bufferevent *bufev, struct event_base *base, bufferevent_init_common(struct bufferevent_private *bufev_private,
struct event_base *base,
const struct bufferevent_ops *ops, const struct bufferevent_ops *ops,
enum bufferevent_options options) enum bufferevent_options options)
{ {
struct bufferevent *bufev = &bufev_private->bev;
if ((bufev->input = evbuffer_new()) == NULL) if ((bufev->input = evbuffer_new()) == NULL)
return -1; return -1;
@ -130,7 +137,7 @@ bufferevent_init_common(struct bufferevent *bufev, struct event_base *base,
*/ */
bufev->enabled = EV_WRITE; bufev->enabled = EV_WRITE;
bufev->options = options; bufev_private->options = options;
return 0; return 0;
} }
@ -196,8 +203,10 @@ bufferevent_read_buffer(struct bufferevent *bufev, struct evbuffer *buf)
int int
bufferevent_enable(struct bufferevent *bufev, short event) bufferevent_enable(struct bufferevent *bufev, short event)
{ {
struct bufferevent_private *bufev_private =
EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
short impl_events = event; short impl_events = event;
if (bufev->read_suspended) if (bufev_private->read_suspended)
impl_events &= ~EV_READ; impl_events &= ~EV_READ;
bufev->enabled |= event; bufev->enabled |= event;
@ -272,6 +281,8 @@ void
bufferevent_setwatermark(struct bufferevent *bufev, short events, bufferevent_setwatermark(struct bufferevent *bufev, short events,
size_t lowmark, size_t highmark) size_t lowmark, size_t highmark)
{ {
struct bufferevent_private *bufev_private =
EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
if (events & EV_WRITE) { if (events & EV_WRITE) {
bufev->wm_write.low = lowmark; bufev->wm_write.low = lowmark;
@ -287,14 +298,14 @@ bufferevent_setwatermark(struct bufferevent *bufev, short events,
enable the callback if needed, and see if we should enable the callback if needed, and see if we should
suspend/bufferevent_wm_unsuspend. */ suspend/bufferevent_wm_unsuspend. */
if (bufev->read_watermarks_cb == NULL) { if (bufev_private->read_watermarks_cb == NULL) {
bufev->read_watermarks_cb = bufev_private->read_watermarks_cb =
evbuffer_add_cb(bufev->input, evbuffer_add_cb(bufev->input,
bufferevent_inbuf_wm_cb, bufferevent_inbuf_wm_cb,
bufev); bufev);
} }
evbuffer_cb_set_flags(bufev->input, evbuffer_cb_set_flags(bufev->input,
bufev->read_watermarks_cb, bufev_private->read_watermarks_cb,
EVBUFFER_CB_ENABLED); EVBUFFER_CB_ENABLED);
if (EVBUFFER_LENGTH(bufev->input) > highmark) if (EVBUFFER_LENGTH(bufev->input) > highmark)
@ -303,9 +314,9 @@ bufferevent_setwatermark(struct bufferevent *bufev, short events,
bufferevent_wm_unsuspend_read(bufev); bufferevent_wm_unsuspend_read(bufev);
} else { } else {
/* There is now no high-water mark for read. */ /* There is now no high-water mark for read. */
if (bufev->read_watermarks_cb) if (bufev_private->read_watermarks_cb)
evbuffer_cb_set_flags(bufev->input, evbuffer_cb_set_flags(bufev->input,
bufev->read_watermarks_cb, bufev_private->read_watermarks_cb,
EVBUFFER_CB_DISABLED); EVBUFFER_CB_DISABLED);
bufferevent_wm_unsuspend_read(bufev); bufferevent_wm_unsuspend_read(bufev);
} }

View File

@ -76,7 +76,7 @@ static void bufferevent_filtered_outbuf_cb(struct evbuffer *buf,
const struct evbuffer_cb_info *info, void *arg); const struct evbuffer_cb_info *info, void *arg);
struct bufferevent_filtered { struct bufferevent_filtered {
struct bufferevent bev; struct bufferevent_private bev;
/** The bufferevent that we read/write filterd data from/to. */ /** The bufferevent that we read/write filterd data from/to. */
struct bufferevent *underlying; struct bufferevent *underlying;
@ -116,12 +116,12 @@ upcast(struct bufferevent *bev)
if (bev->be_ops != &bufferevent_ops_filter) if (bev->be_ops != &bufferevent_ops_filter)
return NULL; return NULL;
bev_f = (void*)( ((char*)bev) - bev_f = (void*)( ((char*)bev) -
evutil_offsetof(struct bufferevent_filtered, bev) ); evutil_offsetof(struct bufferevent_filtered, bev.bev));
assert(bev_f->bev.be_ops == &bufferevent_ops_filter); assert(bev_f->bev.bev.be_ops == &bufferevent_ops_filter);
return bev_f; return bev_f;
} }
#define downcast(bev_f) (&(bev_f)->bev) #define downcast(bev_f) (&(bev_f)->bev.bev)
/** Return 1 iff bevf's underlying bufferevent's output buffer is at or /** Return 1 iff bevf's underlying bufferevent's output buffer is at or
* over its high watermark such that we should not write to it in a given * over its high watermark such that we should not write to it in a given
@ -195,10 +195,10 @@ bufferevent_filter_new(struct bufferevent *underlying,
bufferevent_setcb(bufev_f->underlying, bufferevent_setcb(bufev_f->underlying,
be_filter_readcb, be_filter_writecb, be_filter_errorcb, bufev_f); be_filter_readcb, be_filter_writecb, be_filter_errorcb, bufev_f);
bufev_f->outbuf_cb = evbuffer_add_cb(bufev_f->bev.output, bufev_f->outbuf_cb = evbuffer_add_cb(downcast(bufev_f)->output,
bufferevent_filtered_outbuf_cb, bufev_f); bufferevent_filtered_outbuf_cb, bufev_f);
return &bufev_f->bev; return downcast(bufev_f);
} }
static void static void
@ -209,7 +209,7 @@ be_filter_destruct(struct bufferevent *bev)
if (bevf->free_context) if (bevf->free_context)
bevf->free_context(bevf->context); bevf->free_context(bevf->context);
if (bev->options & BEV_OPT_CLOSE_ON_FREE) if (bevf->bev.options & BEV_OPT_CLOSE_ON_FREE)
bufferevent_free(bevf->underlying); bufferevent_free(bevf->underlying);
} }
@ -247,28 +247,29 @@ be_filter_process_input(struct bufferevent_filtered *bevf,
int *processed_out) int *processed_out)
{ {
enum bufferevent_filter_result res; enum bufferevent_filter_result res;
struct bufferevent *bev = downcast(bevf);
if (state == BEV_NORMAL) { if (state == BEV_NORMAL) {
/* If we're in 'normal' mode, don't urge data on the filter /* If we're in 'normal' mode, don't urge data on the filter
* unless we're reading data and under our high-water mark.*/ * unless we're reading data and under our high-water mark.*/
if (!(bevf->bev.enabled & EV_READ) || if (!(bev->enabled & EV_READ) ||
be_readbuf_full(bevf, state)) be_readbuf_full(bevf, state))
return BEV_OK; return BEV_OK;
} }
do { do {
ssize_t limit = -1; ssize_t limit = -1;
if (state == BEV_NORMAL && bevf->bev.wm_read.high) if (state == BEV_NORMAL && bev->wm_read.high)
limit = bevf->bev.wm_read.high - limit = bev->wm_read.high -
EVBUFFER_LENGTH(bevf->bev.input); EVBUFFER_LENGTH(bev->input);
res = bevf->process_in(bevf->underlying->input, res = bevf->process_in(bevf->underlying->input,
bevf->bev.input, limit, state, bevf->context); bev->input, limit, state, bevf->context);
if (res == BEV_OK) if (res == BEV_OK)
*processed_out = 1; *processed_out = 1;
} while (res == BEV_OK && } while (res == BEV_OK &&
(bevf->bev.enabled & EV_READ) && (bev->enabled & EV_READ) &&
EVBUFFER_LENGTH(bevf->underlying->input) && EVBUFFER_LENGTH(bevf->underlying->input) &&
!be_readbuf_full(bevf, state)); !be_readbuf_full(bevf, state));
@ -312,7 +313,7 @@ be_filter_process_output(struct bufferevent_filtered *bevf,
limit = bevf->underlying->wm_write.high - limit = bevf->underlying->wm_write.high -
EVBUFFER_LENGTH(bevf->underlying->output); EVBUFFER_LENGTH(bevf->underlying->output);
res = bevf->process_out(bevf->bev.output, res = bevf->process_out(downcast(bevf)->output,
bevf->underlying->output, bevf->underlying->output,
limit, limit,
state, state,
@ -405,10 +406,11 @@ static void
be_filter_errorcb(struct bufferevent *underlying, short what, void *_me) be_filter_errorcb(struct bufferevent *underlying, short what, void *_me)
{ {
struct bufferevent_filtered *bevf = _me; struct bufferevent_filtered *bevf = _me;
struct bufferevent *bev = downcast(bevf);
/* All we can really to is tell our own errorcb. */ /* All we can really to is tell our own errorcb. */
if (bevf->bev.errorcb) if (bev->errorcb)
bevf->bev.errorcb(&bevf->bev, what, bevf->bev.cbarg); bev->errorcb(bev, what, bev->cbarg);
} }
static int static int

View File

@ -42,7 +42,7 @@
#include "util-internal.h" #include "util-internal.h"
struct bufferevent_pair { struct bufferevent_pair {
struct bufferevent bev; struct bufferevent_private bev;
struct bufferevent_pair *partner; struct bufferevent_pair *partner;
struct deferred_cb deferred_write_cb; struct deferred_cb deferred_write_cb;
struct deferred_cb deferred_read_cb; struct deferred_cb deferred_read_cb;
@ -57,12 +57,12 @@ upcast(struct bufferevent *bev)
struct bufferevent_pair *bev_p; struct bufferevent_pair *bev_p;
if (bev->be_ops != &bufferevent_ops_pair) if (bev->be_ops != &bufferevent_ops_pair)
return NULL; return NULL;
bev_p = EVUTIL_UPCAST(bev, struct bufferevent_pair, bev); bev_p = EVUTIL_UPCAST(bev, struct bufferevent_pair, bev.bev);
assert(bev_p->bev.be_ops == &bufferevent_ops_pair); assert(bev_p->bev.bev.be_ops == &bufferevent_ops_pair);
return bev_p; return bev_p;
} }
#define downcast(bev_pair) (&(bev_pair)->bev) #define downcast(bev_pair) (&(bev_pair)->bev.bev)
/* XXX Handle close */ /* XXX Handle close */
@ -100,7 +100,7 @@ bufferevent_pair_elt_new(struct event_base *base,
} }
/* XXX set read timeout event */ /* XXX set read timeout event */
/* XXX set write timeout event */ /* XXX set write timeout event */
if (!evbuffer_add_cb(bufev->bev.output, be_pair_outbuf_cb, bufev)) { if (!evbuffer_add_cb(bufev->bev.bev.output, be_pair_outbuf_cb, bufev)) {
bufferevent_free(downcast(bufev)); bufferevent_free(downcast(bufev));
return NULL; return NULL;
} }
@ -128,10 +128,10 @@ bufferevent_pair_new(struct event_base *base, enum bufferevent_options options,
bufev1->partner = bufev2; bufev1->partner = bufev2;
bufev2->partner = bufev1; bufev2->partner = bufev1;
evbuffer_freeze(bufev1->bev.input, 0); evbuffer_freeze(downcast(bufev1)->input, 0);
evbuffer_freeze(bufev1->bev.output, 1); evbuffer_freeze(downcast(bufev1)->output, 1);
evbuffer_freeze(bufev2->bev.input, 0); evbuffer_freeze(downcast(bufev2)->input, 0);
evbuffer_freeze(bufev2->bev.output, 1); evbuffer_freeze(downcast(bufev2)->output, 1);
pair[0] = downcast(bufev1); pair[0] = downcast(bufev1);
pair[1] = downcast(bufev2); pair[1] = downcast(bufev2);
@ -180,11 +180,13 @@ done:
} }
static inline int static inline int
be_pair_wants_to_talk(struct bufferevent *src, struct bufferevent *dst) be_pair_wants_to_talk(struct bufferevent_pair *src,
struct bufferevent_pair *dst)
{ {
return (src->enabled & EV_WRITE) && return (downcast(src)->enabled & EV_WRITE) &&
(dst->enabled & EV_READ) && !dst->read_suspended && (downcast(dst)->enabled & EV_READ) &&
evbuffer_get_length(src->output); !dst->bev.read_suspended &&
evbuffer_get_length(downcast(src)->output);
} }
static void static void
@ -197,8 +199,7 @@ be_pair_outbuf_cb(struct evbuffer *outbuf,
if (info->n_added > info->n_deleted && partner) { if (info->n_added > info->n_deleted && partner) {
/* We got more data. If the other side's reading, then /* We got more data. If the other side's reading, then
hand it over. */ hand it over. */
if (be_pair_wants_to_talk(downcast(bev_pair), if (be_pair_wants_to_talk(bev_pair, partner)) {
downcast(partner))) {
be_pair_transfer(downcast(bev_pair), downcast(partner), 0); be_pair_transfer(downcast(bev_pair), downcast(partner), 0);
} }
} }
@ -212,12 +213,12 @@ be_pair_enable(struct bufferevent *bufev, short events)
/* We're starting to read! Does the other side have anything to write?*/ /* We're starting to read! Does the other side have anything to write?*/
if ((events & EV_READ) && partner && if ((events & EV_READ) && partner &&
be_pair_wants_to_talk(downcast(partner), bufev)) { be_pair_wants_to_talk(partner, bev_p)) {
be_pair_transfer(downcast(partner), bufev, 0); be_pair_transfer(downcast(partner), bufev, 0);
} }
/* We're starting to write! Does the other side want to read? */ /* We're starting to write! Does the other side want to read? */
if ((events & EV_WRITE) && partner && if ((events & EV_WRITE) && partner &&
be_pair_wants_to_talk(bufev, downcast(partner))) { be_pair_wants_to_talk(bev_p, partner)) {
be_pair_transfer(bufev, downcast(partner), 0); be_pair_transfer(bufev, downcast(partner), 0);
} }
return 0; return 0;

View File

@ -225,16 +225,18 @@ struct bufferevent *
bufferevent_socket_new(struct event_base *base, evutil_socket_t fd, bufferevent_socket_new(struct event_base *base, evutil_socket_t fd,
enum bufferevent_options options) enum bufferevent_options options)
{ {
struct bufferevent_private *bufev_p;
struct bufferevent *bufev; struct bufferevent *bufev;
if ((bufev = mm_calloc(1, sizeof(struct bufferevent))) == NULL) if ((bufev_p = mm_calloc(1, sizeof(struct bufferevent_private)))== NULL)
return NULL; return NULL;
if (bufferevent_init_common(bufev, base, &bufferevent_ops_socket, if (bufferevent_init_common(bufev_p, base, &bufferevent_ops_socket,
options) < 0) { options) < 0) {
mm_free(bufev); mm_free(bufev_p);
return NULL; return NULL;
} }
bufev = &bufev_p->bev;
event_assign(&bufev->ev_read, bufev->ev_base, fd, event_assign(&bufev->ev_read, bufev->ev_base, fd,
EV_READ|EV_PERSIST, bufferevent_readcb, bufev); EV_READ|EV_PERSIST, bufferevent_readcb, bufev);
@ -306,6 +308,8 @@ be_socket_disable(struct bufferevent *bufev, short event)
static void static void
be_socket_destruct(struct bufferevent *bufev) be_socket_destruct(struct bufferevent *bufev)
{ {
struct bufferevent_private *bufev_p =
EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
evutil_socket_t fd; evutil_socket_t fd;
assert(bufev->be_ops == &bufferevent_ops_socket); assert(bufev->be_ops == &bufferevent_ops_socket);
@ -314,7 +318,7 @@ be_socket_destruct(struct bufferevent *bufev)
event_del(&bufev->ev_read); event_del(&bufev->ev_read);
event_del(&bufev->ev_write); event_del(&bufev->ev_write);
if (bufev->options & BEV_OPT_CLOSE_ON_FREE) if (bufev_p->options & BEV_OPT_CLOSE_ON_FREE)
EVUTIL_CLOSESOCKET(fd); EVUTIL_CLOSESOCKET(fd);
} }

View File

@ -105,16 +105,9 @@ struct bufferevent {
struct timeval timeout_read; struct timeval timeout_read;
struct timeval timeout_write; struct timeval timeout_write;
/** Evbuffer callback to enforce watermarks on input. */
struct evbuffer_cb_entry *read_watermarks_cb;
/** Events that are currently enabled: currently EV_READ and EV_WRITE /** Events that are currently enabled: currently EV_READ and EV_WRITE
are supported. */ are supported. */
short enabled; short enabled;
/** If set, read is suspended until evbuffer some. */
unsigned read_suspended : 1; /* */
enum bufferevent_options options;
}; };
#ifdef __cplusplus #ifdef __cplusplus