和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.