redis6.0.5之Ae阅读笔记-事件相关

******************************************************************************************
#define AE_OK 0
#define AE_ERR -1

#define AE_NONE 0       /* No events registered. */ 没有事件注册
#define AE_READABLE 1   /* Fire when descriptor is readable. */ 当描述符可读时触发
#define AE_WRITABLE 2   /* Fire when descriptor is writable. */ 当描述符可写时触发
#define AE_BARRIER 4    /* With WRITABLE, never fire the event if the
                           READABLE event already fired in the same event
                           loop iteration. Useful when you want to persist
                           things to disk before sending replies, and want
                           to do that in a group fashion. */
屏障                          
对于WRITABLE,如果可读事件已在同一事件循环迭代中激发,则永远不要激发该事件。
当希望在发送回复之前将内容持久化到磁盘,并且希望以组方式执行此操作时,此功能非常有用。

#define AE_FILE_EVENTS (1<<0)  文件事件
#define AE_TIME_EVENTS (1<<1)  时间事件
#define AE_ALL_EVENTS (AE_FILE_EVENTS|AE_TIME_EVENTS) 所有事件
#define AE_DONT_WAIT (1<<2) 
#define AE_CALL_BEFORE_SLEEP (1<<3)
#define AE_CALL_AFTER_SLEEP (1<<4)

#define AE_NOMORE -1
#define AE_DELETED_EVENT_ID -1

/* Macros */ 宏定义 不使用的情况下不报警
#define AE_NOTUSED(V) ((void) V)

struct aeEventLoop;

/* Types and data structures */ 类型和数据结构
文件事件处理
typedef void aeFileProc(struct aeEventLoop *eventLoop, int fd, void *clientData, int mask);
时间事件处理
typedef int aeTimeProc(struct aeEventLoop *eventLoop, long long id, void *clientData);
事件终结处理
typedef void aeEventFinalizerProc(struct aeEventLoop *eventLoop, void *clientData);
在睡眠前处理
typedef void aeBeforeSleepProc(struct aeEventLoop *eventLoop);

/* File event structure */ 文件事件结构
typedef struct aeFileEvent {
    int mask; /* one of AE_(READABLE|WRITABLE|BARRIER) */  事件标志
    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 *prev;  前一个事件
    struct aeTimeEvent *next;  下一个事件
    int refcount; /* refcount to prevent timer events from being
             * freed in recursive time event calls. */
refcount防止在递归时间事件调用中释放计时器事件
} aeTimeEvent;

/* A fired event */ 触发事件
typedef struct aeFiredEvent {
    int fd;      文件描述符
    int mask;   标志
} aeFiredEvent;

/* State of an event based program */ 基于事件程序的状态
typedef struct aeEventLoop {
    int maxfd;   /* highest file descriptor currently registered */ 当前注册的最高文件描述符
    int setsize; /* max number of file descriptors tracked */ 跟踪的最大文件描述符数
    long long timeEventNextId;  下一个时间事件的ID
    time_t lastTime;     /* Used to detect system clock skew */ 上次时间 用于检测系统时钟偏移
    aeFileEvent *events; /* Registered events */ 文件事件结构体
    aeFiredEvent *fired; /* Fired events */      触发事件结构体
    aeTimeEvent *timeEventHead;  时间事件结构体 
    int stop;
    void *apidata; /* This is used for polling API specific data */ 这用于轮询特定于API的数据
    aeBeforeSleepProc *beforesleep; 
    aeBeforeSleepProc *aftersleep;
    int flags;
} aeEventLoop;

/* Prototypes */ 原型
aeEventLoop *aeCreateEventLoop(int setsize); 创建循环事件
void aeDeleteEventLoop(aeEventLoop *eventLoop); 删除注册的循环事件
void aeStop(aeEventLoop *eventLoop); 停止监听事件
int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask,
        aeFileProc *proc, void *clientData);创建文件事件
