1. redis事件的定义
maxfd;
setsize;
*events; *fired; */*定时器事件链表的首部*/ *apidata;
*
1.1 事件定义
/* File event structure */typedef struct aeFileEvent { int mask; /* one of AE_(READABLE|WRITABLE) */ aeFileProc *rfileProc; aeFileProc *wfileProc; void *clientData;} aeFileEvent;
/* Time event structure */typedef struct aeTimeEvent { long long id; /* time event identifier. */ long when_sec; /* seconds */ long when_ms; /* milliseconds */ aeTimeProc *timeProc; aeEventFinalizerProc *finalizerProc; void *clientData; struct aeTimeEvent *next;} aeTimeEvent;
/* A fired event */typedef struct aeFiredEvent { int fd; int mask;} aeFiredEvent;
2.封装事件处理的实现
3.事件处理的主函数
aeMain(aeEventLoop *->stop = (!eventLoop-> (eventLoop->beforesleep !=->
3.1事件处理过程
aeProcessEvents(aeEventLoop *eventLoop, processed =
</span><span style="color: #008000;">/*</span><span style="color: #008000;"> Nothing to do? return ASAP </span><span style="color: #008000;">*/</span>
<span style="color: #0000ff;">if</span> (!(flags & AE_TIME_EVENTS) && !(flags & AE_FILE_EVENTS)) <span style="color: #0000ff;">return</span> <span style="color: #800080;">0</span><span style="color: #000000;">;
</span><span style="color: #008000;">/*</span><span style="color: #008000;"> Note that we want call select() even if there are no
* file events to process as long as we want to process time
* events,in order to sleep until the next time event is ready
* to fire. </span><span style="color: #008000;">*/</span>
<span style="color: #0000ff;">if</span> (eventLoop->maxfd != -<span style="color: #800080;">1</span> ||<span style="color: #000000;">
((flags </span>& AE_TIME_EVENTS) && !(flags &<span style="color: #000000;"> AE_DONT_WAIT))) {
</span><span style="color: #0000ff;">int</span><span style="color: #000000;"> j;
aeTimeEvent </span>*shortest =<span style="color: #000000;"> NULL;
</span><span style="color: #0000ff;">struct</span> timeval tv,*<span style="color: #000000;">tvp;
</span><span style="color: #0000ff;">if</span> (flags & AE_TIME_EVENTS && !(flags &<span style="color: #000000;"> AE_DONT_WAIT))
shortest </span>=<span style="color: #000000;"> aeSearchNearestTimer(eventLoop);
</span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (shortest) {
</span><span style="color: #0000ff;">long</span><span style="color: #000000;"> now_sec,now_ms;
</span><span style="color: #008000;">/*</span><span style="color: #008000;"> Calculate the time missing for the nearest
* timer to fire. </span><span style="color: #008000;">*/</span><span style="color: #000000;">
aeGetTime(</span>&now_sec,&<span style="color: #000000;">now_ms);
tvp </span>= &<span style="color: #000000;">tv;
tvp</span>->tv_sec = shortest->when_sec -<span style="color: #000000;"> now_sec;
</span><span style="color: #0000ff;">if</span> (shortest->when_ms <<span style="color: #000000;"> now_ms) {
tvp</span>->tv_usec = ((shortest->when_ms+<span style="color: #800080;">1000</span>) - now_ms)*<span style="color: #800080;">1000</span><span style="color: #000000;">;
tvp</span>->tv_sec --<span style="color: #000000;">;
} </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> {
tvp</span>->tv_usec = (shortest->when_ms - now_ms)*<span style="color: #800080;">1000</span><span style="color: #000000;">;
}
</span><span style="color: #0000ff;">if</span> (tvp->tv_sec < <span style="color: #800080;">0</span>) tvp->tv_sec = <span style="color: #800080;">0</span><span style="color: #000000;">;
</span><span style="color: #0000ff;">if</span> (tvp->tv_usec < <span style="color: #800080;">0</span>) tvp->tv_usec = <span style="color: #800080;">0</span><span style="color: #000000;">;
} </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> {
</span><span style="color: #008000;">/*</span><span style="color: #008000;"> If we have to check for events but need to return
* ASAP because of AE_DONT_WAIT we need to set the timeout
* to zero </span><span style="color: #008000;">*/</span>
<span style="color: #0000ff;">if</span> (flags &<span style="color: #000000;"> AE_DONT_WAIT) {
tv.tv_sec </span>= tv.tv_usec = <span style="color: #800080;">0</span><span style="color: #000000;">;
tvp </span>= &<span style="color: #000000;">tv;
} </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> {
</span><span style="color: #008000;">/*</span><span style="color: #008000;"> Otherwise we can block </span><span style="color: #008000;">*/</span><span style="color: #000000;">
tvp </span>= NULL; <span style="color: #008000;">/*</span><span style="color: #008000;"> wait forever </span><span style="color: #008000;">*/</span><span style="color: #000000;">
}
}
numevents </span>=<span style="color: #000000;"> aeApiPoll(eventLoop,tvp);
</span><span style="color: #0000ff;">for</span> (j = <span style="color: #800080;">0</span>; j < numevents; j++<span style="color: #000000;">) {
aeFileEvent </span>*fe = &eventLoop->events[eventLoop-><span style="color: #000000;">fired[j].fd];
</span><span style="color: #0000ff;">int</span> mask = eventLoop-><span style="color: #000000;">fired[j].mask;
</span><span style="color: #0000ff;">int</span> fd = eventLoop-><span style="color: #000000;">fired[j].fd;
</span><span style="color: #0000ff;">int</span> rfired = <span style="color: #800080;">0</span><span style="color: #000000;">;
</span><span style="color: #008000;">/*</span><span style="color: #008000;"> note the fe->mask & mask & ... code: maybe an already processed
* event removed an element that fired and we still didn't
* processed,so we check if the event is still valid. </span><span style="color: #008000;">*/</span>
<span style="color: #0000ff;">if</span> (fe->mask & mask &<span style="color: #000000;"> AE_READABLE) {
rfired </span>= <span style="color: #800080;">1</span><span style="color: #000000;">;
fe</span>->rfileProc(eventLoop,fd,fe-><span style="color: #000000;">clientData,mask);
}
</span><span style="color: #0000ff;">if</span> (fe->mask & mask &<span style="color: #000000;"> AE_WRITABLE) {
</span><span style="color: #0000ff;">if</span> (!rfired || fe->wfileProc != fe-><span style="color: #000000;">rfileProc)
fe</span>->wfileProc(eventLoop,mask);
}
processed</span>++<span style="color: #000000;">;
}
}
</span><span style="color: #008000;">/*</span><span style="color: #008000;"> Check time events </span><span style="color: #008000;">*/</span>
<span style="color: #0000ff;">if</span> (flags &<span style="color: #000000;"> AE_TIME_EVENTS)
processed </span>+=<span style="color: #000000;"> processTimeEvents(eventLoop);
</span><span style="color: #0000ff;">return</span> processed; <span style="color: #008000;">/*</span><span style="color: #008000;"> return the number of processed file/time events </span><span style="color: #008000;">*/</span><span style="color: #000000;">
}
processTimeEvents(aeEventLoop * processed = * =
</span><span style="color: #008000;">/*</span><span style="color: #008000;"> If the system clock is moved to the future,and then set back to the
* right value,time events may be delayed in a random way. Often this
* means that scheduled operations will not be performed soon enough.
*
* Here we try to detect system clock skews,and force all the time
* events to be processed ASAP when this happens: the idea is that
* processing events earlier is less dangerous than delaying them
* indefinitely,and practice suggests it is. </span><span style="color: #008000;">*/</span>
<span style="color: #0000ff;">if</span> (now < eventLoop-><span style="color: #000000;">lastTime) {
te </span>= eventLoop-><span style="color: #000000;">timeEventHead;
</span><span style="color: #0000ff;">while</span><span style="color: #000000;">(te) {
te</span>->when_sec = <span style="color: #800080;">0</span><span style="color: #000000;">;
te </span>= te-><span style="color: #000000;">next;
}
}
eventLoop</span>->lastTime =<span style="color: #000000;"> now;
te </span>= eventLoop-><span style="color: #000000;">timeEventHead;
maxId </span>= eventLoop->timeEventNextId-<span style="color: #800080;">1</span><span style="color: #000000;">;
</span><span style="color: #0000ff;">while</span><span style="color: #000000;">(te) {
</span><span style="color: #0000ff;">long</span><span style="color: #000000;"> now_sec,now_ms;
</span><span style="color: #0000ff;">long</span> <span style="color: #0000ff;">long</span><span style="color: #000000;"> id;
</span><span style="color: #0000ff;">if</span> (te->id ><span style="color: #000000;"> maxId) {
te </span>= te-><span style="color: #000000;">next;
</span><span style="color: #0000ff;">continue</span><span style="color: #000000;">;
}
aeGetTime(</span>&now_sec,&<span style="color: #000000;">now_ms);
</span><span style="color: #0000ff;">if</span> (now_sec > te->when_sec ||<span style="color: #000000;">
(now_sec </span>== te->when_sec && now_ms >= te-><span style="color: #000000;">when_ms))
{
</span><span style="color: #0000ff;">int</span><span style="color: #000000;"> retval;
id </span>= te-><span style="color: #000000;">id;
retval </span>= te->timeProc(eventLoop,id,te-><span style="color: #000000;">clientData);
processed</span>++<span style="color: #000000;">;
</span><span style="color: #008000;">/*</span><span style="color: #008000;"> After an event is processed our time event list may
* no longer be the same,so we restart from head.
* Still we make sure to don't process events registered
* by event handlers itself in order to don't loop forever.
* To do so we saved the max ID we want to handle.
*
* FUTURE OPTIMIZATIONS:
* Note that this is NOT great algorithmically. Redis uses
* a single time event so it's not a problem but the right
* way to do this is to add the new elements on head,and
* to flag deleted elements in a special way for later
* deletion (putting references to the nodes to delete into
* another linked list). </span><span style="color: #008000;">*/</span>
<span style="color: #0000ff;">if</span> (retval !=<span style="color: #000000;"> AE_NOMORE) {
aeAddMillisecondsToNow(retval,</span>&te->when_sec,&te-><span style="color: #000000;">when_ms);
} </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> {
aeDeleteTimeEvent(eventLoop,id);
}
te </span>= eventLoop-><span style="color: #000000;">timeEventHead;
} </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> {
te </span>= te-><span style="color: #000000;">next;
}
}
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> processed;
}