1 : /* Linux epoll(2) based ae.c module
2 : * Copyright (C) 2009-2010 Salvatore Sanfilippo - antirez@gmail.com
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 53 : aeApiState *state = zmalloc(sizeof(aeApiState));
14 :
15 53 : if (!state) return -1;
16 53 : state->events = zmalloc(sizeof(struct epoll_event)*eventLoop->setsize);
17 53 : if (!state->events) {
18 0 : zfree(state);
19 0 : return -1;
20 : }
21 53 : state->epfd = epoll_create(1024); /* 1024 is just an hint for the kernel */
22 53 : if (state->epfd == -1) {
23 0 : zfree(state->events);
24 0 : zfree(state);
25 0 : return -1;
26 : }
27 53 : eventLoop->apidata = state;
28 53 : return 0;
29 : }
30 :
31 : static void aeApiFree(aeEventLoop *eventLoop) {
32 0 : aeApiState *state = eventLoop->apidata;
33 :
34 0 : close(state->epfd);
35 0 : zfree(state->events);
36 0 : zfree(state);
37 : }
38 :
39 : static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask) {
40 1066296 : 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 1066296 : int op = eventLoop->events[fd].mask == AE_NONE ?
45 1066296 : EPOLL_CTL_ADD : EPOLL_CTL_MOD;
46 :
47 1066296 : ee.events = 0;
48 1066296 : mask |= eventLoop->events[fd].mask; /* Merge old events */
49 1066296 : if (mask & AE_READABLE) ee.events |= EPOLLIN;
50 1066296 : if (mask & AE_WRITABLE) ee.events |= EPOLLOUT;
51 1066296 : ee.data.u64 = 0; /* avoid valgrind warning */
52 1066296 : ee.data.fd = fd;
53 1066296 : if (epoll_ctl(state->epfd,op,fd,&ee) == -1) return -1;
54 1066296 : return 0;
55 : }
56 :
57 : static void aeApiDelEvent(aeEventLoop *eventLoop, int fd, int delmask) {
58 1066140 : aeApiState *state = eventLoop->apidata;
59 : struct epoll_event ee;
60 1066140 : int mask = eventLoop->events[fd].mask & (~delmask);
61 :
62 1066140 : ee.events = 0;
63 1066140 : if (mask & AE_READABLE) ee.events |= EPOLLIN;
64 1066140 : if (mask & AE_WRITABLE) ee.events |= EPOLLOUT;
65 1066140 : ee.data.u64 = 0; /* avoid valgrind warning */
66 1066140 : ee.data.fd = fd;
67 1066140 : if (mask != AE_NONE) {
68 1066026 : 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 114 : epoll_ctl(state->epfd,EPOLL_CTL_DEL,fd,&ee);
73 : }
74 : }
75 :
76 : static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) {
77 1769701 : aeApiState *state = eventLoop->apidata;
78 1769701 : int retval, numevents = 0;
79 :
80 3539402 : retval = epoll_wait(state->epfd,state->events,eventLoop->setsize,
81 1769701 : tvp ? (tvp->tv_sec*1000 + tvp->tv_usec/1000) : -1);
82 1769701 : if (retval > 0) {
83 : int j;
84 :
85 1766295 : numevents = retval;
86 3876120 : for (j = 0; j < numevents; j++) {
87 2109825 : int mask = 0;
88 2109825 : struct epoll_event *e = state->events+j;
89 :
90 2109825 : if (e->events & EPOLLIN) mask |= AE_READABLE;
91 2109825 : if (e->events & EPOLLOUT) mask |= AE_WRITABLE;
92 2109825 : eventLoop->fired[j].fd = e->data.fd;
93 2109825 : eventLoop->fired[j].mask = mask;
94 : }
95 : }
96 1769701 : return numevents;
97 : }
98 :
99 : static char *aeApiName(void) {
100 9168 : return "epoll";
101 : }
|