/* Since Linux 2.6.17, epoll is able to report about peer half-closed connection usingspecialEPOLLRDHUPflagonareadevent.
*/ #if !defined(EPOLLRDHUP) #define EPOLLRDHUP 0 #define EARLY_CLOSE_IF_HAVE_RDHUP 0 #else #define EARLY_CLOSE_IF_HAVE_RDHUP EV_FEATURE_EARLY_CLOSE #endif
#include"epolltable-internal.h"
#ifdefined(EVENT__HAVE_SYS_TIMERFD_H) && \ defined(EVENT__HAVE_TIMERFD_CREATE) && \ defined(HAVE_POSIX_MONOTONIC) && defined(TFD_NONBLOCK) && \ defined(TFD_CLOEXEC) /* Note that we only use timerfd if TFD_NONBLOCK and TFD_CLOEXEC are available andworking.Thismeansthatwecan'tsupportiton2.6.25(wheretimerfd wasintroduced)or2.6.26,since2.6.27introducedthoseflags.
*/ #define USING_TIMERFD #endif
struct epollop { struct epoll_event *events; int nevents; int epfd; #ifdef USING_TIMERFD int timerfd; #endif
};
/* On Linux kernels at least up to 2.6.24.4, epoll can't handle timeout *valuesbiggerthan(LONG_MAX-999ULL)/HZ.HZinthewildcanbe *asbigas1000,andLONG_MAXcanbeassmallas(1<<31)-1,sothe *largestnumberofmsecwecansupporthereis2147482.Let's *roundthatdownby47seconds.
*/ #define MAX_EPOLL_TIMEOUT_MSEC (35*60*1000)
#ifdef EVENT__HAVE_EPOLL_CREATE1 /* First, try the shiny new epoll_create1 interface, if we have it. */
epfd = epoll_create1(EPOLL_CLOEXEC); #endif if (epfd == -1) { /* Initialize the kernel queue using the old interface. (The
size field is ignored since 2.6.8.) */ if ((epfd = epoll_create(32000)) == -1) { if (errno != ENOSYS)
event_warn("epoll_create"); return (NULL);
}
evutil_make_socket_closeonexec(epfd);
}
switch (op) { case EPOLL_CTL_MOD: if (errno == ENOENT) { /* If a MOD operation fails with ENOENT, the *fdwasprobablyclosedandre-opened.We *shouldretrytheoperationasanADD.
*/ if (epoll_ctl(epollop->epfd, EPOLL_CTL_ADD, ch->fd, &epev) == -1) {
event_warn("Epoll MOD(%d) on %d retried as ADD; that failed too",
(int)epev.events, ch->fd); return -1;
} else {
event_debug(("Epoll MOD(%d) on %d retried as ADD; succeeded.",
(int)epev.events,
ch->fd)); return0;
}
} break; case EPOLL_CTL_ADD: if (errno == EEXIST) { /* If an ADD operation fails with EEXIST, *eithertheoperationwasredundant(aswitha *precautionaryadd),orweranintoafun *kernelbugwhereusingdup*()toduplicatethe *samefileintothesamefdgivesyouthesameepitem *ratherthanafreshone.Forthesecondcase,
* we must retry with MOD. */ if (epoll_ctl(epollop->epfd, EPOLL_CTL_MOD, ch->fd, &epev) == -1) {
event_warn("Epoll ADD(%d) on %d retried as MOD; that failed too",
(int)epev.events, ch->fd); return -1;
} else {
event_debug(("Epoll ADD(%d) on %d retried as MOD; succeeded.",
(int)epev.events,
ch->fd)); return0;
}
} break; case EPOLL_CTL_DEL: if (errno == ENOENT || errno == EBADF || errno == EPERM) { /* If a delete fails with one of these errors, *that'sfinetoo:weclosedthefdbeforewe
* got around to calling epoll_dispatch. */
event_debug(("Epoll DEL(%d) on fd %d gave %s: DEL was unnecessary.",
(int)epev.events,
ch->fd,
strerror(errno))); return0;
} break; default: break;
}
for (i = 0; i < res; i++) { int what = events[i].events; short ev = 0; #ifdef USING_TIMERFD if (events[i].data.fd == epollop->timerfd) continue; #endif
if (what & EPOLLERR) {
ev = EV_READ | EV_WRITE;
} elseif ((what & EPOLLHUP) && !(what & EPOLLRDHUP)) {
ev = EV_READ | EV_WRITE;
} else { if (what & EPOLLIN)
ev |= EV_READ; if (what & EPOLLOUT)
ev |= EV_WRITE; if (what & EPOLLRDHUP)
ev |= EV_CLOSED;
}
if (!ev) continue;
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;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.