summaryrefslogtreecommitdiff
path: root/bufferevent_filter.c
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2009-07-17 17:46:17 +0000
committerNick Mathewson <nickm@torproject.org>2009-07-17 17:46:17 +0000
commita62283a9c3a46c4ba0d72eb3bc18a3db7f9648e2 (patch)
tree2634a85482534f62112cf307c68acfdbf093e7ac /bufferevent_filter.c
parente83a32dfe1c10c90c27ccf1f4f93a59820517108 (diff)
downloadlibevent-a62283a9c3a46c4ba0d72eb3bc18a3db7f9648e2.tar.gz
Always hold a reference to a bufferevent when calling its callbacks.
Rationale: we hold a lock on the bufferevent when its callbacks are executing, so we need to release the lock afterwards. But the callback might free the bufferevent, so unless we're holding a reference on the bufferevent, the lock might not be there for us to release. svn:r1347
Diffstat (limited to 'bufferevent_filter.c')
-rw-r--r--bufferevent_filter.c20
1 files changed, 20 insertions, 0 deletions
diff --git a/bufferevent_filter.c b/bufferevent_filter.c
index d350f081..a77a9524 100644
--- a/bufferevent_filter.c
+++ b/bufferevent_filter.c
@@ -286,6 +286,7 @@ be_filter_process_output(struct bufferevent_filtered *bevf,
enum bufferevent_flush_mode state,
int *processed_out)
{
+ /* Requires references and lock: might call writecb */
enum bufferevent_filter_result res = BEV_OK;
struct bufferevent *bufev = downcast(bevf);
int again = 0;
@@ -365,12 +366,15 @@ bufferevent_filtered_outbuf_cb(struct evbuffer *buf,
const struct evbuffer_cb_info *cbinfo, void *arg)
{
struct bufferevent_filtered *bevf = arg;
+ struct bufferevent *bev = downcast(bevf);
if (cbinfo->n_added) {
int processed_any = 0;
/* Somebody added more data to the output buffer. Try to
* process it, if we should. */
+ _bufferevent_incref_and_lock(bev);
be_filter_process_output(bevf, BEV_NORMAL, &processed_any);
+ _bufferevent_decref_and_unlock(bev);
}
}
@@ -384,6 +388,8 @@ be_filter_readcb(struct bufferevent *underlying, void *_me)
struct bufferevent *bufev = downcast(bevf);
int processed_any = 0;
+ _bufferevent_incref_and_lock(bufev);
+
if (bevf->got_eof)
state = BEV_FINISHED;
else
@@ -391,10 +397,15 @@ be_filter_readcb(struct bufferevent *underlying, void *_me)
res = be_filter_process_input(bevf, state, &processed_any);
+ /* XXX This should be in process_input, not here. There are
+ * other places that can call process-input, and they should
+ * force readcb calls as needed. */
if (processed_any &&
evbuffer_get_length(bufev->input) >= bufev->wm_read.low &&
bufev->readcb != NULL)
_bufferevent_run_readcb(bufev);
+
+ _bufferevent_decref_and_unlock(bufev);
}
/* Called when the underlying socket has drained enough that we can write to
@@ -403,9 +414,12 @@ static void
be_filter_writecb(struct bufferevent *underlying, void *_me)
{
struct bufferevent_filtered *bevf = _me;
+ struct bufferevent *bev = downcast(bevf);
int processed_any = 0;
+ _bufferevent_incref_and_lock(bev);
be_filter_process_output(bevf, BEV_NORMAL, &processed_any);
+ _bufferevent_decref_and_unlock(bev);
}
/* Called when the underlying socket has given us an error */
@@ -415,9 +429,11 @@ be_filter_eventcb(struct bufferevent *underlying, short what, void *_me)
struct bufferevent_filtered *bevf = _me;
struct bufferevent *bev = downcast(bevf);
+ _bufferevent_incref_and_lock(bev);
/* All we can really to is tell our own eventcb. */
if (bev->errorcb)
_bufferevent_run_eventcb(bev, what);
+ _bufferevent_decref_and_unlock(bev);
}
static int
@@ -428,6 +444,8 @@ be_filter_flush(struct bufferevent *bufev,
int processed_any = 0;
assert(bevf);
+ _bufferevent_incref_and_lock(bufev);
+
if (iotype & EV_READ) {
be_filter_process_input(bevf, mode, &processed_any);
}
@@ -438,6 +456,8 @@ be_filter_flush(struct bufferevent *bufev,
/* XXX does this want to recursively call lower-level flushes? */
bufferevent_flush(bevf->underlying, iotype, mode);
+ _bufferevent_decref_and_unlock(bufev);
+
return processed_any;
}