void aeDeleteFileEvent(aeEventLoop *eventLoop, int fd, int mask);删除注册的文件事件
int aeGetFileEvents(aeEventLoop *eventLoop, int fd);获取注册的文件事件
long long aeCreateTimeEvent(aeEventLoop *eventLoop, long long milliseconds,
        aeTimeProc *proc, void *clientData,
        aeEventFinalizerProc *finalizerProc); 创建时间事件
int aeDeleteTimeEvent(aeEventLoop *eventLoop, long long id);删除时间事件
int aeProcessEvents(aeEventLoop *eventLoop, int flags); 处理事件
int aeWait(int fd, int mask, long long milliseconds); 等待事件
void aeMain(aeEventLoop *eventLoop); 事件主程序
char *aeGetApiName(void); 获取API名字
void aeSetBeforeSleepProc(aeEventLoop *eventLoop, aeBeforeSleepProc *beforesleep);
void aeSetAfterSleepProc(aeEventLoop *eventLoop, aeBeforeSleepProc *aftersleep);
int aeGetSetSize(aeEventLoop *eventLoop); 获取注册的事件数
int aeResizeSetSize(aeEventLoop *eventLoop, int setsize);注册事件扩容
void aeSetDontWait(aeEventLoop *eventLoop, int noWait); 取消等待

#endif

*****************************************************************************************************
/* A simple event-driven programming library. Originally I wrote this code
 * for the Jim's event-loop (Jim is a Tcl interpreter) but later translated
 * it in form of a library for easy reuse.
一个简单的事件驱动程序库。开始redis作者写这个代码是为了Jim的事件循环(Jim是一个Tcl的解释器)
但后来将其翻译成库的形式以便于重用
 */

/* Include the best multiplexing layer supported by this system.
 * The following should be ordered by performances, descending. */
包括该系统支持的最佳复用层。 以下内容应按性能降序排列。
#ifdef HAVE_EVPORT   Solaris系统
#include "ae_evport.c"
#else
    #ifdef HAVE_EPOLL  linux的EPOLL
    #include "ae_epoll.c"
    #else
        #ifdef HAVE_KQUEUE  FreeBSD
        #include "ae_kqueue.c"
        #else
        #include "ae_select.c" 最普通大的情况,采用select
        #endif
    #endif
#endif

创建一个循环事件
aeEventLoop *aeCreateEventLoop(int setsize) {
    aeEventLoop *eventLoop;
    int i;

    if ((eventLoop = zmalloc(sizeof(*eventLoop))) == NULL) goto err;
    eventLoop->events = zmalloc(sizeof(aeFileEvent)*setsize); 文件事件
    eventLoop->fired = zmalloc(sizeof(aeFiredEvent)*setsize);  触发事件
    if (eventLoop->events == NULL || eventLoop->fired == NULL) goto err;
    eventLoop->setsize = setsize;
    eventLoop->lastTime = time(NULL);当前时间
    eventLoop->timeEventHead = NULL;
    eventLoop->timeEventNextId = 0;
    eventLoop->stop = 0;
    eventLoop->maxfd = -1;
    eventLoop->beforesleep = NULL;
    eventLoop->aftersleep = NULL;
    eventLoop->flags = 0;
    if (aeApiCreate(eventLoop) == -1) goto err;  设置各种不同API初始的状态
    /* Events with mask == AE_NONE are not set. So let's initialize the
     * vector with it. */
     当事件的标志为AE_NONE,表示没有设置。让我们用它来初始化向量
    for (i = 0; i < setsize; i++)
        eventLoop->events[i].mask = AE_NONE;
    return eventLoop;

err:
    if (eventLoop) { 非空,需要释放
        zfree(eventLoop->events);
        zfree(eventLoop->fired);
        zfree(eventLoop);
    }
    return NULL;
}

/* Return the current set size. */
返回当前设置的事件数量
int aeGetSetSize(aeEventLoop *eventLoop) {
    return eventLoop->setsize;
}

/* Tells the next iteration/s of the event processing to set timeout of 0. */
通知事件处理的下一次迭代将超时设置为0
void aeSetDontWait(aeEventLoop *eventLoop, int noWait) {
    if (noWait) 不需要等待
        eventLoop->flags |= AE_DONT_WAIT; 设置不需要等待的标识
    else 需要等待
        eventLoop->flags &= ~AE_DONT_WAIT; 取消不需要等待的标识
}

