int aeProcessEvents(aeEventLoop *eventLoop, int flags) { int processed = 0, numevents; if (!(flags & AE_TIME_EVENTS) && !(flags & AE_FILE_EVENTS)) return 0; if (eventLoop->maxfd != -1 || ((flags & AE_TIME_EVENTS) && !(flags & AE_DONT_WAIT))) { int j; aeTimeEvent *shortest = NULL; struct timeval tv, *tvp; if (flags & AE_TIME_EVENTS && !(flags & AE_DONT_WAIT)) shortest = aeSearchNearestTimer(eventLoop); if (shortest) { long now_sec, now_ms; aeGetTime(&now_sec, &now_ms); tvp = &tv; tvp->tv_sec = shortest->when_sec - now_sec; if (shortest->when_ms < now_ms) { tvp->tv_usec = ((shortest->when_ms+1000) - now_ms)*1000; tvp->tv_sec --; } else { tvp->tv_usec = (shortest->when_ms - now_ms)*1000; } if (tvp->tv_sec < 0) tvp->tv_sec = 0; if (tvp->tv_usec < 0) tvp->tv_usec = 0; } else { if (flags & AE_DONT_WAIT) { tv.tv_sec = tv.tv_usec = 0; tvp = &tv; } else { tvp = NULL; } } numevents = aeApiPoll(eventLoop, tvp); for (j = 0; j < numevents; j++) { aeFileEvent *fe = &eventLoop->events[eventLoop->fired[j].fd]; int mask = eventLoop->fired[j].mask; int fd = eventLoop->fired[j].fd; int rfired = 0; if (fe->mask & mask & AE_READABLE) { rfired = 1; fe->rfileProc(eventLoop,fd,fe->clientData,mask); } if (fe->mask & mask & AE_WRITABLE) { if (!rfired || fe->wfileProc != fe->rfileProc) fe->wfileProc(eventLoop,fd,fe->clientData,mask); } processed++; } } if (flags & AE_TIME_EVENTS) processed += processTimeEvents(eventLoop); return processed; }
/* Process time events */ static int processTimeEvents(aeEventLoop *eventLoop) { int processed = 0; aeTimeEvent *te; long long maxId; te = eventLoop->timeEventHead; maxId = eventLoop->timeEventNextId - 1; while (te) { long now_sec, now_ms; long long id; if (te->id > maxId) { te = te->next; continue; } aeGetTime(&now_sec, &now_ms); if (now_sec > te->when_sec || (now_sec == te->when_sec && now_ms >= te->when_ms)) { int retval; id = te->id; retval = te->timeProc(eventLoop, id, te->clientData); processed++; /* 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). */ if (retval != AE_NOMORE) { aeAddMillisecondsToNow(retval, &te->when_sec, &te->when_ms); } else { aeDeleteTimeEvent(eventLoop, id); } te = eventLoop->timeEventHead; } else { te = te->next; } } return processed; }
/* Process time events */ static int processTimeEvents(aeEventLoop *eventLoop) { int processed = 0; aeTimeEvent *te; time_t now = time(NULL); struct rb_node *node; /* 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. */ if (now < eventLoop->lastTime) { for (node = rb_first(eventLoop->timeEventRbtreeRoot); node; node = rb_next(node)) { rb_entry(node, struct aeTimeEvent, rb_node)->when_sec = 0; rb_entry(node, struct aeTimeEvent, rb_node)->when_ms = 0; } } eventLoop->lastTime = now; for(;;) { long now_sec, now_ms; node = rb_first(eventLoop->timeEventRbtreeRoot); if (!node) { break; } te = container_of(node, struct aeTimeEvent, rb_node); aeGetTime(&now_sec, &now_ms); if (now_sec > te->when_sec || (now_sec == te->when_sec && now_ms >= te->when_ms)) { int retval; retval = te->timeProc(eventLoop, te->id, te->clientData); rb_erase(node, eventLoop->timeEventRbtreeRoot); if (retval != AE_NOMORE) { aeAddMillisecondsToNow(retval,&te->when_sec,&te->when_ms); aeInsertTimeEvent(eventLoop->timeEventRbtreeRoot, te); } else { freeTimeEvent(eventLoop, te); } } else { break; } } return processed; }
static void aeAddMillisecondsToNow(long long milliseconds, long *sec, long *ms) { long cur_sec, cur_ms, when_sec, when_ms; aeGetTime(&cur_sec, &cur_ms); when_sec = cur_sec + milliseconds/1000; when_ms = cur_ms + milliseconds%1000; if (when_ms >= 1000) { when_sec ++; when_ms -= 1000; } *sec = when_sec; *ms = when_ms; }
static void aeAddMillisecondsToNow(PORT_LONGLONG milliseconds, PORT_LONG *sec, PORT_LONG *ms) { PORT_LONG cur_sec, cur_ms, when_sec, when_ms; aeGetTime(&cur_sec, &cur_ms); when_sec = (PORT_LONG) (cur_sec + milliseconds/1000); when_ms = cur_ms + milliseconds%1000; if (when_ms >= 1000) { when_sec ++; when_ms -= 1000; } *sec = when_sec; *ms = when_ms; }
/* Process every pending time event, then every pending file event * (that may be registered by time event callbacks just processed). * Without special flags the function sleeps until some file event * fires, or when the next time event occurs (if any). * * If flags is 0, the function does nothing and returns. * if flags has AE_ALL_EVENTS set, all the kind of events are processed. * if flags has AE_FILE_EVENTS set, file events are processed. * if flags has AE_TIME_EVENTS set, time events are processed. * if flags has AE_DONT_WAIT set the function returns ASAP until all * the events that's possible to process without to wait are processed. * * The function returns the number of events processed. */ int aeProcessEvents(aeEventLoop *eventLoop, int flags) { int processed = 0, numevents; #ifdef _WIN32 if (ServiceStopIssued() == TRUE) { aeStop(eventLoop); } #endif /* Nothing to do? return ASAP */ if (!(flags & AE_TIME_EVENTS) && !(flags & AE_FILE_EVENTS)) return 0; /* 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. */ if (eventLoop->maxfd != -1 || ((flags & AE_TIME_EVENTS) && !(flags & AE_DONT_WAIT))) { int j; aeTimeEvent *shortest = NULL; struct timeval tv, *tvp; if (flags & AE_TIME_EVENTS && !(flags & AE_DONT_WAIT)) shortest = aeSearchNearestTimer(eventLoop); if (shortest) { PORT_LONG now_sec, now_ms; /* Calculate the time missing for the nearest * timer to fire. */ aeGetTime(&now_sec, &now_ms); tvp = &tv; tvp->tv_sec = (int)(shortest->when_sec - now_sec); WIN_PORT_FIX /* cast (int) */ if (shortest->when_ms < now_ms) { tvp->tv_usec = (int)((shortest->when_ms+1000) - now_ms)*1000; WIN_PORT_FIX /* cast (int) */ tvp->tv_sec --; } else { tvp->tv_usec = (int)(shortest->when_ms - now_ms)*1000; WIN_PORT_FIX /* cast (int) */ } if (tvp->tv_sec < 0) tvp->tv_sec = 0; if (tvp->tv_usec < 0) tvp->tv_usec = 0; } else { /* 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 */ if (flags & AE_DONT_WAIT) {
/* * 为当前时间加上 milliseconds 秒。 */ static void aeAddMillisecondsToNow(long long milliseconds, long *sec, long *ms) { long cur_sec, cur_ms, when_sec, when_ms; // 获取当前时间 aeGetTime(&cur_sec, &cur_ms); // 计算增加 milliseconds 之后的秒数和毫秒数 when_sec = cur_sec + milliseconds/1000; when_ms = cur_ms + milliseconds%1000; // 进位: // 如果 when_ms 大于等于 1000 // 那么将 when_sec 增大一秒 if (when_ms >= 1000) { when_sec ++; when_ms -= 1000; } *sec = when_sec; *ms = when_ms; }
/* * 给当前时间加上N毫秒 * * milliseconds 毫秒 * sec 秒 * ms 毫秒 * */ static void aeAddMillisecondsToNow(long long milliseconds, long *sec, long *ms) { // 初始化要用到的变量 long cur_sec, cur_ms, when_sec, when_ms; // 获取当前时间 aeGetTime(&cur_sec, &cur_ms); // 获取当前时间加上N毫秒后的秒数 when_sec = cur_sec + milliseconds/1000; // 获取当前时间加上N毫秒后的毫秒数 when_ms = cur_ms + milliseconds%1000; // 再对毫秒数进行一次处理,大于1000毫秒将秒数加1,毫秒数减1000 if (when_ms >= 1000) { when_sec ++; when_ms -= 1000; } // 最终得到的秒与毫秒数 *sec = when_sec; *ms = when_ms; }
/*** * 当前时间增加特定毫秒后得到的事件, 以秒和毫秒表示 * @milliseconds[IN]: 要增加的毫秒数 * @sec[OUT]: 当前时间增加特定毫秒后的得到的时间的秒数 * @ms[OUT]: 当前时间增加特定毫秒后的得到的时间的毫秒数 */ static void aeAddMillisecondsToNow(long long milliseconds, long *sec, long *ms) { long cur_sec, cur_ms, when_sec, when_ms; /* 获取当前时间值, 秒和毫秒部分 */ aeGetTime(&cur_sec, &cur_ms); /* 新增毫秒数如果超过1秒, 则直接进位到当前时间的秒部分 */ when_sec = cur_sec + milliseconds/1000; /* 新增毫秒不足1秒的部分, 则直接将其加到当前时间的毫秒部分 * 注意: when_ms此时也可能存在进位, 所以下面还要处理when_ms到when_sec的进位 */ when_ms = cur_ms + milliseconds%1000; if (when_ms >= 1000) { when_sec ++; when_ms -= 1000; } /* 最终得到的未来时间的秒和毫秒部分 */ *sec = when_sec; *ms = when_ms; }
static int processTimeEvents(aeEventLoop *eventLoop) { int processed = 0; aeTimeEvent *te; long long maxId; te = eventLoop->timeEventHead; maxId = eventLoop->timeEventNextId-1; while(te) { long now_sec, now_ms; long long id; if (te->id > maxId) { te = te->next; continue; } aeGetTime(&now_sec, &now_ms); if (now_sec > te->when_sec || (now_sec == te->when_sec && now_ms >= te->when_ms)) { int retval; id = te->id; retval = te->timeProc(eventLoop, id, te->clientData); processed++; if (retval != AE_NOMORE) { aeAddMillisecondsToNow(retval,&te->when_sec,&te->when_ms); } else { aeDeleteTimeEvent(eventLoop, id); } te = eventLoop->timeEventHead; } else { te = te->next; } } return processed; }
/* Process every pending time event, then every pending file event * (that may be registered by time event callbacks just processed). * Without special flags the function sleeps until some file event * fires, or when the next time event occurrs (if any). * * If flags is 0, the function does nothing and returns. * if flags has AE_ALL_EVENTS set, all the kind of events are processed. * if flags has AE_FILE_EVENTS set, file events are processed. * if flags has AE_TIME_EVENTS set, time events are processed. * if flags has AE_DONT_WAIT set the function returns ASAP until all * the events that's possible to process without to wait are processed. * * The function returns the number of events processed. */ int aeProcessEvents(aeEventLoop *eventLoop, int flags) { int maxfd = 0, numfd = 0, processed = 0; fd_set rfds, wfds, efds; aeFileEvent *fe = eventLoop->fileEventHead; aeTimeEvent *te; long long maxId; AE_NOTUSED(flags); /* Nothing to do? return ASAP */ if (!(flags & AE_TIME_EVENTS) && !(flags & AE_FILE_EVENTS)) return 0; FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); /* Check file events */ if (flags & AE_FILE_EVENTS) { while (fe != NULL) { if (fe->mask & AE_READABLE) FD_SET(fe->fd, &rfds); if (fe->mask & AE_WRITABLE) FD_SET(fe->fd, &wfds); if (fe->mask & AE_EXCEPTION) FD_SET(fe->fd, &efds); if (maxfd < fe->fd) maxfd = fe->fd; numfd++; fe = fe->next; } } /* 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. */ if (numfd || ((flags & AE_TIME_EVENTS) && !(flags & AE_DONT_WAIT))) { int retval; aeTimeEvent *shortest = NULL; struct timeval tv, *tvp; if (flags & AE_TIME_EVENTS && !(flags & AE_DONT_WAIT)) shortest = aeSearchNearestTimer(eventLoop); if (shortest) { long now_sec, now_ms; /* Calculate the time missing for the nearest * timer to fire. */ aeGetTime(&now_sec, &now_ms); tvp = &tv; tvp->tv_sec = shortest->when_sec - now_sec; if (shortest->when_ms < now_ms) { tvp->tv_usec = ((shortest->when_ms+1000) - now_ms)*1000; tvp->tv_sec --; } else { tvp->tv_usec = (shortest->when_ms - now_ms)*1000; } } else { /* If we have to check for events but need to return * ASAP because of AE_DONT_WAIT we need to se the timeout * to zero */ if (flags & AE_DONT_WAIT) { tv.tv_sec = tv.tv_usec = 0; tvp = &tv; } else { /* Otherwise we can block */ tvp = NULL; /* wait forever */ } } retval = select(maxfd+1, &rfds, &wfds, &efds, tvp); if (retval > 0) { fe = eventLoop->fileEventHead; while(fe != NULL) { int fd = (int) fe->fd; if ((fe->mask & AE_READABLE && FD_ISSET(fd, &rfds)) || (fe->mask & AE_WRITABLE && FD_ISSET(fd, &wfds)) || (fe->mask & AE_EXCEPTION && FD_ISSET(fd, &efds))) { int mask = 0; if (fe->mask & AE_READABLE && FD_ISSET(fd, &rfds)) mask |= AE_READABLE; if (fe->mask & AE_WRITABLE && FD_ISSET(fd, &wfds)) mask |= AE_WRITABLE; if (fe->mask & AE_EXCEPTION && FD_ISSET(fd, &efds)) mask |= AE_EXCEPTION; fe->fileProc(eventLoop, fe->fd, fe->clientData, mask); processed++; /* After an event is processed our file event list * may no longer be the same, so what we do * is to clear the bit for this file descriptor and * restart again from the head. */ fe = eventLoop->fileEventHead; FD_CLR(fd, &rfds); FD_CLR(fd, &wfds); FD_CLR(fd, &efds); } else { fe = fe->next; } } } } /* Check time events */ if (flags & AE_TIME_EVENTS) { te = eventLoop->timeEventHead; maxId = eventLoop->timeEventNextId-1; while(te) { long now_sec, now_ms; long long id; if (te->id > maxId) { te = te->next; continue; } aeGetTime(&now_sec, &now_ms); if (now_sec > te->when_sec || (now_sec == te->when_sec && now_ms >= te->when_ms)) { int retval; id = te->id; retval = te->timeProc(eventLoop, id, te->clientData); /* 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. */ if (retval != AE_NOMORE) { aeAddMillisecondsToNow(retval,&te->when_sec,&te->when_ms); } else { aeDeleteTimeEvent(eventLoop, id); } te = eventLoop->timeEventHead; } else { te = te->next; } } } return processed; /* return the number of processed file/time events */ }
// 处理所有待处理的时间事件,以及所有待处理的文件事件 // 如果不给函数传入特定的 flag ,那么函数会一直 sleep , // 直到有文件事件触发,或者下一个时间事件发生(如果有的话) // // 如果 flags 为 0 的话,函数不做动作,直接返回 // 如果 flags 的 AE_ALL_EVENTS 被打开,那么所有种类的事件都会被处理 // 如果 flags 的 AE_FILE_EVENTS 被打开,那么文件事件会被处理 // 如果 flags 的 AE_TIME_EVENTS 被打开,那么时间事件会被处理 // 如果 flags 的 AE_DONT_WAIT 被打开,那么函数在处理完所有不须等待的事件后返回 // // 函数的返回值为处理事件的个数 int aeProcessEvents(aeEventLoop *eventLoop, int flags) { int processed = 0, numevents; /* Nothing to do? return ASAP */ // 无操作,直接返回 if (!(flags & AE_TIME_EVENTS) && !(flags & AE_FILE_EVENTS)) return 0; /* 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. */ // 如果文件事件的个数不为空 // 或者 AE_TIME_EVENTS 被打开,且没有打开 AE_DONT_WAIT // 那么执行以下语句,设置处理文件事件时所使用的时间差 if (eventLoop->maxfd != -1 || ((flags & AE_TIME_EVENTS) && !(flags & AE_DONT_WAIT))) { int j; aeTimeEvent *shortest = NULL; struct timeval tv, *tvp; // 如果 AE_TIME_EVENTS 被打开且没有打开 AE_DONT_WAIT // 那么查找执行时间离现在最近的一个时间事件 if (flags & AE_TIME_EVENTS && !(flags & AE_DONT_WAIT)) shortest = aeSearchNearestTimer(eventLoop); // 如果最近时间事件不为空的话。。 if (shortest) { long now_sec, now_ms; /* Calculate the time missing for the nearest * timer to fire. */ // 计算距离最近时间事件发生还需要多少时间 aeGetTime(&now_sec, &now_ms); tvp = &tv; tvp->tv_sec = shortest->when_sec - now_sec; if (shortest->when_ms < now_ms) { tvp->tv_usec = ((shortest->when_ms+1000) - now_ms)*1000; tvp->tv_sec --; } else { tvp->tv_usec = (shortest->when_ms - now_ms)*1000; } // 如果时间差小于 0 // 说明当前时间已经超过时间事件的执行时间了 // 那么将时间差设置为 0 if (tvp->tv_sec < 0) tvp->tv_sec = 0; if (tvp->tv_usec < 0) tvp->tv_usec = 0; } else { /* If we have to check for events but need to return * ASAP because of AE_DONT_WAIT we need to se the timeout * to zero */ // 如果执行到这一步,说明没有时间事件 // 那么根据 AE_DONT_WAIT 的设置状态,设置时间差 if (flags & AE_DONT_WAIT) { // 如果 AE_DONT_WAIT 被打开 // 那么将时间差设置为 0 ,也即是不等待 tv.tv_sec = tv.tv_usec = 0; tvp = &tv; } else { // 否则,就一直等待(直到有文件事件触发,或时间事件触发) /* Otherwise we can block */ tvp = NULL; /* wait forever */ } } // 处理文件事件 numevents = aeApiPoll(eventLoop, tvp); for (j = 0; j < numevents; j++) { // 根据 fired 数组,从 events 数组中取出事件 aeFileEvent *fe = &eventLoop->events[eventLoop->fired[j].fd]; int mask = eventLoop->fired[j].mask; int fd = eventLoop->fired[j].fd; int rfired = 0; /* 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. */ // 因为一个已处理的事件有可能对当前被执行的事件进行了修改 // 因此在执行当前事件前,需要再进行一次检查 // 确保事件可以被执行 if (fe->mask & mask & AE_READABLE) { rfired = 1; fe->rfileProc(eventLoop,fd,fe->clientData,mask); } if (fe->mask & mask & AE_WRITABLE) { if (!rfired || fe->wfileProc != fe->rfileProc) fe->wfileProc(eventLoop,fd,fe->clientData,mask); } processed++; } } /* Check time events */ // 如果 AE_TIME_EVENTS 被打开 // 那么处理时间事件 if (flags & AE_TIME_EVENTS) processed += processTimeEvents(eventLoop); // 返回被执行事件的个数 return processed; /* return the number of processed file/time events */ }
// 处理时间事件 // 所有满足条件的时间事件都会被执行 static int processTimeEvents(aeEventLoop *eventLoop) { int processed = 0; aeTimeEvent *te; long long maxId; // 遍历所有时间事件 te = eventLoop->timeEventHead; maxId = eventLoop->timeEventNextId-1; while(te) { long now_sec, now_ms; long long id; // 略过无效事件 if (te->id > maxId) { te = te->next; continue; } // 获取当前时间 aeGetTime(&now_sec, &now_ms); // 如果当前时间等于或大于事件的执行时间 // 那么执行这个事件 if (now_sec > te->when_sec || (now_sec == te->when_sec && now_ms >= te->when_ms)) { // 记录返回值 int retval; // 执行事件 id = te->id; retval = te->timeProc(eventLoop, id, te->clientData); // 更新执行计数器 processed++; /* 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). */ if (retval != AE_NOMORE) { // 如果 retval 不等于 AE_NOMORE // 那么修改这个事件的执行时间 // 让事件在稍候再次执行 aeAddMillisecondsToNow(retval,&te->when_sec,&te->when_ms); } else { // 如果执行成功, 那么删除这个事件 aeDeleteTimeEvent(eventLoop, id); } // 因为执行事件之后,事件列表可能已经被改变了 // 因此需要返回到表头,继续开始执行事件 te = eventLoop->timeEventHead; } else { // 如果事件的执行时间未到,那么继续检查链表中的下个事件 te = te->next; } } // 返回处理事件的数量 return processed; }
/* * 处理所有已到达的时间事件以及所有已就绪的文件事件 * * eventLoop 事件处理器指针 * flags 事件处理旗标 * 0 事件不处理直接返回 * AE_ALL_EVENTS 所有类型的事件都会被处理 * AE_FILE_EVENTS 处理文件事件 * AE_TIME_EVENTS 处理时间事件 * AE_DONT_WAIT 处理完所有不许阻塞的事件之后立即返回 * */ int aeProcessEvents(aeEventLoop *eventLoop, int flags) { // 初始化已处理的事件计数器,定义事件数量变量 int processed = 0, numevents; /* Nothing to do? return ASAP */ // 什么也不做,直接返回0 if (!(flags & AE_TIME_EVENTS) && !(flags & AE_FILE_EVENTS)) return 0; /* 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. */ // 当前已注册的最大文件描述符不为-1或旗标为处理时间事件并且不为不许阻塞的事件 if (eventLoop->maxfd != -1 || ((flags & AE_TIME_EVENTS) && !(flags & AE_DONT_WAIT))) { // 定义循环计数器 int j; // 定义时间事件指针 aeTimeEvent *shortest = NULL; // 定义timeval结构体与指针 struct timeval tv, *tvp; // 旗标为处理时间事件并且不为不许阻塞的事件 if (flags & AE_TIME_EVENTS && !(flags & AE_DONT_WAIT)) // 获取离当前最近需要处理的时间事件 shortest = aeSearchNearestTimer(eventLoop); // 如果存在需要处理的时间事件 if (shortest) { // 定义当前时间秒与微秒 long now_sec, now_ms; /* Calculate the time missing for the nearest * timer to fire. */ // 获取当前时间 aeGetTime(&now_sec, &now_ms); // 设置timeval结构体指针 tvp = &tv; // 计算距今最近的时间事件还要多久才能达到 tvp->tv_sec = shortest->when_sec - now_sec; // 最近的时间事件到达时间小于当前时间 if (shortest->when_ms < now_ms) { // 获取时间差 tvp->tv_usec = ((shortest->when_ms+1000) - now_ms)*1000; tvp->tv_sec --; } else { // 获取时间差 tvp->tv_usec = (shortest->when_ms - now_ms)*1000; } // 时间差小于0,表示事件可以执行,并将时间设置为0 if (tvp->tv_sec < 0) tvp->tv_sec = 0; if (tvp->tv_usec < 0) tvp->tv_usec = 0; } else { /* 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 */ // 没有要处理的时间事件 // 根据AE_DONT_WAIT是否设置来决定是否阻塞,以及阻塞的时间长度 if (flags & AE_DONT_WAIT) { // 设置文件事件不阻塞 tv.tv_sec = tv.tv_usec = 0; tvp = &tv; } else { /* Otherwise we can block */ // 文件事件可以阻塞直到有事件到达为止 tvp = NULL; /* wait forever */ } } // 获取已就绪事件数量 numevents = aeApiPoll(eventLoop, tvp); // 遍历事件 for (j = 0; j < numevents; j++) { // 从已就绪数组中获取事件 aeFileEvent *fe = &eventLoop->events[eventLoop->fired[j].fd]; // 获取已就绪事件类型 int mask = eventLoop->fired[j].mask; // 获取已就绪事件文件描述符 int fd = eventLoop->fired[j].fd; // 是否为读事件 int rfired = 0; /* 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. */ // 读事件 if (fe->mask & mask & AE_READABLE) { // 标记为读事件,确保读与写事件只能执行其中一个 rfired = 1; // 调用读文件方法 fe->rfileProc(eventLoop,fd,fe->clientData,mask); } // 写事件 if (fe->mask & mask & AE_WRITABLE) { if (!rfired || fe->wfileProc != fe->rfileProc) // 调用写文件方法 fe->wfileProc(eventLoop,fd,fe->clientData,mask); } // 已处理事件加1 processed++; } } /* Check time events */ // 处理时间事件 if (flags & AE_TIME_EVENTS) // 使用processTimeEvents函数执行时间事件,并将已处理的事件数量累加 processed += processTimeEvents(eventLoop); // 返回已处理的事件数量 return processed; /* return the number of processed file/time events */ }
/* * 处理所有已到达的时间事件 * * eventLoop 事件处理器指针 * */ static int processTimeEvents(aeEventLoop *eventLoop) { // 初始化已处理的事件计数器 int processed = 0; // 定义时间事件 aeTimeEvent *te; // 定义最大的时间事件ID long long maxId; // 获取当前时间 time_t now = time(NULL); /* 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. */ // 当前时间小于最后一次执行事件的时间,表示系统时间移动到了未来时间后又回调到了正确的时间,这里的处理是为了防止这种情况的出现 if (now < eventLoop->lastTime) { // 获取事件处理器事件头事件 te = eventLoop->timeEventHead; // 遍历事件处理器 while(te) { // 将事件到达时间设为0 te->when_sec = 0; // 继续处理下个事件 te = te->next; } } // 将最后一次执行事件的时间设为当前时间 eventLoop->lastTime = now; // 重新获取事件处理器事件头事件 te = eventLoop->timeEventHead; // 将最大事件ID设为下个事件ID减1 maxId = eventLoop->timeEventNextId-1; // 遍历事件处理器 while(te) { // 时间事件到达的秒与微秒 long now_sec, now_ms; // 时间事件ID long long id; // 当前时间事件的ID大于最大事件ID if (te->id > maxId) { // 处理下一个时间事件 te = te->next; // 跳到下次循环 continue; } // 调用对应复用库中的aeGetTime方法 aeGetTime(&now_sec, &now_ms); // 当前时间大于时间事件到达时间,表示时间事件需要执行了 if (now_sec > te->when_sec || (now_sec == te->when_sec && now_ms >= te->when_ms)) { // 定义retval变量 int retval; // 获取当前处理的时间事件ID id = te->id; // 调用时间事件处理方法,返回-1或一个整数,大于-1时表示这个事件需要循环处理 retval = te->timeProc(eventLoop, id, te->clientData); // 已处理的事件计数器加1 processed++; /* 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). */ // 是否有需要循环执行这个事件时间 if (retval != AE_NOMORE) { // retval毫秒之后继续执行这个时间事件 aeAddMillisecondsToNow(retval,&te->when_sec,&te->when_ms); } else { // 删除时间事件 aeDeleteTimeEvent(eventLoop, id); } // 前当前处理事件设为时间处理器的头事件,继续循环 te = eventLoop->timeEventHead; } else { // 将当前处理事件设为下一个时间事件,继续循环 te = te->next; } } // 返回已处理的时间事件数量 return processed; }
/* Process time events */ static int processTimeEvents(aeEventLoop *eventLoop) { int processed = 0; aeTimeEvent *te, *prev; long long maxId; time_t now = time(NULL); /* 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. */ if (now < eventLoop->lastTime) { te = eventLoop->timeEventHead; while(te) { te->when_sec = 0; te = te->next; } } eventLoop->lastTime = now; prev = NULL; te = eventLoop->timeEventHead; maxId = eventLoop->timeEventNextId-1; while(te) { long now_sec, now_ms; long long id; /* Remove events scheduled for deletion. */ if (te->id == AE_DELETED_EVENT_ID) { aeTimeEvent *next = te->next; if (prev == NULL) eventLoop->timeEventHead = te->next; else prev->next = te->next; if (te->finalizerProc) te->finalizerProc(eventLoop, te->clientData); zfree(te); te = next; continue; } /* Make sure we don't process time events created by time events in * this iteration. Note that this check is currently useless: we always * add new timers on the head, however if we change the implementation * detail, this check may be useful again: we keep it here for future * defense. */ if (te->id > maxId) { te = te->next; continue; } aeGetTime(&now_sec, &now_ms); if (now_sec > te->when_sec || (now_sec == te->when_sec && now_ms >= te->when_ms)) { int retval; id = te->id; retval = te->timeProc(eventLoop, id, te->clientData); processed++; if (retval != AE_NOMORE) { aeAddMillisecondsToNow(retval,&te->when_sec,&te->when_ms); } else { te->id = AE_DELETED_EVENT_ID; } } prev = te; te = te->next; } return processed; }
/* Process time events */ static int processTimeEvents(aeEventLoop *eventLoop) { int processed = 0; aeTimeEvent *te; long long maxId; time_t now = time(NULL); /* 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. */ if (now < eventLoop->lastTime) { te = eventLoop->timeEventHead; while(te) { te->when_sec = 0; te = te->next; } } eventLoop->lastTime = now; te = eventLoop->timeEventHead; maxId = eventLoop->timeEventNextId-1; while(te) { long now_sec, now_ms; long long id; if (te->id > maxId) { te = te->next; continue; } aeGetTime(&now_sec, &now_ms); if (now_sec > te->when_sec || (now_sec == te->when_sec && now_ms >= te->when_ms)) { int retval; id = te->id; retval = te->timeProc(eventLoop, id, te->clientData); processed++; /* 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). */ if (retval != AE_NOMORE) { aeAddMillisecondsToNow(retval,&te->when_sec,&te->when_ms); } else { aeDeleteTimeEvent(eventLoop, id); } te = eventLoop->timeEventHead; } else { te = te->next; } } return processed; }
/*** * 进行一次定时事件处理 * @eventLoop[IN]: 事件循环处理器(Reactor组件) * @return: 本次得到处理的事件数量 */ static int processTimeEvents(aeEventLoop *eventLoop) { /* 记录本次得到处理的定时事件数 */ int processed = 0; aeTimeEvent *te; long long maxId; /* 系统当前绝对时间 */ time_t now = time(NULL); /* 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. */ /*** * 如果发现系统时间, 则将时间值纠正. * 这里我们尝试检测系统时间是否不准确, 如果是, 则尽可能快的处理所有定时事件, * 毕竟提前处理定时事件总比无限期的延迟定时时间更安全, 实践证明这种思想是正确的 */ /* 正常情况下, 当前系统时间值必定是大于eventLoop中记录的上次操作的时间值, 如果不是, * 则说明系统事件不准确, 此时将所有定时事件的超时时间的秒值设为0(尽可能快递处理所有定时事件), * 同时eventLoop的上次操作事件更新为当前系统时间 */ if (now < eventLoop->lastTime) { te = eventLoop->timeEventHead; while(te) { te->when_sec = 0; te = te->next; } } eventLoop->lastTime = now; te = eventLoop->timeEventHead; /* 记录当前定时事件链表中最大的定时器ID */ maxId = eventLoop->timeEventNextId-1; while(te) { long now_sec, now_ms; long long id; /* 为什么会出现某个定时事件的id会大于maxId呢? 可能是因为ae中的所有操作都是非线程 * 安全的, 比如在maxId获取的同时执行了aeCreateTimeEvent操作, 此时我们忽略新增的事件 * 等到下一轮while检测处理(以避免可能出现的无限循环) */ if (te->id > maxId) { te = te->next; continue; } /* 获取系统当前时间的秒和毫秒部分 */ aeGetTime(&now_sec, &now_ms); /* 如果当前时间的秒值已经大于定时事件的超时值的秒部分; 或者秒部分等于当前系统时间的秒部分‘ * 但系统的毫秒部分大于事件的毫秒部分; 则说明该事件已经超时, 可以处理该定时事件了 */ if (now_sec > te->when_sec || (now_sec == te->when_sec && now_ms >= te->when_ms)) { int retval; id = te->id; /* 调用定时事件处理函数 */ retval = te->timeProc(eventLoop, id, te->clientData); /* 本次已处理定时事件数增1 */ processed++; /* 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). */ /* 定时事件处理函数的返回值用于指示该定时事件是循环定时还是单次定时事件 * 如果返回AE_NOMORE, 说明是单次定时, 则此时可以删除该定时事件; * 如果不是返回AE_NOMORE(此时返回的值代表下次超时的相对值), 说明是循环定时事件, 则修改该事件的超时时间值 */ if (retval != AE_NOMORE) { /* 将retval值(相对时间值)加到当前系统绝对事件, 并转化为秒值和毫秒值 */ aeAddMillisecondsToNow(retval,&te->when_sec,&te->when_ms); } else { aeDeleteTimeEvent(eventLoop, id); } /* 处理后链表可能发生了变化, 所以我们再次从链表头开始处理 */ te = eventLoop->timeEventHead; } else { te = te->next; } } return processed; }
/* Process every pending time event, then every pending file event * (that may be registered by time event callbacks just processed). * * 处理所有已到达的时间事件,以及所有已就绪的文件事件。 * * Without special flags the function sleeps until some file event * fires, or when the next time event occurrs (if any). * * 如果不传入特殊 flags 的话,那么函数睡眠直到文件事件就绪, * 或者下个时间事件到达(如果有的话)。 * * If flags is 0, the function does nothing and returns. * 如果 flags 为 0 ,那么函数不作动作,直接返回。 * * if flags has AE_ALL_EVENTS set, all the kind of events are processed. * 如果 flags 包含 AE_ALL_EVENTS ,所有类型的事件都会被处理。 * * if flags has AE_FILE_EVENTS set, file events are processed. * 如果 flags 包含 AE_FILE_EVENTS ,那么处理文件事件。 * * if flags has AE_TIME_EVENTS set, time events are processed. * 如果 flags 包含 AE_TIME_EVENTS ,那么处理时间事件。 * * if flags has AE_DONT_WAIT set the function returns ASAP until all * the events that's possible to process without to wait are processed. * 如果 flags 包含 AE_DONT_WAIT , * 那么函数在处理完所有不许阻塞的事件之后,即刻返回。 * * The function returns the number of events processed. * 函数的返回值为已处理事件的数量 */ int aeProcessEvents(aeEventLoop *eventLoop, int flags) { int processed = 0, numevents; /* Nothing to do? return ASAP */ if (!(flags & AE_TIME_EVENTS) && !(flags & AE_FILE_EVENTS)) return 0; /* 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. */ if (eventLoop->maxfd != -1 || ((flags & AE_TIME_EVENTS) && !(flags & AE_DONT_WAIT))) { int j; aeTimeEvent *shortest = NULL; struct timeval tv, *tvp; // 获取最近的时间事件 if (flags & AE_TIME_EVENTS && !(flags & AE_DONT_WAIT)) shortest = aeSearchNearestTimer(eventLoop); if (shortest) { // 如果时间事件存在的话 // 那么根据最近可执行时间事件和现在时间的时间差来决定文件事件的阻塞时间 long now_sec, now_ms; /* Calculate the time missing for the nearest * timer to fire. */ // 计算距今最近的时间事件还要多久才能达到 // 并将该时间距保存在 tv 结构中 aeGetTime(&now_sec, &now_ms); tvp = &tv; tvp->tv_sec = shortest->when_sec - now_sec; if (shortest->when_ms < now_ms) { tvp->tv_usec = ((shortest->when_ms+1000) - now_ms)*1000; tvp->tv_sec --; } else { tvp->tv_usec = (shortest->when_ms - now_ms)*1000; } // 时间差小于 0 ,说明事件已经可以执行了,将秒和毫秒设为 0 (不阻塞) if (tvp->tv_sec < 0) tvp->tv_sec = 0; if (tvp->tv_usec < 0) tvp->tv_usec = 0; } else { // 执行到这一步,说明没有时间事件 // 那么根据 AE_DONT_WAIT 是否设置来决定是否阻塞,以及阻塞的时间长度 /* If we have to check for events but need to return * ASAP because of AE_DONT_WAIT we need to se the timeout * to zero */ if (flags & AE_DONT_WAIT) { // 设置文件事件不阻塞 tv.tv_sec = tv.tv_usec = 0; tvp = &tv; } else { /* Otherwise we can block */ // 文件事件可以阻塞直到有事件到达为止 tvp = NULL; /* wait forever */ } } // 处理文件事件,阻塞时间由 tvp 决定 numevents = aeApiPoll(eventLoop, tvp); for (j = 0; j < numevents; j++) { // 从已就绪数组中获取事件 aeFileEvent *fe = &eventLoop->events[eventLoop->fired[j].fd]; int mask = eventLoop->fired[j].mask; int fd = eventLoop->fired[j].fd; int rfired = 0; /* 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. */ if (fe->mask & mask & AE_READABLE) { // 读事件 rfired = 1; // 确保读/写事件只能执行其中一个 fe->rfileProc(eventLoop,fd,fe->clientData,mask); } if (fe->mask & mask & AE_WRITABLE) { // 写事件 if (!rfired || fe->wfileProc != fe->rfileProc) fe->wfileProc(eventLoop,fd,fe->clientData,mask); } processed++; } } /* Check time events */ // 执行时间事件 if (flags & AE_TIME_EVENTS) processed += processTimeEvents(eventLoop); return processed; /* return the number of processed file/time events */ }
/*** * 事件循环处理函数 * @eventLoop[IN]: 事件循环处理器 * @flag[IN]: 事件处理标记 * 0-> 表示不做任何处理, 直接返回 * AE_ALL_EVENTS-> 表示处理所有事件(IO事件和定时事件) * AE_FILE_EVENTS-> 表示需要处理IO事件 * AE_TIME_EVENTS-> 表示需要处理定时事件 * AE_DONT_WAIT-> 表示如果没有事件能够处理, 则直接返回 * @return: 返回本次调用处理的事件的总数(IO事件+定时事件) */ int aeProcessEvents(aeEventLoop *eventLoop, int flags) { int processed = 0, numevents; /* 如果没有任何需要处理的事件, 则直接返回*/ if (!(flags & AE_TIME_EVENTS) && !(flags & AE_FILE_EVENTS)) return 0; /* 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. */ /*** * 1)如果maxfd不为-1, 说明存在IO事件, 需要调用IO复用接口进行依次poll * 2)或者如果需要处理定时事件并且没有AE_DONT_WAIT标记, 也可以调用IO复用接口(进行等待) * IO复用接口都存在一个调用超时事件, 这个时间参数可以为我们提供一个原始的定时器, 我们可以将 * 最近将要超时的定时事件的时间值传入, 这样可以避免反复的Poll来轮询是否有定时事件超时 * * 另外值得注意的是AE_DONT_WAIT标记: * 这个标记的意义在于: 如果没有任何IO事件在无需等待的情况下就绪, 或者没有任何定时事件在此刻超时 * 则应保证aeProcessEvents立即返回 */ if (eventLoop->maxfd != -1 || ((flags & AE_TIME_EVENTS) && !(flags & AE_DONT_WAIT))) { int j; aeTimeEvent *shortest = NULL; struct timeval tv, *tvp; /* 如果需要处理定时事件, 并且flag标记没有AE_DONT_WAIT标记, 则获取最近可能要超时的定时事件 */ if (flags & AE_TIME_EVENTS && !(flags & AE_DONT_WAIT)) shortest = aeSearchNearestTimer(eventLoop); /* 如果存在定时事件, 并且没有AE_DONT_WAIT标记, 计算最近的定时事件多长时间后超时, * 通过tvp指示 */ if (shortest) { long now_sec, now_ms; /* Calculate the time missing for the nearest * timer to fire. */ aeGetTime(&now_sec, &now_ms); tvp = &tv; /* 将事件的超时事件的秒值减去当前系统时间值的秒值 */ tvp->tv_sec = shortest->when_sec - now_sec; if (shortest->when_ms < now_ms) { tvp->tv_usec = ((shortest->when_ms+1000) - now_ms)*1000; tvp->tv_sec --; } else { tvp->tv_usec = (shortest->when_ms - now_ms)*1000; } /* 正常情况下是不可能得到负值的, 除非系统时间发生调整, 此时直接将等待事件设置为0, * 从而保证aeApiPoll能够立刻返回(以便与系统事件发生调整时, 所有定时事件得到尽快的处理) */ if (tvp->tv_sec < 0) tvp->tv_sec = 0; if (tvp->tv_usec < 0) tvp->tv_usec = 0; } else { /* 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 */ /* 如果存在AE_DONT_WAIT标记, 则将等待事件设置为0, 以便aeApiPoll能够立刻返回 */ if (flags & AE_DONT_WAIT) { tv.tv_sec = tv.tv_usec = 0; tvp = &tv; } else { /* 如果不存在任何定时事件并且flag中不存在AE_DONT_WAIT标记, 则tvp=NULL, *以便aeApiPoll能够一直阻塞直到有任何IO事件就绪 */ tvp = NULL; /* wait forever */ } } /* 调用特定操作系统IO复用API, 通过前面可知, 如果不存在任何定时事件, 则tvp=NULL */ numevents = aeApiPoll(eventLoop, tvp); for (j = 0; j < numevents; j++) { /* aeApiPoll会修改eventLoop中的fired数组, 将就绪的IO事件在该数组中标记 */ /* 通过fired中的fd定位IO事件数组, 得到该事件对应的事件结构体 */ aeFileEvent *fe = &eventLoop->events[eventLoop->fired[j].fd]; /* 取出代表就绪事件类型的mask标记 */ int mask = eventLoop->fired[j].mask; int fd = eventLoop->fired[j].fd; int rfired = 0; /* 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. */ /* 如果IO事件读就绪, 则调用其读处理函数 */ if (fe->mask & mask & AE_READABLE) { rfired = 1; fe->rfileProc(eventLoop,fd,fe->clientData,mask); } /* 如果IO事件的写就绪, 则调用其写处理函数 */ if (fe->mask & mask & AE_WRITABLE) { /* 前面初始化的时候, 我们注意到, 读和写就绪处理函数时同一个函数, 他们通过mask来区分读写 */ if (!rfired || fe->wfileProc != fe->rfileProc) fe->wfileProc(eventLoop,fd,fe->clientData,mask); } processed++; } } /* Check time events */ /* 处理可能超时的定时事件 */ if (flags & AE_TIME_EVENTS) processed += processTimeEvents(eventLoop); /* 返回本次Poll操作总共就绪并得到处理的事件总数 */ return processed; /* return the number of processed file/time events */ }
/* Process every pending time event, then every pending file event * (that may be registered by time event callbacks just processed). * Without special flags the function sleeps until some file event * fires, or when the next time event occurs (if any). * * If flags is 0, the function does nothing and returns. * if flags has AE_ALL_EVENTS set, all the kind of events are processed. * if flags has AE_FILE_EVENTS set, file events are processed. * if flags has AE_TIME_EVENTS set, time events are processed. * if flags has AE_DONT_WAIT set the function returns ASAP until all * the events that's possible to process without to wait are processed. * * The function returns the number of events processed. */ int aeProcessEvents(aeEventLoop *eventLoop, int flags) { int processed = 0, numevents; /* Nothing to do? return ASAP */ if (!(flags & AE_TIME_EVENTS) && !(flags & AE_FILE_EVENTS)) return 0; /* 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. */ if (eventLoop->maxfd != -1 || ((flags & AE_TIME_EVENTS) && !(flags & AE_DONT_WAIT))) { int j; aeTimeEvent *shortest = NULL; struct timeval tv, *tvp; if (flags & AE_TIME_EVENTS && !(flags & AE_DONT_WAIT)) shortest = aeSearchNearestTimer(eventLoop); if (shortest) { long now_sec, now_ms; /* Calculate the time missing for the nearest * timer to fire. */ aeGetTime(&now_sec, &now_ms); tvp = &tv; tvp->tv_sec = shortest->when_sec - now_sec; if (shortest->when_ms < now_ms) { tvp->tv_usec = ((shortest->when_ms+1000) - now_ms)*1000; tvp->tv_sec --; } else { tvp->tv_usec = (shortest->when_ms - now_ms)*1000; } if (tvp->tv_sec < 0) tvp->tv_sec = 0; if (tvp->tv_usec < 0) tvp->tv_usec = 0; } else { /* 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 */ if (flags & AE_DONT_WAIT) { tv.tv_sec = tv.tv_usec = 0; tvp = &tv; } else { /* Otherwise we can block */ tvp = NULL; /* wait forever */ } } numevents = aeApiPoll(eventLoop, tvp); for (j = 0; j < numevents; j++) { aeFileEvent *fe = &eventLoop->events[eventLoop->fired[j].fd]; int mask = eventLoop->fired[j].mask; int fd = eventLoop->fired[j].fd; int rfired = 0; /* 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. */ if (fe->mask & mask & AE_READABLE) { rfired = 1; fe->rfileProc(eventLoop,fd,fe->clientData,mask); } if (fe->mask & mask & AE_WRITABLE) { if (!rfired || fe->wfileProc != fe->rfileProc) fe->wfileProc(eventLoop,fd,fe->clientData,mask); } processed++; } } /* Check time events */ if (flags & AE_TIME_EVENTS) processed += processTimeEvents(eventLoop); return processed; /* return the number of processed file/time events */ }
static int processTimeEvents(aeEventLoop *eventLoop) { int processed = 0; aeTimeEvent *te; long long maxId; time_t now = time(NULL); /* 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. */ // 通过重置事件的运行时间, // 防止因时间穿插(skew)而造成的事件处理混乱 if (now < eventLoop->lastTime) { te = eventLoop->timeEventHead; while(te) { te->when_sec = 0; te = te->next; } } // 更新最后一次处理时间事件的时间 eventLoop->lastTime = now; // 遍历链表 // 执行那些已经到达的事件 te = eventLoop->timeEventHead; maxId = eventLoop->timeEventNextId-1; while(te) { long now_sec, now_ms; long long id; // 跳过无效事件 if (te->id > maxId) { te = te->next; continue; } // 获取当前时间 aeGetTime(&now_sec, &now_ms); // 如果当前时间等于或等于事件的执行时间,那么说明事件已到达,执行这个事件 if (now_sec > te->when_sec || (now_sec == te->when_sec && now_ms >= te->when_ms)) { int retval; id = te->id; // 执行事件处理器,并获取返回值 retval = te->timeProc(eventLoop, id, te->clientData); processed++; /* 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). */ /* 如果事件处理器返回AE_NOMORE,那么这个事件为定时事件:该事件在达到一次之后就会被删除,之后不再到达。 如果事件处理器返回一个非AE NOMORE的整数值,那么这个事件为周期性时间:当一个时间事件到达之后,服务器会根据事件处理器返回的值, 对时间事件的when属性进行更新,让这个事件在一段时间之后再次到达,并以这种方式一直更新并运行下去。 比如说,如果一个时间事件的赴理器返回整数值30,那么服务器应该对这个时间事件进行更新,让这个事件在30毫秒之后再次到达。 * 决定时间事件是否要持续执行的 flag */ // 记录是否有需要循环执行这个事件时间 if (retval != AE_NOMORE) { // 是的, retval 毫秒之后继续执行这个时间事件 aeAddMillisecondsToNow(retval,&te->when_sec,&te->when_ms); } else { // 不,将这个事件删除 aeDeleteTimeEvent(eventLoop, id); } // 因为执行事件之后,事件列表可能已经被改变了 // 因此需要将 te 放回表头,继续开始执行事件 te = eventLoop->timeEventHead; } else { te = te->next; } } return processed; }