summaryrefslogtreecommitdiff
path: root/select.c
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2009-10-21 03:54:00 +0000
committerNick Mathewson <nickm@torproject.org>2009-10-21 03:54:00 +0000
commit6b22e74aa187f2bbabb58652070af27fff6f547e (patch)
tree412937b5b067186fb0c665a7e6a1a39a26ad4fe1 /select.c
parent50825466821c87f55a7549df47086f7412a5a726 (diff)
downloadlibevent-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.c32
1 files changed, 27 insertions, 5 deletions
diff --git a/select.c b/select.c
index ace8037c..9164ac91 100644
--- a/select.c
+++ b/select.c
@@ -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))