diff options
Diffstat (limited to 'ev_epoll.c')
-rw-r--r-- | ev_epoll.c | 33 |
1 files changed, 31 insertions, 2 deletions
@@ -1,7 +1,7 @@ /* * libev epoll fd activity backend * - * Copyright (c) 2007,2008,2009,2010 Marc Alexander Lehmann <libev@schmorp.de> + * Copyright (c) 2007,2008,2009,2010,2011 Marc Alexander Lehmann <libev@schmorp.de> * All rights reserved. * * Redistribution and use in source and binary forms, with or without modifica- @@ -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 <sys/epoll.h> +#define EV_EMASK_EPERM 0x80 + static void epoll_modify (EV_P_ int fd, int oev, int nev) { @@ -112,6 +115,19 @@ epoll_modify (EV_P_ int fd, int oev, int nev) if (!epoll_ctl (backend_fd, EPOLL_CTL_MOD, fd, &ev)) return; } + else if (expect_true (errno == EPERM)) + { + 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); @@ -186,6 +202,18 @@ epoll_poll (EV_P_ ev_tstamp timeout) 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 add 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 +245,7 @@ void inline_size epoll_destroy (EV_P) { ev_free (epoll_events); + array_free (epoll_eperm, EMPTY); } void inline_size |