/* Resize the maximum set size of the event loop.
调整事件循环的最大设置大小。
 * If the requested set size is smaller than the current set size, but
 * there is already a file descriptor in use that is >= the requested
 * set size minus one, AE_ERR is returned and the operation is not
 * performed at all.
如果请求设置的大小比当前设置的大小小,也就是说当前使用的最大文件描述符 大于等于 请求设置数量-1.
那么返回AE_ERR,不需要执行任何操作
 * Otherwise AE_OK is returned and the operation is successful. */
否则返回AE_OK,操作成功
int aeResizeSetSize(aeEventLoop *eventLoop, int setsize) {
    int i;

    if (setsize == eventLoop->setsize) return AE_OK;  如果两个数量相同,直接返回成功
    if (eventLoop->maxfd >= setsize) return AE_ERR; 
    当前注册最高的文件描述符 大于等于 当前请求设置的数量
    (这里就是上面解释所说,请求的数量小于原设置数量)
    
    if (aeApiResize(eventLoop,setsize) == -1) return AE_ERR;初始化api的状态

    eventLoop->events = zrealloc(eventLoop->events,sizeof(aeFileEvent)*setsize); 重新分配所需文件事件空间
    eventLoop->fired = zrealloc(eventLoop->fired,sizeof(aeFiredEvent)*setsize);  重新分配所需触发事件空间
    eventLoop->setsize = setsize;

    /* Make sure that if we created new slots, they are initialized with
     * an AE_NONE mask. */
    创建了新的插槽,我们需要用AE_NONE标志对他们进行初始化
    for (i = eventLoop->maxfd+1; i < setsize; i++)
        eventLoop->events[i].mask = AE_NONE;
    return AE_OK;
}

删除事件
void aeDeleteEventLoop(aeEventLoop *eventLoop) {
    aeApiFree(eventLoop); 释放api的中申请的空间
    zfree(eventLoop->events); 释放循环结构体中释放的空间
    zfree(eventLoop->fired);

    /* Free the time events list. */ 释放时间事件列表
    aeTimeEvent *next_te, *te = eventLoop->timeEventHead;
    while (te) {
        next_te = te->next;
        zfree(te);
        te = next_te;
    }
    zfree(eventLoop);
}

停止监听事件
void aeStop(aeEventLoop *eventLoop) {
    eventLoop->stop = 1;
}

创建文件事件
int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask,
        aeFileProc *proc, void *clientData)
{
    if (fd >= eventLoop->setsize) { 超过了设置的最大量
        errno = ERANGE;
        return AE_ERR;
    }
    aeFileEvent *fe = &eventLoop->events[fd];

    if (aeApiAddEvent(eventLoop, fd, mask) == -1) 添加具体操作api的相关事件
        return AE_ERR;
    fe->mask |= mask;
    if (mask & AE_READABLE) fe->rfileProc = proc;  文件事件处理函数
    if (mask & AE_WRITABLE) fe->wfileProc = proc;  
    fe->clientData = clientData; 客户数据
    if (fd > eventLoop->maxfd)  大于当前最大的描述符
        eventLoop->maxfd = fd; 更换最大描述符
    return AE_OK;
}

删除文件事件
void aeDeleteFileEvent(aeEventLoop *eventLoop, int fd, int mask)
{
    if (fd >= eventLoop->setsize) return; 如果传入的文件描述符 超过了当前设置的最大值,显然不存在,无需操作
    aeFileEvent *fe = &eventLoop->events[fd];
    if (fe->mask == AE_NONE) return; 如果没有实际赋过值,那就是初始化状态,无需处理

    /* We want to always remove AE_BARRIER if set when AE_WRITABLE
     * is removed. */
如果在删除AE_WRITABLE时设置了AE_BARRIER,我们希望始终删除它
    if (mask & AE_WRITABLE) mask |= AE_BARRIER;

    aeApiDelEvent(eventLoop, fd, mask); 删除具体API相关事件
    fe->mask = fe->mask & (~mask);
    if (fd == eventLoop->maxfd && fe->mask == AE_NONE) { 被删除的文件事件是最大的
        /* Update the max fd */ 更新最大的文件描述符
        int j;

        for (j = eventLoop->maxfd-1; j >= 0; j--) 在剩下的文件描述符中查找现在最大的
            if (eventLoop->events[j].mask != AE_NONE) break;
        eventLoop->maxfd = j;
    }
}

