Add a lock/unlock pair inside the event callbacks in bufferevents.

This fixes part of bug 2800642, I believe, though there is still a
general race condition in multithreaded use of events that we need to
think about.

svn:r1337
This commit is contained in:
Nick Mathewson 2009-07-10 19:34:00 +00:00
parent 6469598e56
commit a501d6833b
3 changed files with 21 additions and 6 deletions

View File

@ -40,6 +40,7 @@ Changes in 2.0.2-alpha:
o Fix preamble of rpcgen-generated files to rely on event2 includes; based on work by jmansion; patch from Zack Weinberg. o Fix preamble of rpcgen-generated files to rely on event2 includes; based on work by jmansion; patch from Zack Weinberg.
o Allow specifying the output filename for rpcgen; based on work by jmansion; patch from Zack Weinberg. o Allow specifying the output filename for rpcgen; based on work by jmansion; patch from Zack Weinberg.
o Allow C identifiers as struct names; allow multiple comments in .rpc files; from Zack Weinberg o Allow C identifiers as struct names; allow multiple comments in .rpc files; from Zack Weinberg
o Mitigate a race condition when using socket bufferevents in multiple threads.
Changes in 2.0.1-alpha: Changes in 2.0.1-alpha:

View File

@ -574,13 +574,17 @@ static void
bufferevent_generic_read_timeout_cb(evutil_socket_t fd, short event, void *ctx) bufferevent_generic_read_timeout_cb(evutil_socket_t fd, short event, void *ctx)
{ {
struct bufferevent *bev = ctx; struct bufferevent *bev = ctx;
BEV_LOCK(bev);
_bufferevent_run_eventcb(bev, BEV_EVENT_TIMEOUT|BEV_EVENT_READING); _bufferevent_run_eventcb(bev, BEV_EVENT_TIMEOUT|BEV_EVENT_READING);
BEV_UNLOCK(bev);
} }
static void static void
bufferevent_generic_write_timeout_cb(evutil_socket_t fd, short event, void *ctx) bufferevent_generic_write_timeout_cb(evutil_socket_t fd, short event, void *ctx)
{ {
struct bufferevent *bev = ctx; struct bufferevent *bev = ctx;
BEV_LOCK(bev);
_bufferevent_run_eventcb(bev, BEV_EVENT_TIMEOUT|BEV_EVENT_WRITING); _bufferevent_run_eventcb(bev, BEV_EVENT_TIMEOUT|BEV_EVENT_WRITING);
BEV_UNLOCK(bev);
} }
void void

View File

@ -122,6 +122,8 @@ bufferevent_readcb(evutil_socket_t fd, short event, void *arg)
short what = BEV_EVENT_READING; short what = BEV_EVENT_READING;
int howmuch = -1; int howmuch = -1;
BEV_LOCK(arg);
if (event == EV_TIMEOUT) { if (event == EV_TIMEOUT) {
what |= BEV_EVENT_TIMEOUT; what |= BEV_EVENT_TIMEOUT;
goto error; goto error;
@ -138,7 +140,7 @@ bufferevent_readcb(evutil_socket_t fd, short event, void *arg)
/* we somehow lowered the watermark, stop reading */ /* we somehow lowered the watermark, stop reading */
if (howmuch <= 0) { if (howmuch <= 0) {
bufferevent_wm_suspend_read(bufev); bufferevent_wm_suspend_read(bufev);
return; goto done;
} }
} }
@ -166,14 +168,17 @@ bufferevent_readcb(evutil_socket_t fd, short event, void *arg)
bufev->readcb != NULL) bufev->readcb != NULL)
_bufferevent_run_readcb(bufev); _bufferevent_run_readcb(bufev);
return; goto done;
reschedule: reschedule:
return; goto done;
error: error:
event_del(&bufev->ev_read); event_del(&bufev->ev_read);
_bufferevent_run_eventcb(bufev, what); _bufferevent_run_eventcb(bufev, what);
done:
BEV_UNLOCK(bufev);
} }
static void static void
@ -185,6 +190,8 @@ bufferevent_writecb(evutil_socket_t fd, short event, void *arg)
int res = 0; int res = 0;
short what = BEV_EVENT_WRITING; short what = BEV_EVENT_WRITING;
BEV_LOCK(bufev);
if (event == EV_TIMEOUT) { if (event == EV_TIMEOUT) {
what |= BEV_EVENT_TIMEOUT; what |= BEV_EVENT_TIMEOUT;
goto error; goto error;
@ -194,7 +201,7 @@ bufferevent_writecb(evutil_socket_t fd, short event, void *arg)
_bufferevent_run_eventcb(bufev, BEV_EVENT_CONNECTED); _bufferevent_run_eventcb(bufev, BEV_EVENT_CONNECTED);
if (!(bufev->enabled & EV_WRITE)) { if (!(bufev->enabled & EV_WRITE)) {
event_del(&bufev->ev_write); event_del(&bufev->ev_write);
return; goto done;
} }
} }
@ -226,16 +233,19 @@ bufferevent_writecb(evutil_socket_t fd, short event, void *arg)
evbuffer_get_length(bufev->output) <= bufev->wm_write.low) evbuffer_get_length(bufev->output) <= bufev->wm_write.low)
_bufferevent_run_writecb(bufev); _bufferevent_run_writecb(bufev);
return; goto done;
reschedule: reschedule:
if (evbuffer_get_length(bufev->output) == 0) if (evbuffer_get_length(bufev->output) == 0)
event_del(&bufev->ev_write); event_del(&bufev->ev_write);
return; goto done;
error: error:
event_del(&bufev->ev_write); event_del(&bufev->ev_write);
_bufferevent_run_eventcb(bufev, what); _bufferevent_run_eventcb(bufev, what);
done:
BEV_UNLOCK(bufev);
} }
struct bufferevent * struct bufferevent *