1 /* Linux epoll(2) based ae.c module 2 * Copyright (C) 2009-2010 Salvatore Sanfilippo - [email protected] 3 * Released under the BSD license. See the COPYING file for more info. */ 4 5 #include <sys/epoll.h> 6 7 typedef struct aeApiState { 8 int epfd; 9 struct epoll_event *events; 10 } aeApiState; 11 12 static int aeApiCreate(aeEventLoop *eventLoop) { 13 aeApiState *state = zmalloc(sizeof(aeApiState)); 14 15 if (!state) return -1; 16 state->events = zmalloc(sizeof(struct epoll_event)*eventLoop->setsize); 17 if (!state->events) { 18 zfree(state); 19 return -1; 20 } 21 state->epfd = epoll_create(1024); /* 1024 is just an hint for the kernel */ 22 if (state->epfd == -1) { 23 zfree(state->events); 24 zfree(state); 25 return -1; 26 } 27 eventLoop->apidata = state; 28 return 0; 29 } 30 31 static void aeApiFree(aeEventLoop *eventLoop) { 32 aeApiState *state = eventLoop->apidata; 33 34 close(state->epfd); 35 zfree(state->events); 36 zfree(state); 37 } 38 39 static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask) { 40 aeApiState *state = eventLoop->apidata; 41 struct epoll_event ee; 42 /* If the fd was already monitored for some event, we need a MOD 43 * operation. Otherwise we need an ADD operation. */ 44 int op = eventLoop->events[fd].mask == AE_NONE ? 45 EPOLL_CTL_ADD : EPOLL_CTL_MOD; 46 47 ee.events = 0; 48 mask |= eventLoop->events[fd].mask; /* Merge old events */ 49 if (mask & AE_READABLE) ee.events |= EPOLLIN; 50 if (mask & AE_WRITABLE) ee.events |= EPOLLOUT; 51 ee.data.u64 = 0; /* avoid valgrind warning */ 52 ee.data.fd = fd; 53 if (epoll_ctl(state->epfd,op,fd,&ee) == -1) return -1; 54 return 0; 55 } 56 57 static void aeApiDelEvent(aeEventLoop *eventLoop, int fd, int delmask) { 58 aeApiState *state = eventLoop->apidata; 59 struct epoll_event ee; 60 int mask = eventLoop->events[fd].mask & (~delmask); 61 62 ee.events = 0; 63 if (mask & AE_READABLE) ee.events |= EPOLLIN; 64 if (mask & AE_WRITABLE) ee.events |= EPOLLOUT; 65 ee.data.u64 = 0; /* avoid valgrind warning */ 66 ee.data.fd = fd; 67 if (mask != AE_NONE) { 68 epoll_ctl(state->epfd,EPOLL_CTL_MOD,fd,&ee); 69 } else { 70 /* Note, Kernel < 2.6.9 requires a non null event pointer even for 71 * EPOLL_CTL_DEL. */ 72 epoll_ctl(state->epfd,EPOLL_CTL_DEL,fd,&ee); 73 } 74 } 75 76 static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) { 77 aeApiState *state = eventLoop->apidata; 78 int retval, numevents = 0; 79 80 retval = epoll_wait(state->epfd,state->events,eventLoop->setsize, 81 tvp ? (tvp->tv_sec*1000 + tvp->tv_usec/1000) : -1); 82 if (retval > 0) { 83 int j; 84 85 numevents = retval; 86 for (j = 0; j < numevents; j++) { 87 int mask = 0; 88 struct epoll_event *e = state->events+j; 89 90 if (e->events & EPOLLIN) mask |= AE_READABLE; 91 if (e->events & EPOLLOUT) mask |= AE_WRITABLE; 92 eventLoop->fired[j].fd = e->data.fd; 93 eventLoop->fired[j].mask = mask; 94 } 95 } 96 return numevents; 97 } 98 99 static char *aeApiName(void) { 100 return "epoll"; 101 } 102