获取文件事件标志
int aeGetFileEvents(aeEventLoop *eventLoop, int fd) {
    if (fd >= eventLoop->setsize) return 0; 超过了设置的最大值(肯定没有事件),直接返回
    aeFileEvent *fe = &eventLoop->events[fd];

    return fe->mask;
}

获取时间
static void aeGetTime(long *seconds, long *milliseconds)
{
    struct timeval tv;

    gettimeofday(&tv, NULL);
    *seconds = tv.tv_sec;
    *milliseconds = tv.tv_usec/1000;
}

在当前时间上增加指定的时间
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) { 超过了1000,需要进位
        when_sec ++;
        when_ms -= 1000;
    }
    *sec = when_sec;
    *ms = when_ms;
}

创建时间事件
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; 用户数据
    te->prev = NULL;
    te->next = eventLoop->timeEventHead;
    te->refcount = 0;
    if (te->next)
        te->next->prev = te;
    eventLoop->timeEventHead = te;
    return id;
}

删除指定描述符的时间事件
int aeDeleteTimeEvent(aeEventLoop *eventLoop, long long id)
{
    aeTimeEvent *te = eventLoop->timeEventHead;
    while(te) {
        if (te->id == id) {
            te->id = AE_DELETED_EVENT_ID;
            return AE_OK;
        }
        te = te->next;
    }
    return AE_ERR; /* NO event with the specified ID found */ 找不到指定描述符的事件
}

/* Search the first timer to fire. 查找第一个定时器去触发
 * This operation is useful to know how many time the select can be
 * put in sleep without to delay any event.
此操作有助于了解select可以在不延迟任何事件的情况下处于睡眠状态的时间(话句话说就是 还剩多少时间会触发事件)
 * If there are no timers NULL is returned.
如果没有定时器,返回空
 * Note that's O(N) since time events are unsorted.
注意,这里的复杂度是O(N),因为时间事件没有排序
 * Possible optimizations (not needed by Redis so far, but...):
可能的优化(Redis目前不需要,但…)
 * 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).
1)按顺序插入事件,因此最近的事件就是头。这样更好,但是插入或删除的时间复杂度任然是O(N)
 * 2) Use a skiplist to have this operation as O(1) and insertion as O(log(N)).
2)使用跳表将此操作的时间复杂度变为O(1),将插入操作的时间复杂度变为O(log(N))
 */
查找最近的时间事件
static aeTimeEvent *aeSearchNearestTimer(aeEventLoop *eventLoop)
{
    aeTimeEvent *te = eventLoop->timeEventHead;
    aeTimeEvent *nearest = NULL;

    while(te) {
        if (!nearest || te->when_sec < nearest->when_sec || 先比秒  秒相同比毫秒
                (te->when_sec == nearest->when_sec &&
                 te->when_ms < nearest->when_ms))
            nearest = te;
        te = te->next;
    }
    return nearest;
}

/* 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;  将等待设置的秒设置为0, 这样剩下毫秒的时间很快到了就会执行。
            te = te->next;
        }
    }
    eventLoop->lastTime = now; 设置成系统时间

    te = eventLoop->timeEventHead;
    maxId = eventLoop->timeEventNextId-1;  当前最大的时间事件的ID
    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 a reference exists for this timer event,
             * don't free it. This is currently incremented
             * for recursive timerProc calls */
