/* * 创建时间事件 */ long long aeCreateTimeEvent(aeEventLoop *eventLoop, long long milliseconds, aeTimeProc *proc, void *clientData, aeEventFinalizerProc *finalizerProc) { // 更新时间计数器 long long id = eventLoop->timeEventNextId++; aeTimeEvent *te; te = malloc(sizeof(*te)); if (te == NULL) return AE_ERR; te->id = id; // 设定处理事件的时间 aeAddMillisecondsToNow(milliseconds,&te->when_sec,&te->when_ms); te->timeProc = proc; te->finalizerProc = finalizerProc; te->clientData = clientData; // 将新事件放入表头 te->next = eventLoop->timeEventHead; eventLoop->timeEventHead = te; return id; }
/* * 创建时间事件 * * eventLoop 事件处理器指针 * milliseconds 毫秒数 * proc 时间事件处理方法 * clientData 复用库的私有数据 * finalizerProc 时间事件释放方法 * */ long long aeCreateTimeEvent(aeEventLoop *eventLoop, long long milliseconds, aeTimeProc *proc, void *clientData, aeEventFinalizerProc *finalizerProc) { // 将时间事件ID加1 long long id = eventLoop->timeEventNextId++; // 定义时间事件指针 aeTimeEvent *te; // 分配内存 te = zmalloc(sizeof(*te)); // 分配内存失败返回错误状态 if (te == NULL) return AE_ERR; // 设置时间事件ID te->id = id; // 设置时间事件到达的秒与毫秒数 aeAddMillisecondsToNow(milliseconds,&te->when_sec,&te->when_ms); // 设置时间事件处理方法 te->timeProc = proc; // 设置时间事件释放方法 te->finalizerProc = finalizerProc; // 设置复用库的私有数据 te->clientData = clientData; // 设置指向下个时间事件的指针 te->next = eventLoop->timeEventHead; // 将事件处理器的时间事件头设为当前时间事件 eventLoop->timeEventHead = te; // 返回时间事件ID return id; }
/* 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; }
long long aeCreateTimeEvent(aeEventLoop *eventLoop, long long milliseconds, aeTimeProc *proc, void *clientData, aeEventFinalizerProc *finalizerProc) { long long id = eventLoop->timeEventNextId++; aeTimeEvent *te; te = zmalloc(sizeof(*te)); if (te == NULL) return AE_ERR; te->id = id; aeAddMillisecondsToNow(milliseconds,&te->when_sec,&te->when_ms); te->timeProc = proc; te->finalizerProc = finalizerProc; te->clientData = clientData; aeInsertTimeEvent(eventLoop->timeEventRbtreeRoot, te); return id; }
/** * Add by wangqiying */ int aeModifyTimeEvent(aeEventLoop *eventLoop, long long id, long long milliseconds) { aeTimeEvent *te, *prev = NULL; te = eventLoop->timeEventHead; while (te) { if (te->id == id) { aeAddMillisecondsToNow(milliseconds, &te->when_sec, &te->when_ms); return AE_OK; } prev = te; te = te->next; } return AE_ERR; /* NO event with the specified ID found */ }
PORT_LONGLONG aeCreateTimeEvent(aeEventLoop *eventLoop, PORT_LONGLONG milliseconds, aeTimeProc *proc, void *clientData, aeEventFinalizerProc *finalizerProc) { PORT_LONGLONG id = eventLoop->timeEventNextId++; aeTimeEvent *te; te = zmalloc(sizeof(*te)); if (te == NULL) return AE_ERR; te->id = id; aeAddMillisecondsToNow(milliseconds,&te->when_sec,&te->when_ms); te->timeProc = proc; te->finalizerProc = finalizerProc; te->clientData = clientData; te->next = eventLoop->timeEventHead; eventLoop->timeEventHead = te; return id; }
long long kr_event_time_create(T_KREventLoop *eventLoop, long long milliseconds, KREventTimeFunc *proc, void *clientData, KREventFinalizerFunc *finalizerProc) { long long id = eventLoop->timeEventNextId++; T_KRTimeEvent *te; te = kr_malloc(sizeof(*te)); if (te == NULL) return KR_EVENT_ERR; te->id = id; aeAddMillisecondsToNow(milliseconds,&te->when_sec,&te->when_ms); te->timeProc = proc; te->finalizerProc = finalizerProc; te->clientData = clientData; te->next = eventLoop->timeEventHead; eventLoop->timeEventHead = te; return id; }
/* 在eventLoop中添加时间事件,创建的时间为当前时间加上自己传入的时间 */ long long aeCreateTimeEvent(aeEventLoop *eventLoop, long long milliseconds, aeTimeProc *proc, void *clientData, aeEventFinalizerProc *finalizerProc) { long long id = eventLoop->timeEventNextId++; aeTimeEvent *te; te = zmalloc(sizeof(*te)); if (te == NULL) return AE_ERR; te->id = id; aeAddMillisecondsToNow(milliseconds,&te->when_sec,&te->when_ms); te->timeProc = proc; te->finalizerProc = finalizerProc; te->clientData = clientData; //新加的变为timeEvent的头部 te->next = eventLoop->timeEventHead; eventLoop->timeEventHead = te; //返回新创建的时间事件的id return id; }
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; }
/*** * 创建并注册定时事件到eventLoop中 * @eventLoop[IN]: 新建定时事件要添加到的事件循环处理器 * @milliseconds[IN]: 定时时间的定时值, 即多少毫秒后定时事件超时 * @proc[IN]: 定时事件就绪处理函数 * @clientData[IN]: 用户私有数据 * @finalizerProc[IN]: 定时事件删除处理函数 * @return: 新建定时器事件的ID */ long long aeCreateTimeEvent(aeEventLoop *eventLoop, long long milliseconds, aeTimeProc *proc, void *clientData, aeEventFinalizerProc *finalizerProc) { /* 下一个定时器ID, 初始时,eventLoop的timeEventNextId为0, 即第一个定时器的ID为0 * 这里可以看到, eventLoop是非线程安全的, 建议一个线程一个eventLoop */ long long id = eventLoop->timeEventNextId++; aeTimeEvent *te; /* 定时事件结构体分配内存 */ te = zmalloc(sizeof(*te)); if (te == NULL) return AE_ERR; /* 以下操作初始化定时事件 */ /* 定时器ID */ te->id = id; /* 将定时的时间值加到当前绝对时间值, 从而得到定时器超时的一个未来绝对时间值 */ aeAddMillisecondsToNow(milliseconds,&te->when_sec,&te->when_ms); /* 定时事件超时处理函数 */ te->timeProc = proc; /* 定时事件删除处理函数 */ te->finalizerProc = finalizerProc; /* 用户私有数据, 通过处理函数传回 */ te->clientData = clientData; /* 将定时事件添加到事件循环定时事件链表的头部 */ te->next = eventLoop->timeEventHead; eventLoop->timeEventHead = te; return id; }
// 处理时间事件 // 所有满足条件的时间事件都会被执行 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 事件处理器指针 * */ 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; }
/*** * 进行一次定时事件处理 * @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). * * 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 */ }
/* 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; }
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; }