uloop: improve edge trigger reliability on mac os x

Sometimes after re-arming a fd, an initial event for reads is not generated,
even though there is data pending. Work around this by making the trigger
level-triggered first, then switching to edge trigger after processing the first
event.

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
This commit is contained in:
Felix Fietkau 2013-01-04 03:17:51 +01:00
parent c2916d7bcc
commit 17f4e41ecb
2 changed files with 26 additions and 2 deletions

22
uloop.c
View file

@ -90,7 +90,7 @@ static uint16_t get_flags(unsigned int flags, unsigned int mask)
static struct kevent events[ULOOP_MAX_EVENTS]; static struct kevent events[ULOOP_MAX_EVENTS];
static int register_poll(struct uloop_fd *fd, unsigned int flags) static int register_kevent(struct uloop_fd *fd, unsigned int flags)
{ {
struct timespec timeout = { 0, 0 }; struct timespec timeout = { 0, 0 };
struct kevent ev[2]; struct kevent ev[2];
@ -98,6 +98,9 @@ static int register_poll(struct uloop_fd *fd, unsigned int flags)
unsigned int fl = 0; unsigned int fl = 0;
uint16_t kflags; uint16_t kflags;
if (flags & ULOOP_EDGE_DEFER)
flags &= ~ULOOP_EDGE_TRIGGER;
kflags = get_flags(flags, ULOOP_READ); kflags = get_flags(flags, ULOOP_READ);
EV_SET(&ev[nev++], fd->fd, EVFILT_READ, kflags, 0, 0, fd); EV_SET(&ev[nev++], fd->fd, EVFILT_READ, kflags, 0, 0, fd);
@ -107,12 +110,23 @@ static int register_poll(struct uloop_fd *fd, unsigned int flags)
if (!flags) if (!flags)
fl |= EV_DELETE; fl |= EV_DELETE;
if (nev && (kevent(poll_fd, ev, nev, NULL, fl, &timeout) == -1)) if (kevent(poll_fd, ev, nev, NULL, fl, &timeout) == -1)
return -1; return -1;
return 0; return 0;
} }
static int register_poll(struct uloop_fd *fd, unsigned int flags)
{
if (flags & ULOOP_EDGE_TRIGGER)
flags |= ULOOP_EDGE_DEFER;
else
flags &= ~ULOOP_EDGE_DEFER;
fd->flags = flags;
return register_kevent(fd, flags);
}
int uloop_fd_delete(struct uloop_fd *sock) int uloop_fd_delete(struct uloop_fd *sock)
{ {
int i; int i;
@ -166,6 +180,10 @@ static void uloop_run_events(int timeout)
cur_fd = n; cur_fd = n;
cur_nfds = nfds; cur_nfds = nfds;
u->cb(u, ev); u->cb(u, ev);
if (u->flags & ULOOP_EDGE_DEFER) {
u->flags &= ~ULOOP_EDGE_DEFER;
register_kevent(u, u->flags);
}
} }
} }
cur_nfds = 0; cur_nfds = 0;

View file

@ -46,6 +46,9 @@ typedef void (*uloop_process_handler)(struct uloop_process *c, int ret);
#define ULOOP_WRITE (1 << 1) #define ULOOP_WRITE (1 << 1)
#define ULOOP_EDGE_TRIGGER (1 << 2) #define ULOOP_EDGE_TRIGGER (1 << 2)
#define ULOOP_BLOCKING (1 << 3) #define ULOOP_BLOCKING (1 << 3)
#ifdef USE_KQUEUE
#define ULOOP_EDGE_DEFER (1 << 4)
#endif
struct uloop_fd struct uloop_fd
{ {
@ -54,6 +57,9 @@ struct uloop_fd
bool eof; bool eof;
bool error; bool error;
bool registered; bool registered;
#ifdef USE_KQUEUE
bool flags;
#endif
}; };
struct uloop_timeout struct uloop_timeout