o When we send a BEV_EVENT_CONNECTED to indicate connected status, we no longer invoke the write callback as well unless we actually wrote data too.
o If the kernel tells us that there are a negative number of bytes to read from a socket, do not believe it. Fixes bug 2841177; found by Alexander Pronchenkov.
o Do not detect whether we have monotonic clock support every time a new event base is created: instead do it only once. Patch taken from Chromium.
+ o Do not allocate the maximum event queue for the epoll backend at startup. Instead, start out accepting 32 events at a time, and double the queue's size when it seems that the OS is generating events faster than we're requesting them. Saves up to 374K per epoll-based event_base. Resolves bug 2839240.
Changes in 2.0.2-alpha:
#include <string.h>
#include <unistd.h>
#include <errno.h>
+#include <assert.h>
#ifdef _EVENT_HAVE_FCNTL_H
#include <fcntl.h>
#endif
#define FD_CLOSEONEXEC(x)
#endif
-#define NEVENT 32000
+#define INITIAL_NEVENT 32
+#define MAX_NEVENT 4096
/* On Linux kernels at least up to 2.6.24.4, epoll can't handle timeout
* values bigger than (LONG_MAX - 999ULL)/HZ. HZ in the wild can be
static void *
epoll_init(struct event_base *base)
{
- int epfd, nfiles = NEVENT;
- struct rlimit rl;
+ int epfd;
struct epollop *epollop;
- if (getrlimit(RLIMIT_NOFILE, &rl) == 0 &&
- rl.rlim_cur != RLIM_INFINITY) {
- /*
- * Solaris is somewhat retarded - it's important to drop
- * backwards compatibility when making changes. So, don't
- * dare to put rl.rlim_cur here.
- */
- nfiles = rl.rlim_cur - 1;
- }
-
- /* Initalize the kernel queue */
-
- if ((epfd = epoll_create(nfiles)) == -1) {
+ /* Initalize the kernel queue. (The size field is ignored since
+ * 2.6.8.) */
+ if ((epfd = epoll_create(32000)) == -1) {
if (errno != ENOSYS)
event_warn("epoll_create");
return (NULL);
epollop->epfd = epfd;
/* Initalize fields */
- epollop->events = mm_malloc(nfiles * sizeof(struct epoll_event));
+ epollop->events = mm_malloc(INITIAL_NEVENT * sizeof(struct epoll_event));
if (epollop->events == NULL) {
mm_free(epollop);
return (NULL);
}
- epollop->nevents = nfiles;
+ epollop->nevents = INITIAL_NEVENT;
evsig_init(base);
}
event_debug(("%s: epoll_wait reports %d", __func__, res));
+ assert(res < epollop->nevents);
for (i = 0; i < res; i++) {
int what = events[i].events;
- short res = 0;
+ short ev = 0;
if (what & (EPOLLHUP|EPOLLERR)) {
- res = EV_READ | EV_WRITE;
+ ev = EV_READ | EV_WRITE;
} else {
if (what & EPOLLIN)
- res |= EV_READ;
+ ev |= EV_READ;
if (what & EPOLLOUT)
- res |= EV_WRITE;
+ ev |= EV_WRITE;
}
- if (!res)
+ if (!events)
continue;
- evmap_io_active(base, events[i].data.fd, res | EV_ET);
+ evmap_io_active(base, events[i].data.fd, ev | EV_ET);
+ }
+
+ if (res == epollop->nevents && epollop->nevents < MAX_NEVENT) {
+ /* We used all of the event space this time. We should
+ be ready for more events next time. */
+ int new_nevents = epollop->nevents * 2;
+ struct epoll_event *new_events;
+
+ new_events = mm_realloc(epollop->events,
+ new_nevents * sizeof(struct epoll_event));
+ if (new_events) {
+ epollop->events = new_events;
+ epollop->nevents = new_nevents;
+ }
}
return (0);