/* 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. * 1,定时任务,时间修正 2,io事件循环 3,处理定时任务 返回io事件+定时事件 处理的个数 * 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 */ }
/* 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 事件处理器指针 * 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[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 */ }