xref: /redis-3.2.3/src/ae_epoll.c (revision 80586cb8)
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