如果存在此计时器事件的引用,请不要释放它。对于递归timerProc调用,该值当前递增
            if (te->refcount) { 当前是递归调用,还不能释放
                te = next;
                continue;
            }
            if (te->prev) 存在前置节点
                te->prev->next = te->next;
            else
                eventLoop->timeEventHead = te->next;
            if (te->next) 存在后接节点
                te->next->prev = te->prev;
            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;
            te->refcount++;
            retval = te->timeProc(eventLoop, id, te->clientData); 进行处理
            te->refcount--;
            processed++;
            if (retval != AE_NOMORE) {
                aeAddMillisecondsToNow(retval,&te->when_sec,&te->when_ms);
            } else {
                te->id = AE_DELETED_EVENT_ID; 准备删除
            }
        }
        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 occurs (if any).
 处理每个挂起的时间事件,然后处理每个挂起的文件事件(可能由刚刚处理的时间事件回调注册)。
 如果没有特殊标志,函数将一直休眠,直到触发某个文件事件,或者下次事件发生时(如果有)
 *
 * If flags is 0, the function does nothing and returns.
如果标志为0,那么函数不做任何事情直接返回
 * if flags has AE_ALL_EVENTS set, all the kind of events are processed.
如果标志设置为AE_ALL_EVENTS,那么所有的事件都会被处理
 * if flags has AE_FILE_EVENTS set, file events are processed.
如果标志设置为AE_FILE_EVENTS,那么文件事件会被处理
 * if flags has AE_TIME_EVENTS set, time events are processed.
如果标志设置为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.
如果标志设置了AE_DONT_WAIT,则函数将尽快返回,直到所有可以不等待处理的事件都处理完毕。
 * if flags has AE_CALL_AFTER_SLEEP set, the aftersleep callback is called.
如果标志设置为AE_CALL_AFTER_SLEEP,那么aftersleep回调将会被调用
 * if flags has AE_CALL_BEFORE_SLEEP set, the beforesleep callback is called.
如果标志设置为AE_CALL_BEFORE_SLEEP,那么beforesleep回调将会被调用
 * 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. */
请注意,我们希望调用select,即使没有要处理的文件事件,只要我们希望处理时间事件,就可以一直休眠到下一次事件准备触发为止。
    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;

            /* How many milliseconds we need to wait for the next
             * time event to fire? */
            我们需要等待多少毫秒才能触发下一次事件
            long long ms =
                (shortest->when_sec - now_sec)*1000 +
                shortest->when_ms - now_ms;

            if (ms > 0) {
                tvp->tv_sec = ms/1000;
                tvp->tv_usec = (ms % 1000)*1000;
            } else {
                tvp->tv_sec = 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 */ 一直等待
            }
        }

        if (eventLoop->flags & AE_DONT_WAIT) {
            tv.tv_sec = tv.tv_usec = 0;
            tvp = &tv;
        }

        if (eventLoop->beforesleep != NULL && flags & AE_CALL_BEFORE_SLEEP)
            eventLoop->beforesleep(eventLoop); 在睡眠之前回调

        /* Call the multiplexing API, will return only on timeout or when
         * some event fires. */ 调用多路复用API,将仅在超时或某些事件触发时返回。
        numevents = aeApiPoll(eventLoop, tvp);  返回需要处理的事件数目

        /* After sleep callback. */ 在睡眠之后回调
        if (eventLoop->aftersleep != NULL && flags & AE_CALL_AFTER_SLEEP)
            eventLoop->aftersleep(eventLoop);

        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 fired = 0; /* Number of events fired for current fd. */ 为当前fd触发的事件数。

            /* Normally we execute the readable event first, and the writable
             * event laster. This is useful as sometimes we may be able
             * to serve the reply of a query immediately after processing the
             * query.
通常我们首先执行可读事件,最后执行可写事件。
这很有用,因为有时我们可以在处理查询后立即提供查询的答复。
             * However if AE_BARRIER is set in the mask, our application is
             * asking us to do the reverse: never fire the writable event
             * after the readable. In such a case, we invert the calls.
             * This is useful when, for instance, we want to do things
             * in the beforeSleep() hook, like fsynching a file to disk,
             * before replying to a client. */
