diff --git a/ae.c b/ae.c index 4f12e410..048fa51c 100644 --- a/ae.c +++ b/ae.c @@ -45,7 +45,11 @@ #ifdef HAVE_EPOLL #include "ae_epoll.c" #else -#include "ae_select.c" + #ifdef HAVE_KQUEUE + #include "ae_kqueue.c" + #else + #include "ae_select.c" + #endif #endif aeEventLoop *aeCreateEventLoop(void) { diff --git a/ae_kqueue.c b/ae_kqueue.c new file mode 100644 index 00000000..1dc86af5 --- /dev/null +++ b/ae_kqueue.c @@ -0,0 +1,90 @@ +/* Kqueue(2)-based ae.c module + * Copyright (C) 2009 Harish Mallipeddi - harish.mallipeddi@gmail.com + * Released under the BSD license. See the COPYING file for more info. */ + +#include +#include +#include + +typedef struct aeApiState { + int kqfd; + struct kevent events[AE_SETSIZE]; +} aeApiState; + +static int aeApiCreate(aeEventLoop *eventLoop) { + aeApiState *state = zmalloc(sizeof(aeApiState)); + + if (!state) return -1; + state->kqfd = kqueue(); + if (state->kqfd == -1) return -1; + eventLoop->apidata = state; + + return 0; +} + +static void aeApiFree(aeEventLoop *eventLoop) { + aeApiState *state = eventLoop->apidata; + + close(state->kqfd); + zfree(state); +} + +static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask) { + aeApiState *state = eventLoop->apidata; + struct kevent ke; + + if (mask & AE_READABLE) { + EV_SET(&ke, fd, EVFILT_READ, EV_ADD, 0, 0, NULL); + if (kevent(state->kqfd, &ke, 1, NULL, 0, NULL) == -1) return -1; + } + if (mask & AE_WRITABLE) { + EV_SET(&ke, fd, EVFILT_WRITE, EV_ADD, 0, 0, NULL); + if (kevent(state->kqfd, &ke, 1, NULL, 0, NULL) == -1) return -1; + } + return 0; +} + +static void aeApiDelEvent(aeEventLoop *eventLoop, int fd, int mask) { + aeApiState *state = eventLoop->apidata; + struct kevent ke; + + if (mask & AE_READABLE) { + EV_SET(&ke, fd, EVFILT_READ, EV_DELETE, 0, 0, NULL); + kevent(state->kqfd, &ke, 1, NULL, 0, NULL); + } + if (mask & AE_WRITABLE) { + EV_SET(&ke, fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL); + kevent(state->kqfd, &ke, 1, NULL, 0, NULL); + } +} + +static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) { + aeApiState *state = eventLoop->apidata; + int retval, numevents = 0; + + if (tvp != NULL) { + struct timespec timeout; + timeout.tv_sec = tvp->tv_sec; + timeout.tv_nsec = tvp->tv_usec * 1000; + retval = kevent(state->kqfd, NULL, 0, state->events, AE_SETSIZE, &timeout); + } else { + retval = kevent(state->kqfd, NULL, 0, state->events, AE_SETSIZE, NULL); + } + + if (retval > 0) { + int j; + + numevents = retval; + for(j = 0; j < numevents; j++) { + int mask = 0; + struct kevent *e = state->events+j; + + if (e->filter == EVFILT_READ) mask |= AE_READABLE; + if (e->filter == EVFILT_WRITE) mask |= AE_WRITABLE; + eventLoop->fired[j].fd = e->ident; + eventLoop->fired[j].mask = mask; + } + + } + return numevents; +} \ No newline at end of file diff --git a/config.h b/config.h index af733895..86e943dd 100644 --- a/config.h +++ b/config.h @@ -31,4 +31,8 @@ #define HAVE_EPOLL 1 #endif +#ifdef __APPLE__ +#define HAVE_KQUEUE 1 +#endif + #endif