diff options
author | Nick Mathewson <nickm@torproject.org> | 2009-07-17 17:46:17 +0000 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2009-07-17 17:46:17 +0000 |
commit | a62283a9c3a46c4ba0d72eb3bc18a3db7f9648e2 (patch) | |
tree | 2634a85482534f62112cf307c68acfdbf093e7ac /bufferevent_filter.c | |
parent | e83a32dfe1c10c90c27ccf1f4f93a59820517108 (diff) | |
download | libevent-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.c | 20 |
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; } |