【redis源码】(六)Ae.c
和memcached不同的是,redis没有使用第三方的事件框架,而是自己封装了io处理机制。
有些细节上,redis并没有做到最优化,比如超时事件管理,redis仅仅使用了一个单链表,最新插入的超时事件放在链表头,作者在源码中也提到超时事件上的一些可以改进的地方【比如libevent超时事件采用最大堆实现】
“Note that's O(N) since time events are unsorted.
Possible optimizations (not needed by Redis so far, but...):
1) Insert the event in order, so that the nearest is just the head. Much better but still insertion or deletion of timers is O(N).
2) Use a skiplist to have this operation as O(1) and insertion as O(log(N)).”
另外一个小细节是,如果使用epoll做io复用模型的话,redis会使用水平触发作为工作方式。
哦了,贴代码,看了好久才想清楚~ 感觉表述越来越不清楚了,还是自己理解的不够透彻,再接再厉
Ae_select.c
1 /* Select()-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 <string.h> 6 7 //select底层底层封装,被ae.c使用,用来处理读写文件描述符的时间管理 8 typedef struct aeApiState { 9 //用来保存注册到select文件描述符 10 fd_set rfds, wfds; 11 /* We need to have a copy of the fd sets as it's not safe to reuse 12 * FD sets after select(). */ 13 //select操作时使用的fd_set文件 14 fd_set _rfds, _wfds; 15 } aeApiState; 16 17 //给上层zip调用的方法,用于初始化一个select事件管理 18 static int aeApiCreate(aeEventLoop *eventLoop) { 19 aeApiState *state = zmalloc(sizeof(aeApiState)); 20 21 if (!state) return -1; 22 //初始化aeApiState中的fd_set 23 FD_ZERO(&state->rfds); 24 FD_ZERO(&state->wfds); 25 eventLoop->apidata = state; 26 return 0; 27 } 28 29 //释放aeApiState内存 30 static void aeApiFree(aeEventLoop *eventLoop) { 31 zfree(eventLoop->apidata); 32 } 33 34 //向eventLoop添加指定mask的文件描述符 35 static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask) { 36 aeApiState *state = eventLoop->apidata; 37 38 //插入读事件文件描述符 39 if (mask & AE_READABLE) FD_SET(fd,&state->rfds); 40 //插入写事件文件描述符 41 if (mask & AE_WRITABLE) FD_SET(fd,&state->wfds); 42 return 0; 43 } 44 45 //从eventLoop中删除描述符fd的指定监听事件 46 static void aeApiDelEvent(aeEventLoop *eventLoop, int fd, int mask) { 47 aeApiState *state = eventLoop->apidata; 48 49 if (mask & AE_READABLE) FD_CLR(fd,&state->rfds); 50 if (mask & AE_WRITABLE) FD_CLR(fd,&state->wfds); 51 } 52 53 //执行事件监听,超时时间为tvp 54 static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) { 55 aeApiState *state = eventLoop->apidata; 56 int retval, j, numevents = 0; 57 58 //复制最新的state->rfds & state->wfds到_rfds,_wfds 59 memcpy(&state->_rfds,&state->rfds,sizeof(fd_set)); 60 memcpy(&state->_wfds,&state->wfds,sizeof(fd_set)); 61 62 //执行select,超时时间tvp 63 retval = select(eventLoop->maxfd+1, 64 &state->_rfds,&state->_wfds,NULL,tvp); 65 if (retval > 0) { 66 for (j = 0; j <= eventLoop->maxfd; j++) { 67 int mask = 0; 68 aeFileEvent *fe = &eventLoop->events[j]; 69 70 if (fe->mask == AE_NONE) continue; 71 if (fe->mask & AE_READABLE && FD_ISSET(j,&state->_rfds)) 72 mask |= AE_READABLE; 73 if (fe->mask & AE_WRITABLE && FD_ISSET(j,&state->_wfds)) 74 mask |= AE_WRITABLE; 75 //将可读或者可写的文件描述符状态更新到eventLoop结构体中 76 eventLoop->fired[numevents].fd = j; 77 eventLoop->fired[numevents].mask = mask; 78 numevents++; 79 } 80 } 81 //返回可读可写的文件描述符总数量 82 return numevents; 83 } 84 85 static char *aeApiName(void) { 86 return "select"; 87 }
Ae_epoll.c
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 8 typedef struct aeApiState { 9 int epfd; 10 struct epoll_event events[AE_SETSIZE]; 11 } aeApiState; 12 13 //初始化一个epoll时间管理结构体eventLoop 14 static int aeApiCreate(aeEventLoop *eventLoop) { 15 aeApiState *state = zmalloc(sizeof(aeApiState)); 16 17 if (!state) return -1; 18 //epoll_create(size)中的size参数不使用 19 //初始化epoll_fd 20 state->epfd = epoll_create(1024); /* 1024 is just an hint for the kernel */ 21 if (state->epfd == -1) return -1; 22 eventLoop->apidata = state; 23 return 0; 24 } 25 26 //释放aeApiState空间 27 static void aeApiFree(aeEventLoop *eventLoop) { 28 aeApiState *state = eventLoop->apidata; 29 30 close(state->epfd); 31 zfree(state); 32 } 33 34 //为eventLoop添加文件描述符与其相应的监听事件 35 static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask) { 36 aeApiState *state = eventLoop->apidata; 37 struct epoll_event ee; 38 /* If the fd was already monitored for some event, we need a MOD 39 * operation. Otherwise we need an ADD operation. */ 40 int op = eventLoop->events[fd].mask == AE_NONE ? 41 EPOLL_CTL_ADD : EPOLL_CTL_MOD; 42 43 ee.events = 0; 44 mask |= eventLoop->events[fd].mask; /* Merge old events */ 45 if (mask & AE_READABLE) ee.events |= EPOLLIN; 46 if (mask & AE_WRITABLE) ee.events |= EPOLLOUT; 47 ee.data.u64 = 0; /* avoid valgrind warning */ 48 ee.data.fd = fd; 49 if (epoll_ctl(state->epfd,op,fd,&ee) == -1) return -1; 50 return 0; 51 } 52 53 //从eventLoop中删除fd的delmask时间类型 54 static void aeApiDelEvent(aeEventLoop *eventLoop, int fd, int delmask) { 55 aeApiState *state = eventLoop->apidata; 56 struct epoll_event ee; 57 int mask = eventLoop->events[fd].mask & (~delmask); 58 59 ee.events = 0; 60 if (mask & AE_READABLE) ee.events |= EPOLLIN; 61 if (mask & AE_WRITABLE) ee.events |= EPOLLOUT; 62 ee.data.u64 = 0; /* avoid valgrind warning */ 63 ee.data.fd = fd; 64 if (mask != AE_NONE) { 65 epoll_ctl(state->epfd,EPOLL_CTL_MOD,fd,&ee); 66 } else { 67 /* Note, Kernel < 2.6.9 requires a non null event pointer even for 68 * EPOLL_CTL_DEL. */ 69 epoll_ctl(state->epfd,EPOLL_CTL_DEL,fd,&ee); 70 } 71 } 72 73 //poll操作,返回事件就绪的fd数量 74 static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) { 75 aeApiState *state = eventLoop->apidata; 76 int retval, numevents = 0; 77 78 retval = epoll_wait(state->epfd,state->events,AE_SETSIZE, 79 tvp ? (tvp->tv_sec*1000 + tvp->tv_usec/1000) : -1); 80 if (retval > 0) { 81 int j; 82 83 numevents = retval; 84 for (j = 0; j < numevents; j++) { 85 int mask = 0; 86 struct epoll_event *e = state->events+j; 87 88 if (e->events & EPOLLIN) mask |= AE_READABLE; 89 if (e->events & EPOLLOUT) mask |= AE_WRITABLE; 90 eventLoop->fired[j].fd = e->data.fd; 91 eventLoop->fired[j].mask = mask; 92 } 93 } 94 return numevents; 95 } 96 97 static char *aeApiName(void) { 98 return "epoll"; 99 }
Ae.h
1 #ifndef __AE_H__ 2 #define __AE_H__ 3 4 //支持的最大监听fd的数量 5 #define AE_SETSIZE (1024*10) /* Max number of fd supported */ 6 7 #define AE_OK 0 8 #define AE_ERR -1 9 10 #define AE_NONE 0 11 #define AE_READABLE 1 12 #define AE_WRITABLE 2 13 14 #define AE_FILE_EVENTS 1 15 #define AE_TIME_EVENTS 2 16 #define AE_ALL_EVENTS (AE_FILE_EVENTS|AE_TIME_EVENTS) 17 #define AE_DONT_WAIT 4 18 19 #define AE_NOMORE -1 20 21 /* Macros */ 22 #define AE_NOTUSED(V) ((void) V) 23 24 //声明aeEventLoop 25 struct aeEventLoop; 26 27 /* Types and data structures */ 28 29 typedef void aeFileProc(struct aeEventLoop *eventLoop, int fd, void *clientData, int mask); 30 typedef int aeTimeProc(struct aeEventLoop *eventLoop, long long id, void *clientData); 31 typedef void aeEventFinalizerProc(struct aeEventLoop *eventLoop, void *clientData); 32 typedef void aeBeforeSleepProc(struct aeEventLoop *eventLoop); 33 34 //描述符时间结构体,要么读,要么写 35 /* File event structure */ 36 typedef struct aeFileEvent { 37 int mask; /* one of AE_(READABLE|WRITABLE) */ 38 aeFileProc *rfileProc; 39 aeFileProc *wfileProc; 40 void *clientData; 41 } aeFileEvent; 42 43 //超时事件结构体 44 /* Time event structure */ 45 typedef struct aeTimeEvent { 46 long long id; /* time event identifier. */ 47 long when_sec; /* seconds */ 48 long when_ms; /* milliseconds */ 49 aeTimeProc *timeProc; 50 aeEventFinalizerProc *finalizerProc; 51 void *clientData; 52 struct aeTimeEvent *next; 53 } aeTimeEvent; 54 55 //已激活事件结构体 56 /* A fired event */ 57 typedef struct aeFiredEvent { 58 int fd; 59 int mask; 60 } aeFiredEvent; 61 62 /* State of an event based program */ 63 typedef struct aeEventLoop { 64 int maxfd; 65 long long timeEventNextId; 66 aeFileEvent events[AE_SETSIZE]; /* Registered events */ 67 aeFiredEvent fired[AE_SETSIZE]; /* Fired events */ 68 aeTimeEvent *timeEventHead; 69 int stop; 70 void *apidata; /* This is used for polling API specific data */ 71 aeBeforeSleepProc *beforesleep; 72 } aeEventLoop; 73 74 /* Prototypes */ 75 aeEventLoop *aeCreateEventLoop(void); 76 void aeDeleteEventLoop(aeEventLoop *eventLoop); 77 void aeStop(aeEventLoop *eventLoop); 78 int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask, 79 aeFileProc *proc, void *clientData); 80 void aeDeleteFileEvent(aeEventLoop *eventLoop, int fd, int mask); 81 long long aeCreateTimeEvent(aeEventLoop *eventLoop, long long milliseconds, 82 aeTimeProc *proc, void *clientData, 83 aeEventFinalizerProc *finalizerProc); 84 int aeDeleteTimeEvent(aeEventLoop *eventLoop, long long id); 85 int aeProcessEvents(aeEventLoop *eventLoop, int flags); 86 int aeWait(int fd, int mask, long long milliseconds); 87 void aeMain(aeEventLoop *eventLoop); 88 char *aeGetApiName(void); 89 void aeSetBeforeSleepProc(aeEventLoop *eventLoop, aeBeforeSleepProc *beforesleep); 90 91 #endif
Ae.c
1 #include <stdio.h> 2 #include <sys/time.h> 3 #include <sys/types.h> 4 #include <unistd.h> 5 #include <stdlib.h> 6 7 #include "ae.h" 8 #include "zmalloc.h" 9 #include "config.h" 10 11 /* Include the best multiplexing layer supported by this system. 12 * The following should be ordered by performances, descending. */ 13 //选择使用的底层事件管理API 14 #ifdef HAVE_EPOLL 15 #include "ae_epoll.c" 16 #else 17 #ifdef HAVE_KQUEUE 18 #include "ae_kqueue.c" 19 #else 20 #include "ae_select.c" 21 #endif 22 #endif 23 24 //初始化eventLoop结构体 25 aeEventLoop *aeCreateEventLoop(void) { 26 aeEventLoop *eventLoop; 27 int i; 28 //申请内存 29 eventLoop = zmalloc(sizeof(*eventLoop)); 30 if (!eventLoop) return NULL; 31 eventLoop->timeEventHead = NULL; 32 eventLoop->timeEventNextId = 0; 33 eventLoop->stop = 0; 34 eventLoop->maxfd = -1; 35 eventLoop->beforesleep = NULL; 36 //初始化底层事件管理结构体aeApiState,赋值给*apidata 37 if (aeApiCreate(eventLoop) == -1) { 38 zfree(eventLoop); 39 return NULL; 40 } 41 /* Events with mask == AE_NONE are not set. So let's initialize the 42 * vector with it. */ 43 //为描述符事件初始化监视事件类型 44 for (i = 0; i < AE_SETSIZE; i++) 45 eventLoop->events[i].mask = AE_NONE; 46 return eventLoop; 47 } 48 49 //释放aeEventLoop 50 void aeDeleteEventLoop(aeEventLoop *eventLoop) { 51 aeApiFree(eventLoop); 52 zfree(eventLoop); 53 } 54 55 void aeStop(aeEventLoop *eventLoop) { 56 eventLoop->stop = 1; 57 } 58 59 //添加一个fd及其处理函数 60 int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask, 61 aeFileProc *proc, void *clientData) 62 { 63 //文件描述符超过过了最大的值 64 if (fd >= AE_SETSIZE) return AE_ERR; 65 aeFileEvent *fe = &eventLoop->events[fd]; 66 67 if (aeApiAddEvent(eventLoop, fd, mask) == -1) 68 return AE_ERR; 69 fe->mask |= mask; 70 if (mask & AE_READABLE) fe->rfileProc = proc; 71 if (mask & AE_WRITABLE) fe->wfileProc = proc; 72 fe->clientData = clientData; 73 if (fd > eventLoop->maxfd) 74 eventLoop->maxfd = fd; 75 return AE_OK; 76 } 77 78 //从eventLoop中删除对fd的mask中知名的监听类型的删除 79 void aeDeleteFileEvent(aeEventLoop *eventLoop, int fd, int mask) 80 { 81 //文件描述符超过过了最大的值 82 if (fd >= AE_SETSIZE) return; 83 aeFileEvent *fe = &eventLoop->events[fd]; 84 85 //fd上并未绑定任何类型的时间 86 if (fe->mask == AE_NONE) return; 87 //对mask指定的bit置零 88 fe->mask = fe->mask & (~mask); 89 //如果去除的监听fd是最大的那个,并且此fd当前没有任何监听事件,则更新eventloop的maxfd字段 90 if (fd == eventLoop->maxfd && fe->mask == AE_NONE) { 91 /* Update the max fd */ 92 int j; 93 94 for (j = eventLoop->maxfd-1; j >= 0; j--) 95 if (eventLoop->events[j].mask != AE_NONE) break; 96 eventLoop->maxfd = j; 97 } 98 //在api中删除对此fd的mask类事件的监听 99 aeApiDelEvent(eventLoop, fd, mask); 100 } 101 102 //得到当前时间 103 static void aeGetTime(long *seconds, long *milliseconds) 104 { 105 struct timeval tv; 106 107 gettimeofday(&tv, NULL); 108 *seconds = tv.tv_sec; 109 *milliseconds = tv.tv_usec/1000; 110 } 111 112 //得到millissconds后的时间 113 static void aeAddMillisecondsToNow(long long milliseconds, long *sec, long *ms) { 114 long cur_sec, cur_ms, when_sec, when_ms; 115 116 aeGetTime(&cur_sec, &cur_ms); 117 when_sec = cur_sec + milliseconds/1000; 118 when_ms = cur_ms + milliseconds%1000; 119 if (when_ms >= 1000) { 120 when_sec ++; 121 when_ms -= 1000; 122 } 123 *sec = when_sec; 124 *ms = when_ms; 125 } 126 127 //注册一个超时事件 128 long long aeCreateTimeEvent(aeEventLoop *eventLoop, long long milliseconds, 129 aeTimeProc *proc, void *clientData, 130 aeEventFinalizerProc *finalizerProc) 131 { 132 //得到新的超时事件的id 133 long long id = eventLoop->timeEventNextId++; 134 aeTimeEvent *te; 135 136 te = zmalloc(sizeof(*te)); 137 if (te == NULL) return AE_ERR; 138 te->id = id; 139 aeAddMillisecondsToNow(milliseconds,&te->when_sec,&te->when_ms); 140 te->timeProc = proc; 141 te->finalizerProc = finalizerProc; 142 te->clientData = clientData; 143 //将新的超时事件数据插到单链表的头部 144 te->next = eventLoop->timeEventHead; 145 eventLoop->timeEventHead = te; 146 return id; 147 } 148 149 //删除id为id的超时事件,单链表操作 150 int aeDeleteTimeEvent(aeEventLoop *eventLoop, long long id) 151 { 152 aeTimeEvent *te, *prev = NULL; 153 154 te = eventLoop->timeEventHead; 155 while(te) { 156 if (te->id == id) { 157 if (prev == NULL) 158 eventLoop->timeEventHead = te->next; 159 else 160 prev->next = te->next; 161 if (te->finalizerProc) 162 te->finalizerProc(eventLoop, te->clientData); 163 zfree(te); 164 return AE_OK; 165 } 166 prev = te; 167 te = te->next; 168 } 169 return AE_ERR; /* NO event with the specified ID found */ 170 } 171 172 /* Search the first timer to fire. 173 * This operation is useful to know how many time the select can be 174 * put in sleep without to delay any event. 175 * If there are no timers NULL is returned. 176 * 177 * Note that's O(N) since time events are unsorted. 178 * Possible optimizations (not needed by Redis so far, but...): 179 * 1) Insert the event in order, so that the nearest is just the head. 180 * Much better but still insertion or deletion of timers is O(N). 181 * 最大堆呀最大堆,libevent 182 * 2) Use a skiplist to have this operation as O(1) and insertion as O(log(N)). 183 */ 184 static aeTimeEvent *aeSearchNearestTimer(aeEventLoop *eventLoop) 185 { 186 aeTimeEvent *te = eventLoop->timeEventHead; 187 aeTimeEvent *nearest = NULL; 188 189 while(te) { 190 if (!nearest || te->when_sec < nearest->when_sec || 191 (te->when_sec == nearest->when_sec && 192 te->when_ms < nearest->when_ms)) 193 nearest = te; 194 te = te->next; 195 } 196 return nearest; 197 } 198 199 //遍历超时事件链表,把时间到了的一个一个处理 200 /* Process time events */ 201 static int processTimeEvents(aeEventLoop *eventLoop) { 202 int processed = 0; 203 aeTimeEvent *te; 204 long long maxId; 205 206 te = eventLoop->timeEventHead; 207 maxId = eventLoop->timeEventNextId-1; 208 while(te) { 209 long now_sec, now_ms; 210 long long id; 211 212 if (te->id > maxId) { 213 te = te->next; 214 continue; 215 } 216 aeGetTime(&now_sec, &now_ms); 217 if (now_sec > te->when_sec || 218 (now_sec == te->when_sec && now_ms >= te->when_ms)) 219 { 220 int retval; 221 222 id = te->id; 223 retval = te->timeProc(eventLoop, id, te->clientData); 224 processed++; 225 /* After an event is processed our time event list may 226 * no longer be the same, so we restart from head. 227 * Still we make sure to don't process events registered 228 * by event handlers itself in order to don't loop forever. 229 * To do so we saved the max ID we want to handle. 230 * 231 * FUTURE OPTIMIZATIONS: 232 * Note that this is NOT great algorithmically. Redis uses 233 * a single time event so it's not a problem but the right 234 * way to do this is to add the new elements on head, and 235 * to flag deleted elements in a special way for later 236 * deletion (putting references to the nodes to delete into 237 * another linked list). */ 238 if (retval != AE_NOMORE) { 239 aeAddMillisecondsToNow(retval,&te->when_sec,&te->when_ms); 240 } else { 241 aeDeleteTimeEvent(eventLoop, id); 242 } 243 te = eventLoop->timeEventHead; 244 } else { 245 te = te->next; 246 } 247 } 248 return processed; 249 } 250 251 252 //处理可处理的所有事件,包括文件事件和超时事件 253 /* Process every pending time event, then every pending file event 254 * (that may be registered by time event callbacks just processed). 255 * Without special flags the function sleeps until some file event 256 * fires, or when the next time event occurrs (if any). 257 * 258 * If flags is 0, the function does nothing and returns. 259 * if flags has AE_ALL_EVENTS set, all the kind of events are processed. 260 * if flags has AE_FILE_EVENTS set, file events are processed. 261 * if flags has AE_TIME_EVENTS set, time events are processed. 262 * if flags has AE_DONT_WAIT set the function returns ASAP until all 263 * the events that's possible to process without to wait are processed. 264 * 265 * The function returns the number of events processed. */ 266 int aeProcessEvents(aeEventLoop *eventLoop, int flags) 267 { 268 int processed = 0, numevents; 269 270 /* Nothing to do? return ASAP */ 271 if (!(flags & AE_TIME_EVENTS) && !(flags & AE_FILE_EVENTS)) return 0; 272 273 /* Note that we want call select() even if there are no 274 * file events to process as long as we want to process time 275 * events, in order to sleep until the next time event is ready 276 * to fire. */ 277 if (eventLoop->maxfd != -1 || 278 ((flags & AE_TIME_EVENTS) && !(flags & AE_DONT_WAIT))) { 279 int j; 280 aeTimeEvent *shortest = NULL; 281 struct timeval tv, *tvp; 282 283 if (flags & AE_TIME_EVENTS && !(flags & AE_DONT_WAIT)) 284 shortest = aeSearchNearestTimer(eventLoop); 285 if (shortest) { 286 long now_sec, now_ms; 287 288 /* Calculate the time missing for the nearest 289 * timer to fire. */ 290 aeGetTime(&now_sec, &now_ms); 291 tvp = &tv; 292 tvp->tv_sec = shortest->when_sec - now_sec; 293 if (shortest->when_ms < now_ms) { 294 tvp->tv_usec = ((shortest->when_ms+1000) - now_ms)*1000; 295 tvp->tv_sec --; 296 } else { 297 tvp->tv_usec = (shortest->when_ms - now_ms)*1000; 298 } 299 if (tvp->tv_sec < 0) tvp->tv_sec = 0; 300 if (tvp->tv_usec < 0) tvp->tv_usec = 0; 301 } else { 302 /* If we have to check for events but need to return 303 * ASAP because of AE_DONT_WAIT we need to se the timeout 304 * to zero */ 305 if (flags & AE_DONT_WAIT) { 306 tv.tv_sec = tv.tv_usec = 0; 307 tvp = &tv; 308 } else { 309 /* Otherwise we can block */ 310 tvp = NULL; /* wait forever */ 311 } 312 } 313 314 numevents = aeApiPoll(eventLoop, tvp); 315 for (j = 0; j < numevents; j++) { 316 aeFileEvent *fe = &eventLoop->events[eventLoop->fired[j].fd]; 317 int mask = eventLoop->fired[j].mask; 318 int fd = eventLoop->fired[j].fd; 319 int rfired = 0; 320 321 /* note the fe->mask & mask & ... code: maybe an already processed 322 * event removed an element that fired and we still didn't 323 * processed, so we check if the event is still valid. */ 324 if (fe->mask & mask & AE_READABLE) { 325 rfired = 1; 326 fe->rfileProc(eventLoop,fd,fe->clientData,mask); 327 } 328 if (fe->mask & mask & AE_WRITABLE) { 329 if (!rfired || fe->wfileProc != fe->rfileProc) 330 fe->wfileProc(eventLoop,fd,fe->clientData,mask); 331 } 332 processed++; 333 } 334 } 335 /* Check time events */ 336 if (flags & AE_TIME_EVENTS) 337 processed += processTimeEvents(eventLoop); 338 339 return processed; /* return the number of processed file/time events */ 340 } 341 342 343 //使用select模型,等待millseconds,返回0,表示超时,返回1,表明fd可读,返回2,表明fd可写 344 /* Wait for millseconds until the given file descriptor becomes 345 * writable/readable/exception */ 346 int aeWait(int fd, int mask, long long milliseconds) { 347 struct timeval tv; 348 fd_set rfds, wfds, efds; 349 int retmask = 0, retval; 350 351 tv.tv_sec = milliseconds/1000; 352 tv.tv_usec = (milliseconds%1000)*1000; 353 FD_ZERO(&rfds); 354 FD_ZERO(&wfds); 355 FD_ZERO(&efds); 356 357 if (mask & AE_READABLE) FD_SET(fd,&rfds); 358 if (mask & AE_WRITABLE) FD_SET(fd,&wfds); 359 if ((retval = select(fd+1, &rfds, &wfds, &efds, &tv)) > 0) { 360 if (FD_ISSET(fd,&rfds)) retmask |= AE_READABLE; 361 if (FD_ISSET(fd,&wfds)) retmask |= AE_WRITABLE; 362 return retmask; 363 } else { 364 return retval; 365 } 366 } 367 368 void aeMain(aeEventLoop *eventLoop) { 369 eventLoop->stop = 0; 370 while (!eventLoop->stop) { 371 if (eventLoop->beforesleep != NULL) 372 eventLoop->beforesleep(eventLoop); 373 aeProcessEvents(eventLoop, AE_ALL_EVENTS); 374 } 375 } 376 377 char *aeGetApiName(void) { 378 return aeApiName(); 379 } 380 381 void aeSetBeforeSleepProc(aeEventLoop *eventLoop, aeBeforeSleepProc *beforesleep) { 382 eventLoop->beforesleep = beforesleep; 383 }
喜欢一起简单,实用的东西,拒绝复杂花哨,我不是GEEK.