然而,如果AE_BARRIER在标志中被设置,我们的应用程序要求我们做相反的事情:不要触发读之后的写事件。
在这种情况下,我们需要将调用倒转过来。这个很有用,举例来说,我们想要在beforeSleep的钩子中做一些事情,
例如在回复客户端之前刷新一些文件到磁盘
            int invert = fe->mask & AE_BARRIER;

            /* 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.
注意“fe->mask&mask&…”代码:可能一个已经处理的事件删除了一个触发的元素,
而我们仍然没有处理,所以我们检查该事件是否仍然有效。
             * Fire the readable event if the call sequence is not
             * inverted. */  如果调用序列未反转,则触发可读事件。
            if (!invert && fe->mask & mask & AE_READABLE) {
                fe->rfileProc(eventLoop,fd,fe->clientData,mask);
                fired++;
                fe = &eventLoop->events[fd]; /* Refresh in case of resize. */  调整大小时刷新
            }

            /* Fire the writable event. */ 触发写事件
            if (fe->mask & mask & AE_WRITABLE) {
                if (!fired || fe->wfileProc != fe->rfileProc) {
                    fe->wfileProc(eventLoop,fd,fe->clientData,mask);
                    fired++;
                }
            }

            /* If we have to invert the call, fire the readable event now
             * after the writable one. */
             如果我们要掉转调用顺序,在写事件之后触发读事件
            if (invert) {
                fe = &eventLoop->events[fd]; /* Refresh in case of resize. */ 调整大小后刷新
                if ((fe->mask & mask & AE_READABLE) &&
                    (!fired || fe->wfileProc != fe->rfileProc))
                {
                    fe->rfileProc(eventLoop,fd,fe->clientData,mask);
                    fired++;
                }
            }

            processed++; 处理数++
        }
    }
    /* Check time events */ 检查时间事件
    if (flags & AE_TIME_EVENTS)
        processed += processTimeEvents(eventLoop); 处理时间事件

    return processed; /* return the number of processed file/time events */ 返回已处理的文件/时间事件数
}

/* Wait for milliseconds until the given file descriptor becomes
 * writable/readable/exception */
等待给定的毫秒数直到给定的文件描述符变成 可写/可读/异常
int aeWait(int fd, int mask, long long milliseconds) {
    struct pollfd pfd;
    int retmask = 0, retval;

    memset(&pfd, 0, sizeof(pfd));
    pfd.fd = fd;
    if (mask & AE_READABLE) pfd.events |= POLLIN;
    if (mask & AE_WRITABLE) pfd.events |= POLLOUT;

    if ((retval = poll(&pfd, 1, milliseconds))== 1) {  等待milliseconds,返回的事件
        if (pfd.revents & POLLIN) retmask |= AE_READABLE;
        if (pfd.revents & POLLOUT) retmask |= AE_WRITABLE;
        if (pfd.revents & POLLERR) retmask |= AE_WRITABLE;
        if (pfd.revents & POLLHUP) retmask |= AE_WRITABLE;
        return retmask;  返回的标志
    } else {
        return retval;  错误信息
    }
}

事件的主程序
void aeMain(aeEventLoop *eventLoop) {
    eventLoop->stop = 0;
    while (!eventLoop->stop) { 触发事件不停止,一直循环等待事件触发
        aeProcessEvents(eventLoop, AE_ALL_EVENTS|
                                   AE_CALL_BEFORE_SLEEP|
                                   AE_CALL_AFTER_SLEEP);
    }
}

获取api具体的名字
char *aeGetApiName(void) {
    return aeApiName();
}

设置睡眠前回调函数
void aeSetBeforeSleepProc(aeEventLoop *eventLoop, aeBeforeSleepProc *beforesleep) {
    eventLoop->beforesleep = beforesleep;
}

设置睡眠后回调函数
void aeSetAfterSleepProc(aeEventLoop *eventLoop, aeBeforeSleepProc *aftersleep) {
    eventLoop->aftersleep = aftersleep;
}
*****************************************************************************************************

 

上一篇:1353. 最多可以参加的会议数目


下一篇:vue框架vant组件中events的使用方法