Back to home page

Redis cross reference

 
 

    


0001 /* Linux epoll(2) based ae.c module
0002  *
0003  * Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com>
0004  * All rights reserved.
0005  *
0006  * Redistribution and use in source and binary forms, with or without
0007  * modification, are permitted provided that the following conditions are met:
0008  *
0009  *   * Redistributions of source code must retain the above copyright notice,
0010  *     this list of conditions and the following disclaimer.
0011  *   * Redistributions in binary form must reproduce the above copyright
0012  *     notice, this list of conditions and the following disclaimer in the
0013  *     documentation and/or other materials provided with the distribution.
0014  *   * Neither the name of Redis nor the names of its contributors may be used
0015  *     to endorse or promote products derived from this software without
0016  *     specific prior written permission.
0017  *
0018  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0019  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0020  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0021  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0022  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0023  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0024  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0025  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0026  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0027  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0028  * POSSIBILITY OF SUCH DAMAGE.
0029  */
0030 
0031 
0032 #include <sys/epoll.h>
0033 
0034 typedef struct aeApiState {
0035     int epfd;
0036     struct epoll_event *events;
0037 } aeApiState;
0038 
0039 static int aeApiCreate(aeEventLoop *eventLoop) {
0040     aeApiState *state = zmalloc(sizeof(aeApiState));
0041 
0042     if (!state) return -1;
0043     state->events = zmalloc(sizeof(struct epoll_event)*eventLoop->setsize);
0044     if (!state->events) {
0045         zfree(state);
0046         return -1;
0047     }
0048     state->epfd = epoll_create(1024); /* 1024 is just an hint for the kernel */
0049     if (state->epfd == -1) {
0050         zfree(state->events);
0051         zfree(state);
0052         return -1;
0053     }
0054     eventLoop->apidata = state;
0055     return 0;
0056 }
0057 
0058 static void aeApiFree(aeEventLoop *eventLoop) {
0059     aeApiState *state = eventLoop->apidata;
0060 
0061     close(state->epfd);
0062     zfree(state->events);
0063     zfree(state);
0064 }
0065 
0066 static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask) {
0067     aeApiState *state = eventLoop->apidata;
0068     struct epoll_event ee;
0069     /* If the fd was already monitored for some event, we need a MOD
0070      * operation. Otherwise we need an ADD operation. */
0071     int op = eventLoop->events[fd].mask == AE_NONE ?
0072             EPOLL_CTL_ADD : EPOLL_CTL_MOD;
0073 
0074     ee.events = 0;
0075     mask |= eventLoop->events[fd].mask; /* Merge old events */
0076     if (mask & AE_READABLE) ee.events |= EPOLLIN;
0077     if (mask & AE_WRITABLE) ee.events |= EPOLLOUT;
0078     ee.data.u64 = 0; /* avoid valgrind warning */
0079     ee.data.fd = fd;
0080     if (epoll_ctl(state->epfd,op,fd,&ee) == -1) return -1;
0081     return 0;
0082 }
0083 
0084 static void aeApiDelEvent(aeEventLoop *eventLoop, int fd, int delmask) {
0085     aeApiState *state = eventLoop->apidata;
0086     struct epoll_event ee;
0087     int mask = eventLoop->events[fd].mask & (~delmask);
0088 
0089     ee.events = 0;
0090     if (mask & AE_READABLE) ee.events |= EPOLLIN;
0091     if (mask & AE_WRITABLE) ee.events |= EPOLLOUT;
0092     ee.data.u64 = 0; /* avoid valgrind warning */
0093     ee.data.fd = fd;
0094     if (mask != AE_NONE) {
0095         epoll_ctl(state->epfd,EPOLL_CTL_MOD,fd,&ee);
0096     } else {
0097         /* Note, Kernel < 2.6.9 requires a non null event pointer even for
0098          * EPOLL_CTL_DEL. */
0099         epoll_ctl(state->epfd,EPOLL_CTL_DEL,fd,&ee);
0100     }
0101 }
0102 
0103 static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) {
0104     aeApiState *state = eventLoop->apidata;
0105     int retval, numevents = 0;
0106 
0107     retval = epoll_wait(state->epfd,state->events,eventLoop->setsize,
0108             tvp ? (tvp->tv_sec*1000 + tvp->tv_usec/1000) : -1);
0109     if (retval > 0) {
0110         int j;
0111 
0112         numevents = retval;
0113         for (j = 0; j < numevents; j++) {
0114             int mask = 0;
0115             struct epoll_event *e = state->events+j;
0116 
0117             if (e->events & EPOLLIN) mask |= AE_READABLE;
0118             if (e->events & EPOLLOUT) mask |= AE_WRITABLE;
0119             if (e->events & EPOLLERR) mask |= AE_WRITABLE;
0120             if (e->events & EPOLLHUP) mask |= AE_WRITABLE;
0121             eventLoop->fired[j].fd = e->data.fd;
0122             eventLoop->fired[j].mask = mask;
0123         }
0124     }
0125     return numevents;
0126 }
0127 
0128 static char *aeApiName(void) {
0129     return "epoll";
0130 }