Make bufferevent_free() clear all callbacks immediately.

This should end the family of bugs where we call bufferevent_free()
while a pending callback is holding a reference on the bufferevent,
and the callback tries to invoke the user callbacks before it releases
its own final reference.

This means that bufferevent_decref() is now a separate function from
bufferevent_free().
This commit is contained in:
Nick Mathewson 2010-02-22 15:38:23 -05:00
parent 4faeaea90e
commit b2fbeb3f07
3 changed files with 11 additions and 3 deletions

View File

@ -413,7 +413,7 @@ evbuffer_deferred_callback(struct deferred_cb *cb, void *arg)
evbuffer_run_callbacks(buffer, 1);
_evbuffer_decref_and_unlock(buffer);
if (parent)
bufferevent_free(parent);
bufferevent_decref(parent);
}
static void

View File

@ -274,11 +274,11 @@ void bufferevent_incref(struct bufferevent *bufev);
/** Internal: Lock bufev and increase its reference count.
* unlocking it otherwise. */
void _bufferevent_incref_and_lock(struct bufferevent *bufev);
/** Internal: Increment the reference count on bufev. */
void bufferevent_decref(struct bufferevent *bufev);
/** Internal: Drop the reference count on bufev, freeing as necessary, and
* unlocking it otherwise. */
void _bufferevent_decref_and_unlock(struct bufferevent *bufev);
/** Sometimes it is more clear to say "decref" than "free" */
#define bufferevent_decref(b) bufferevent_free(b)
/** Internal: If callbacks are deferred and we have a read callback, schedule
* a readcb. Otherwise just run the readcb. */

View File

@ -560,10 +560,18 @@ _bufferevent_decref_and_unlock(struct bufferevent *bufev)
bufferevent_decref(underlying);
}
void
bufferevent_decref(struct bufferevent *bufev)
{
BEV_LOCK(bufev);
_bufferevent_decref_and_unlock(bufev);
}
void
bufferevent_free(struct bufferevent *bufev)
{
BEV_LOCK(bufev);
bufferevent_setcb(bufev, NULL, NULL, NULL, NULL);
_bufferevent_decref_and_unlock(bufev);
}