--- libev/ev_epoll.c 2010/10/22 10:50:24 1.54 +++ libev/ev_epoll.c 2011/02/16 08:02:50 1.60 @@ -1,19 +1,19 @@ /* * libev epoll fd activity backend * - * Copyright (c) 2007,2008,2009,2010 Marc Alexander Lehmann + * Copyright (c) 2007,2008,2009,2010,2011 Marc Alexander Lehmann * All rights reserved. * * Redistribution and use in source and binary forms, with or without modifica- * tion, are permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO @@ -53,7 +53,8 @@ * (such as files). while not critical, no other advanced interface * seems to share this (rather non-unixy) limitation. * e) epoll claims to be embeddable, but in practise you never get - * a ready event for the epoll fd. + * a ready event for the epoll fd (broken: <=2.6.26, working: >=2.6.32). + * f) epoll_ctl returning EPERM means the fd is always ready. * * lots of "weird code" and complication handling in this file is due * to these design problems with epoll, as we try very hard to avoid @@ -64,6 +65,8 @@ #include +#define EV_EMASK_EPERM 0x80 + static void epoll_modify (EV_P_ int fd, int oev, int nev) { @@ -112,6 +115,21 @@ if (!epoll_ctl (backend_fd, EPOLL_CTL_MOD, fd, &ev)) return; } + else if (expect_true (errno == EPERM)) + { + /* EPERM means the fd is always ready, but epoll is too snobbish */ + /* to handle it, unlike select or poll. */ + anfds [fd].emask = EV_EMASK_EPERM; + + /* add fd to epoll_eperms, if not already inside */ + if (!(oldmask & EV_EMASK_EPERM)) + { + array_needsize (int, epoll_eperms, epoll_epermmax, epoll_epermcnt + 1, EMPTY2); + epoll_eperms [epoll_epermcnt++] = fd; + } + + return; + } fd_kill (EV_A_ fd); @@ -125,11 +143,12 @@ { int i; int eventcnt; - + /* epoll wait times cannot be larger than (LONG_MAX - 999UL) / HZ msecs, which is below */ /* the default libev max wait time, however. */ EV_RELEASE_CB; - eventcnt = epoll_wait (backend_fd, epoll_events, epoll_eventmax, (int)ceil (timeout * 1000.)); + eventcnt = epoll_wait (backend_fd, epoll_events, epoll_eventmax, + epoll_epermcnt ? 0 : ev_timeout_to_ms (timeout)); EV_ACQUIRE_CB; if (expect_false (eventcnt < 0)) @@ -186,6 +205,18 @@ epoll_eventmax = array_nextsize (sizeof (struct epoll_event), epoll_eventmax, epoll_eventmax + 1); epoll_events = (struct epoll_event *)ev_malloc (sizeof (struct epoll_event) * epoll_eventmax); } + + /* now synthesize events for all fds where epoll fails, while select works... */ + for (i = epoll_epermcnt; i--; ) + { + int fd = epoll_eperms [i]; + unsigned char events = anfds [fd].events & (EV_READ | EV_WRITE); + + if (anfds [fd].emask & EV_EMASK_EPERM && events) + fd_event (EV_A_ fd, events); + else + epoll_eperms [i] = epoll_eperms [--epoll_epermcnt]; + } } int inline_size @@ -217,6 +248,7 @@ epoll_destroy (EV_P) { ev_free (epoll_events); + array_free (epoll_eperm, EMPTY); } void inline_size