diff options
author | Nick Mathewson <nickm@torproject.org> | 2009-10-21 03:54:00 +0000 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2009-10-21 03:54:00 +0000 |
commit | 6b22e74aa187f2bbabb58652070af27fff6f547e (patch) | |
tree | 412937b5b067186fb0c665a7e6a1a39a26ad4fe1 /select.c | |
parent | 50825466821c87f55a7549df47086f7412a5a726 (diff) | |
download | libevent-6b22e74aa187f2bbabb58652070af27fff6f547e.tar.gz |
Add locking to event_base_loop.
This is harder than it sounds, since we need to make sure to
release the lock around the key call to the kernel (e.g.,
select, epoll_wait, kevent), AND we need to make sure that
none of the fields that are used in that call are touched by
anything that might be running concurrently in another
thread. I managed to do this pretty well for everything but
poll(). With poll, I needed to introduce a copy of the
event_set structure.
This patch also fixes a bug in win32.c where we called
realloc() instead of mm_realloc().
svn:r1450
Diffstat (limited to 'select.c')
-rw-r--r-- | select.c | 32 |
1 files changed, 27 insertions, 5 deletions
@@ -50,6 +50,8 @@ #include "event-internal.h" #include "evsignal-internal.h" +#include "event2/thread.h" +#include "evthread-internal.h" #include "log-internal.h" #include "evmap-internal.h" @@ -67,6 +69,7 @@ typedef unsigned long fd_mask; struct selectop { int event_fds; /* Highest fd in fd set */ int event_fdsz; + int resize_out_sets; fd_set *event_readset_in; fd_set *event_writeset_in; fd_set *event_readset_out; @@ -121,19 +124,38 @@ check_selectop(struct selectop *sop) static int select_dispatch(struct event_base *base, struct timeval *tv) { - int res, i, j; + int res=0, i, j, nfds; struct selectop *sop = base->evbase; check_selectop(sop); + if (sop->resize_out_sets) { + fd_set *readset_out=NULL, *writeset_out=NULL; + size_t sz = sop->event_fdsz; + if (!(readset_out = mm_realloc(sop->event_readset_out, sz))) + return (-1); + if (!(writeset_out = mm_realloc(sop->event_writeset_out, sz))) { + mm_free(readset_out); + return (-1); + } + sop->event_readset_out = readset_out; + sop->event_writeset_out = writeset_out; + sop->resize_out_sets = 0; + } memcpy(sop->event_readset_out, sop->event_readset_in, sop->event_fdsz); memcpy(sop->event_writeset_out, sop->event_writeset_in, sop->event_fdsz); - res = select(sop->event_fds + 1, sop->event_readset_out, + nfds = sop->event_fds+1; + + EVBASE_RELEASE_LOCK(base, EVTHREAD_WRITE, th_base_lock); + + res = select(nfds, sop->event_readset_out, sop->event_writeset_out, NULL, tv); + EVBASE_ACQUIRE_LOCK(base, EVTHREAD_WRITE, th_base_lock); + check_selectop(sop); if (res == -1) { @@ -151,9 +173,9 @@ select_dispatch(struct event_base *base, struct timeval *tv) event_debug(("%s: select reports %d", __func__, res)); check_selectop(sop); - i = random() % (sop->event_fds+1); - for (j = 0; j <= sop->event_fds; ++j) { - if (++i >= sop->event_fds+1) + i = random() % (nfds+1); + for (j = 0; j <= nfds; ++j) { + if (++i >= nfds+1) i = 0; res = 0; if (FD_ISSET(i, sop->event_readset_out)) |