X-Git-Url: http://git.pk910.de/?a=blobdiff_plain;f=ircd%2Fengine_epoll.c;h=a9be73735ea97fe7b7bfdbf8a2a53fd94feaa5bf;hb=refs%2Fheads%2Fupstream;hp=6680dace15d9f78ee830af0ebc490f433b095d3d;hpb=79035436c61e2b58004b47f250ab1e54744a88d6;p=ircu2.10.12-pk.git diff --git a/ircd/engine_epoll.c b/ircd/engine_epoll.c index 6680dac..a9be737 100644 --- a/ircd/engine_epoll.c +++ b/ircd/engine_epoll.c @@ -15,8 +15,10 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * $Id$ + */ +/** @file + * @brief Linux epoll_*() event engine. + * @version $Id$ */ #include "config.h" @@ -27,7 +29,7 @@ #include "ircd_log.h" #include "s_debug.h" -#include +/* #include -- Now using assert in ircd_log.h */ #include #include #ifdef HAVE_STDINT_H @@ -46,11 +48,7 @@ /* Oh, did we mention that some glibc releases do not even define the * syscall numbers? */ #if !defined(__NR_epoll_create) -#if defined(__i386__) -#define __NR_epoll_create 254 -#define __NR_epoll_ctl 255 -#define __NR_epoll_wait 256 -#elif defined(__ia64__) +#if defined(__ia64__) #define __NR_epoll_create 1243 #define __NR_epoll_ctl 1244 #define __NR_epoll_wait 1245 @@ -58,6 +56,34 @@ #define __NR_epoll_create 214 #define __NR_epoll_ctl 233 #define __NR_epoll_wait 232 +#elif defined(__sparc64__) || defined(__sparc__) +#define __NR_epoll_create 193 +#define __NR_epoll_ctl 194 +#define __NR_epoll_wait 195 +#elif defined(__s390__) || defined(__m68k__) +#define __NR_epoll_create 249 +#define __NR_epoll_ctl 250 +#define __NR_epoll_wait 251 +#elif defined(__ppc64__) || defined(__ppc__) +#define __NR_epoll_create 236 +#define __NR_epoll_ctl 237 +#define __NR_epoll_wait 238 +#elif defined(__parisc__) || defined(__arm26__) || defined(__arm__) +#define __NR_epoll_create 224 +#define __NR_epoll_ctl 225 +#define __NR_epoll_wait 226 +#elif defined(__alpha__) +#define __NR_epoll_create 407 +#define __NR_epoll_ctl 408 +#define __NR_epoll_wait 409 +#elif defined(__sh64__) +#define __NR_epoll_create 282 +#define __NR_epoll_ctl 283 +#define __NR_epoll_wait 284 +#elif defined(__i386__) || defined(__sh__) || defined(__m32r__) || defined(__h8300__) || defined(__frv__) +#define __NR_epoll_create 254 +#define __NR_epoll_ctl 255 +#define __NR_epoll_wait 256 #else /* cpu types */ #error No system call numbers defined for epoll family. #endif /* cpu types */ @@ -69,14 +95,23 @@ _syscall4(int, epoll_wait, int, epfd, struct epoll_event *, pevents, int, maxeve #endif /* epoll_create defined as stub */ -#define EPOLL_ERROR_THRESHOLD 20 /* after 20 epoll errors, restart */ -#define ERROR_EXPIRE_TIME 3600 /* expire errors after an hour */ +#define EPOLL_ERROR_THRESHOLD 20 /**< after 20 epoll errors, restart */ +#define ERROR_EXPIRE_TIME 3600 /**< expire errors after an hour */ +/** File descriptor for epoll pseudo-file. */ static int epoll_fd; +/** Number of recent epoll errors. */ static int errors; +/** Periodic timer to forget errors. */ static struct Timer clear_error; +/** Current array of event descriptors. */ +static struct epoll_event *events; +/** Number of ::events elements that have been populated. */ +static int events_used; -/* decrements the error count once per hour */ +/** Decrement the error count (once per hour). + * @param[in] ev Expired timer event (ignored). + */ static void error_clear(struct Event *ev) { @@ -84,7 +119,10 @@ error_clear(struct Event *ev) timer_del(ev_timer(ev)); } -/* initialize the epoll engine */ +/** Initialize the epoll engine. + * @param[in] max_sockets Maximum number of file descriptors to support. + * @return Non-zero on success, or zero on failure. + */ static int engine_init(int max_sockets) { @@ -96,6 +134,12 @@ engine_init(int max_sockets) return 1; } +/** Set events for a particular socket. + * @param[in] sock Socket to calculate events for. + * @param[in] state Current socket state. + * @param[in] events User-specified event interest list. + * @param[out] evt epoll event structure for socket. + */ static void set_events(struct Socket *sock, enum SocketState state, unsigned int events, struct epoll_event *evt) { @@ -136,6 +180,10 @@ set_events(struct Socket *sock, enum SocketState state, unsigned int events, str } } +/** Add a socket to the event engine. + * @param[in] sock Socket to add to engine. + * @return Non-zero on success, or zero on error. + */ static int engine_add(struct Socket *sock) { @@ -152,6 +200,10 @@ engine_add(struct Socket *sock) return 1; } +/** Handle state transition for a socket. + * @param[in] sock Socket changing state. + * @param[in] new_state New state for socket. + */ static void engine_set_state(struct Socket *sock, enum SocketState new_state) { @@ -165,6 +217,10 @@ engine_set_state(struct Socket *sock, enum SocketState new_state) event_generate(ET_ERROR, sock, errno); } +/** Handle change to preferred socket events. + * @param[in] sock Socket getting new interest list. + * @param[in] new_events New set of interesting events for socket. + */ static void engine_set_events(struct Socket *sock, unsigned new_events) { @@ -178,44 +234,52 @@ engine_set_events(struct Socket *sock, unsigned new_events) event_generate(ET_ERROR, sock, errno); } +/** Remove a socket from the event engine. + * @param[in] sock Socket being destroyed. + */ static void engine_delete(struct Socket *sock) { - struct epoll_event evt; + int ii; assert(0 != sock); - memset(&evt, 0, sizeof(evt)); Debug((DEBUG_ENGINE, "epoll: Deleting socket %d [%p], state %s", s_fd(sock), sock, state_to_name(s_state(sock)))); - if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, s_fd(sock), &evt) < 0) - log_write(LS_SOCKET, L_WARNING, 0, - "Unable to delete epoll item for socket %d", s_fd(sock)); + /* Drop any unprocessed events citing this socket. */ + for (ii = 0; ii < events_used; ii++) { + if (events[ii].data.ptr == sock) { + events[ii] = events[--events_used]; + } + } } +/** Run engine event loop. + * @param[in] gen Lists of generators of various types. + */ static void engine_loop(struct Generators *gen) { - struct epoll_event *events; + struct epoll_event *evt; struct Socket *sock; - size_t codesize; - int events_count, i, wait, nevs, errcode; + socklen_t codesize; + int events_count, tmp, wait, errcode; if ((events_count = feature_int(FEAT_POLLS_PER_LOOP)) < 20) events_count = 20; events = MyMalloc(sizeof(events[0]) * events_count); while (running) { - if ((i = feature_int(FEAT_POLLS_PER_LOOP)) >= 20 && i != events_count) { - events = MyRealloc(events, sizeof(events[0]) * i); - events_count = i; + if ((tmp = feature_int(FEAT_POLLS_PER_LOOP)) >= 20 && tmp != events_count) { + events = MyRealloc(events, sizeof(events[0]) * tmp); + events_count = tmp; } wait = timer_next(gen) ? (timer_next(gen) - CurrentTime) * 1000 : -1; - Debug((DEBUG_INFO, "epoll: delay: %d (%d) %d", timer_next(gen), + Debug((DEBUG_ENGINE, "epoll: delay: %d (%d) %d", timer_next(gen), CurrentTime, wait)); - nevs = epoll_wait(epoll_fd, events, events_count, wait); + events_used = epoll_wait(epoll_fd, events, events_count, wait); CurrentTime = time(0); - if (nevs < 0) { + if (events_used < 0) { if (errno != EINTR) { log_write(LS_SOCKET, L_ERROR, 0, "epoll() error: %m"); if (!errors++) @@ -227,8 +291,9 @@ engine_loop(struct Generators *gen) continue; } - for (i = 0; i < nevs; i++) { - if (!(sock = events[i].data.ptr)) + while (events_used > 0) { + evt = &events[--events_used]; + if (!(sock = evt->data.ptr)) continue; gen_ref_inc(sock); Debug((DEBUG_ENGINE, @@ -236,7 +301,7 @@ engine_loop(struct Generators *gen) sock, s_fd(sock), state_to_name(s_state(sock)), sock_flags(s_events(sock)))); - if (events[i].events & EPOLLERR) { + if (evt->events & EPOLLERR) { errcode = 0; codesize = sizeof(errcode); if (getsockopt(s_fd(sock), SOL_SOCKET, SO_ERROR, &errcode, @@ -247,32 +312,26 @@ engine_loop(struct Generators *gen) gen_ref_dec(sock); continue; } - } - - switch (s_state(sock)) { + } else if (evt->events & EPOLLHUP) { + event_generate(ET_EOF, sock, 0); + } else switch (s_state(sock)) { case SS_CONNECTING: - if (events[i].events & EPOLLOUT) /* connection completed */ + if (evt->events & EPOLLOUT) /* connection completed */ event_generate(ET_CONNECT, sock, 0); break; case SS_LISTENING: - if (events[i].events & EPOLLIN) /* incoming connection */ + if (evt->events & EPOLLIN) /* incoming connection */ event_generate(ET_ACCEPT, sock, 0); break; case SS_NOTSOCK: case SS_CONNECTED: - if (events[i].events & EPOLLIN) - event_generate((events[i].events & EPOLLHUP) ? ET_EOF : ET_READ, sock, 0); - if (events[i].events & EPOLLOUT) - event_generate(ET_WRITE, sock, 0); - break; - case SS_DATAGRAM: case SS_CONNECTDG: - if (events[i].events & EPOLLIN) + if (evt->events & EPOLLIN) event_generate(ET_READ, sock, 0); - if (events[i].events & EPOLLOUT) + if (evt->events & EPOLLOUT) event_generate(ET_WRITE, sock, 0); break; } @@ -280,8 +339,10 @@ engine_loop(struct Generators *gen) } timer_run(); } + MyFree(events); } +/** Descriptor for epoll event engine. */ struct Engine engine_epoll = { "epoll()", engine_init,