1 | /* Linux epoll(2) based ae.c module |
2 | * |
3 | * Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com> |
4 | * All rights reserved. |
5 | * |
6 | * Redistribution and use in source and binary forms, with or without |
7 | * modification, are permitted provided that the following conditions are met: |
8 | * |
9 | * * Redistributions of source code must retain the above copyright notice, |
10 | * this list of conditions and the following disclaimer. |
11 | * * Redistributions in binary form must reproduce the above copyright |
12 | * notice, this list of conditions and the following disclaimer in the |
13 | * documentation and/or other materials provided with the distribution. |
14 | * * Neither the name of Redis nor the names of its contributors may be used |
15 | * to endorse or promote products derived from this software without |
16 | * specific prior written permission. |
17 | * |
18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
28 | * POSSIBILITY OF SUCH DAMAGE. |
29 | */ |
30 | |
31 | |
32 | #include <sys/epoll.h> |
33 | |
34 | typedef struct aeApiState { |
35 | int epfd; |
36 | struct epoll_event *events; |
37 | } aeApiState; |
38 | |
39 | static int aeApiCreate(aeEventLoop *eventLoop) { |
40 | aeApiState *state = zmalloc(sizeof(aeApiState)); |
41 | |
42 | if (!state) return -1; |
43 | state->events = zmalloc(sizeof(struct epoll_event)*eventLoop->setsize); |
44 | if (!state->events) { |
45 | zfree(state); |
46 | return -1; |
47 | } |
48 | state->epfd = epoll_create(1024); /* 1024 is just a hint for the kernel */ |
49 | if (state->epfd == -1) { |
50 | zfree(state->events); |
51 | zfree(state); |
52 | return -1; |
53 | } |
54 | anetCloexec(state->epfd); |
55 | eventLoop->apidata = state; |
56 | return 0; |
57 | } |
58 | |
59 | static int aeApiResize(aeEventLoop *eventLoop, int setsize) { |
60 | aeApiState *state = eventLoop->apidata; |
61 | |
62 | state->events = zrealloc(state->events, sizeof(struct epoll_event)*setsize); |
63 | return 0; |
64 | } |
65 | |
66 | static void aeApiFree(aeEventLoop *eventLoop) { |
67 | aeApiState *state = eventLoop->apidata; |
68 | |
69 | close(state->epfd); |
70 | zfree(state->events); |
71 | zfree(state); |
72 | } |
73 | |
74 | static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask) { |
75 | aeApiState *state = eventLoop->apidata; |
76 | struct epoll_event ee = {0}; /* avoid valgrind warning */ |
77 | /* If the fd was already monitored for some event, we need a MOD |
78 | * operation. Otherwise we need an ADD operation. */ |
79 | int op = eventLoop->events[fd].mask == AE_NONE ? |
80 | EPOLL_CTL_ADD : EPOLL_CTL_MOD; |
81 | |
82 | ee.events = 0; |
83 | mask |= eventLoop->events[fd].mask; /* Merge old events */ |
84 | if (mask & AE_READABLE) ee.events |= EPOLLIN; |
85 | if (mask & AE_WRITABLE) ee.events |= EPOLLOUT; |
86 | ee.data.fd = fd; |
87 | if (epoll_ctl(state->epfd,op,fd,&ee) == -1) return -1; |
88 | return 0; |
89 | } |
90 | |
91 | static void aeApiDelEvent(aeEventLoop *eventLoop, int fd, int delmask) { |
92 | aeApiState *state = eventLoop->apidata; |
93 | struct epoll_event ee = {0}; /* avoid valgrind warning */ |
94 | int mask = eventLoop->events[fd].mask & (~delmask); |
95 | |
96 | ee.events = 0; |
97 | if (mask & AE_READABLE) ee.events |= EPOLLIN; |
98 | if (mask & AE_WRITABLE) ee.events |= EPOLLOUT; |
99 | ee.data.fd = fd; |
100 | if (mask != AE_NONE) { |
101 | epoll_ctl(state->epfd,EPOLL_CTL_MOD,fd,&ee); |
102 | } else { |
103 | /* Note, Kernel < 2.6.9 requires a non null event pointer even for |
104 | * EPOLL_CTL_DEL. */ |
105 | epoll_ctl(state->epfd,EPOLL_CTL_DEL,fd,&ee); |
106 | } |
107 | } |
108 | |
109 | static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) { |
110 | aeApiState *state = eventLoop->apidata; |
111 | int retval, numevents = 0; |
112 | |
113 | retval = epoll_wait(state->epfd,state->events,eventLoop->setsize, |
114 | tvp ? (tvp->tv_sec*1000 + (tvp->tv_usec + 999)/1000) : -1); |
115 | if (retval > 0) { |
116 | int j; |
117 | |
118 | numevents = retval; |
119 | for (j = 0; j < numevents; j++) { |
120 | int mask = 0; |
121 | struct epoll_event *e = state->events+j; |
122 | |
123 | if (e->events & EPOLLIN) mask |= AE_READABLE; |
124 | if (e->events & EPOLLOUT) mask |= AE_WRITABLE; |
125 | if (e->events & EPOLLERR) mask |= AE_WRITABLE|AE_READABLE; |
126 | if (e->events & EPOLLHUP) mask |= AE_WRITABLE|AE_READABLE; |
127 | eventLoop->fired[j].fd = e->data.fd; |
128 | eventLoop->fired[j].mask = mask; |
129 | } |
130 | } else if (retval == -1 && errno != EINTR) { |
131 | panic("aeApiPoll: epoll_wait, %s" , strerror(errno)); |
132 | } |
133 | |
134 | return numevents; |
135 | } |
136 | |
137 | static char *aeApiName(void) { |
138 | return "epoll" ; |
139 | } |
140 | |