From b99254ac22d8fda951a6a0f28279c5ffc19afecf Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 24 Jun 2009 22:39:03 +0000 Subject: [PATCH] Activate fd events in a pseudorandom order on older backends. New backends like poll and kqueue and so on add fds to the queue in the order that they are triggered. But the select backend currently activates low-numbered fds first, whereas the poll and win32 backends currently favor whatever fds have been on for the longest. This is no good for fairness. svn:r1327 --- ChangeLog | 2 +- WIN32-Code/win32.c | 51 +++++++++++++++++++++++++++------------------- poll.c | 13 ++++++++---- select.c | 8 ++++++-- 4 files changed, 46 insertions(+), 28 deletions(-) diff --git a/ChangeLog b/ChangeLog index 46afa167..afe50078 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,7 @@ Changes in 1.4.12-stable: o Try to contain degree of failure when running on a win32 version so heavily firewalled that we can't fake a socketpair. o Fix an obscure timing-dependent, allocator-dependent crash in the evdns code. o Use __VA_ARGS__ syntax for varargs macros in event_rpcgen when compiler is not GCC. + o Activate fd events in a pseudorandom order with O(N) backends, so that we don't systematically favor low fds (select) or earlier-added fds (poll, win32). o Fix another pair of fencepost bugs in epoll.c. [Patch from Adam Langley.] Changes in 1.4.11-stable: @@ -86,7 +87,6 @@ Changes in 1.4.4-stable: o Fix autoconf script behavior on IRIX. o Make sure winsock2.h include always comes before windows.h include. - Changes in 1.4.3-stable: o include Content-Length in reply for HTTP/1.0 requests with keep-alive o Patch from Tani Hosokawa: make some functions in http.c threadsafe. diff --git a/WIN32-Code/win32.c b/WIN32-Code/win32.c index 213af37a..0d4705fd 100644 --- a/WIN32-Code/win32.c +++ b/WIN32-Code/win32.c @@ -352,8 +352,9 @@ win32_dispatch(struct event_base *base, void *op, { struct win32op *win32op = op; int res = 0; - unsigned i; + unsigned j, i; int fd_count; + SOCKET s; fd_set_copy(win32op->readset_out, win32op->readset_in); fd_set_copy(win32op->exset_out, win32op->readset_in); @@ -384,29 +385,37 @@ win32_dispatch(struct event_base *base, void *op, evsignal_process(base); } - for (i=0; ireadset_out->fd_count; ++i) { - struct event_entry *ent; - SOCKET s = win32op->readset_out->fd_array[i]; - if ((ent = get_event_entry(win32op, s, 0)) && ent->read_event) - event_active(ent->read_event, EV_READ, 1); + if (win32op->readset_out->fd_count) { + i = rand() % win32op->readset_out->fd_count; + for (j=0; jreadset_out->fd_count; ++j) { + if (++i >= win32op->readset_out->fd_count) + i = 0; + s = win32op->readset_out->fd_array[i]; + if ((ent = get_event_entry(win32op, s, 0)) && ent->read_event) + event_active(ent->read_event, EV_READ, 1); + } } - for (i=0; iexset_out->fd_count; ++i) { - struct event_entry *ent; - SOCKET s = win32op->exset_out->fd_array[i]; - if ((ent = get_event_entry(win32op, s, 0)) && ent->read_event) - event_active(ent->read_event, EV_READ, 1); - } - for (i=0; iwriteset_out->fd_count; ++i) { - struct event_entry *ent; - SOCKET s = win32op->writeset_out->fd_array[i]; - if ((ent = get_event_entry(win32op, s, 0)) && ent->write_event) - event_active(ent->write_event, EV_WRITE, 1); + if (win32op->exset_out->fd_count) { + i = rand() % win32op->exset_out->fd_count; + for (j=0; jexset_out->fd_count; ++j) { + if (++i >= win32op-exset_out->fd_count) + i = 0; + s = win32op->exset_out->fd_array[i]; + if ((ent = get_event_entry(win32op, s, 0)) && ent->read_event) + event_active(ent->read_event, EV_READ, 1); + } } + if (win32op->writeset_out->fd_count) { + i = rand() % win32op->writeset_out->fd_count; + for (j=0; jwriteset_out->fd_count; ++j) { + if (++i >= win32op-exset_out->fd_count) + i = 0; + s = win32op->writeset_out->fd_array[i]; + if ((ent = get_event_entry(win32op, s, 0)) && ent->write_event) + event_active(ent->write_event, EV_WRITE, 1); -#if 0 - if (signal_recalc() == -1) - return (-1); -#endif + } + } return (0); } diff --git a/poll.c b/poll.c index b67c6ffa..5d496618 100644 --- a/poll.c +++ b/poll.c @@ -135,7 +135,7 @@ poll_check_ok(struct pollop *pop) static int poll_dispatch(struct event_base *base, void *arg, struct timeval *tv) { - int res, i, msec = -1, nfds; + int res, i, j, msec = -1, nfds; struct pollop *pop = arg; poll_check_ok(pop); @@ -160,12 +160,17 @@ poll_dispatch(struct event_base *base, void *arg, struct timeval *tv) event_debug(("%s: poll reports %d", __func__, res)); - if (res == 0) + if (res == 0 || nfds == 0) return (0); - for (i = 0; i < nfds; i++) { - int what = pop->event_set[i].revents; + i = random() % nfds; + for (j = 0; j < nfds; j++) { struct event *r_ev = NULL, *w_ev = NULL; + int what; + if (++i == nfds) + i = 0; + what = pop->event_set[i].revents; + if (!what) continue; diff --git a/select.c b/select.c index 7faafe4e..ca6639fd 100644 --- a/select.c +++ b/select.c @@ -137,7 +137,7 @@ check_selectop(struct selectop *sop) static int select_dispatch(struct event_base *base, void *arg, struct timeval *tv) { - int res, i; + int res, i, j; struct selectop *sop = arg; check_selectop(sop); @@ -167,8 +167,12 @@ select_dispatch(struct event_base *base, void *arg, struct timeval *tv) event_debug(("%s: select reports %d", __func__, res)); check_selectop(sop); - for (i = 0; i <= sop->event_fds; ++i) { + i = random() % (sop->event_fds+1); + for (j = 0; j <= sop->event_fds; ++j) { struct event *r_ev = NULL, *w_ev = NULL; + if (++i >= sop->event_fds+1) + i = 0; + res = 0; if (FD_ISSET(i, sop->event_readset_out)) { r_ev = sop->event_r_by_fd[i];