码迷,mamicode.com
首页 > 其他好文 > 详细

对于redis框架的理解(三)

时间:2016-05-09 12:29:00      阅读:251      评论:0      收藏:0      [点我收藏+]

标签:

上一篇讲完了initServer的大体流程,其中aeCreateEventLoop(),这个函数

没有详细说明,我们在这一篇里讲述Ae.h和Ae.c, 这里面的api阐述了如何创建

eventLoop和添加文件读写事件等等。

ae.h中的解释

//文件读写事件回调函数
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);

//文件事件回调函数
 typedef struct aeFileEvent {
     int mask; /* one of AE_(READABLE|WRITABLE) */ //文件事件类型 读/写
     aeFileProc *rfileProc;
     aeFileProc *wfileProc;
     void *clientData;
 } aeFileEvent;

 /* A fired event */
 typedef struct aeFiredEvent {
     int fd;    ////已出现的事件的文件号对应的事件描述在aeEventLoop.events[]中的下标
     int mask;  //文件事件类型 AE_WRITABLE||AE_READABLE
 } aeFiredEvent;

 typedef struct aeTimeEvent {
     long long id; /* time event identifier. */  //由aeEventLoop.timeEventNextId进行管理
     long when_sec; /* seconds */
     long when_ms; /* milliseconds */
     aeTimeProc *timeProc;
     aeEventFinalizerProc *finalizerProc;
     void *clientData;
     struct aeTimeEvent *next;
 } aeTimeEvent;

 /* State of an event based program */
 typedef struct aeEventLoop {
     int maxfd;   //监听的最大文件号  
     int setsize; //跟踪的文件描述符最大数量
     long long timeEventNextId;     //定时器事件的ID编号管理(分配ID号所用)
     time_t lastTime;     /* Used to detect system clock skew */
     aeFileEvent *events; //注册的文件事件,这些是需要进程关注的文件
     aeFiredEvent *fired;  //poll结果,待处理的文件事件的文件号和事件类型  
     aeTimeEvent *timeEventHead; //定时器时间链表
     int stop;   //时间轮询是否结束?
     void *apidata;  //polling API 特殊的数据
     aeBeforeSleepProc *beforesleep;  //休眠前的程序
 } aeEventLoop;

 /* Prototypes */
 //创建eventLoop结构
 aeEventLoop *aeCreateEventLoop(int setsize);
 //删除eventloop
 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);
 //等待millionseconds直到文件描述符可读或者可写
 int aeWait(int fd, int mask, long long milliseconds);
 //ae事件轮询主函数
 void aeMain(aeEventLoop *eventLoop);
 //获取当前网络模型
 char *aeGetApiName(void);
 //进程休眠前回调函数
 void aeSetBeforeSleepProc(aeEventLoop *eventLoop, 
     aeBeforeSleepProc *beforesleep);
 //获取eventloop所有的事件个数
 int aeGetSetSize(aeEventLoop *eventLoop);
 //重新设置eventloop事件个数
 int aeResizeSetSize(aeEventLoop *eventLoop, int setsize);

 ae.cpp中,一个函数一个函数解析

 

//定义了几个宏,根据不同的宏加载
//不同的网络模型
#ifdef HAVE_EVPORT
#include "ae_evport.c"
#else
#ifdef HAVE_EPOLL
#include "ae_epoll.c"
#else
#ifdef HAVE_KQUEUE
#include "ae_kqueue.c"
#else
#include "ae_select.c"
#endif
#endif
#endif

 aeCreateEventLoop,主要负责eventloop结构的创建和初始化,以及模型的初始化

aeEventLoop *aeCreateEventLoop(int setsize) {
    aeEventLoop *eventLoop;
    int i;
    //创建eventloop
    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;
    //将不同模式的api注册到eventloop里
    if (aeApiCreate(eventLoop) == -1) goto err;
    /* Events with mask == AE_NONE are not set. So let‘s initialize the
     * vector with it. */
    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;
}

//事件队列大小和重置 

//获取eventloop事件队列大小
int aeGetSetSize(aeEventLoop *eventLoop) {
    return eventLoop->setsize;
}

//重新设置大小
int aeResizeSetSize(aeEventLoop *eventLoop, int setsize) {
    int i;

    if (setsize == eventLoop->setsize) return AE_OK;
    if (eventLoop->maxfd >= setsize) return AE_ERR;
    //不同的网络模型调用不同的resize
    if (aeApiResize(eventLoop,setsize) == -1) return AE_ERR;
    //重新开辟空间
    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. */
    //重新初始化事件类型
    for (i = eventLoop->maxfd+1; i < setsize; i++)
        eventLoop->events[i].mask = AE_NONE;
    return AE_OK;
}

 删除eventloop和stop事件轮询

//删除eventloop结构
void aeDeleteEventLoop(aeEventLoop *eventLoop) {
    aeApiFree(eventLoop);
    zfree(eventLoop->events);
    zfree(eventLoop->fired);
    zfree(eventLoop);
}

//设置eventloop停止标记
void aeStop(aeEventLoop *eventLoop) {
    eventLoop->stop = 1;
}

 创建监听事件

//创建监听事件
int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask,
                      aeFileProc *proc, void *clientData)
{
    //判断fd大于eventloop设置的事件队列大小
    if (fd >= eventLoop->setsize) {
        errno = ERANGE;
        return AE_ERR;
    }

    //取出对应的aeFileEvent事件
    aeFileEvent *fe = &eventLoop->events[fd];

    //添加读写事件到不同的模型
    if (aeApiAddEvent(eventLoop, fd, mask) == -1)
        return AE_ERR;
    //文件类型按位或
    fe->mask |= mask;
    //根据最终的类型设置读写回调函数
    if (mask & AE_READABLE) fe->rfileProc = proc;
    if (mask & AE_WRITABLE) fe->wfileProc = proc;
    //fe中读写操作的clientdata
    fe->clientData = clientData;
    //如果fd大于当前最大的eventLoop maxfdfd
    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;
    //网络模型里删除对应的事件
    aeApiDelEvent(eventLoop, fd, mask);
    //清除对应的类型标记
    fe->mask = fe->mask & (~mask);
    //如果删除的fd是maxfd,并且对应的事件为空,那么更新maxfd
    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;
}

事件派发函数

//派发事件的函数
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;

   
    //为了休眠,直到有时间事件触发,即便是没有文件事件处理,我们也会
    //调用对应的事件时间
    //这部分不是很清楚,知道大体意思是设置时间,
    //为了aeApiPoll设置等待的时间
    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 */
            }
        }
        //调用不同的网络模型poll事件
        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++;
        }
    }
    /* Check time events */
    //处理所有定时器事件
    if (flags & AE_TIME_EVENTS)
        processed += processTimeEvents(eventLoop);

    return processed; /* return the number of processed file/time events */
}

 

/等待millionseconds,直到有可读或者可写事件触发
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) {
        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;
    }
}                                    
//ae主函数
void aeMain(aeEventLoop *eventLoop) {
    //stop初始为0
    eventLoop->stop = 0;
    while (!eventLoop->stop) {
        //调用beforesleep函数
        if (eventLoop->beforesleep != NULL)
            eventLoop->beforesleep(eventLoop);
        //派发所有的事件
        aeProcessEvents(eventLoop, AE_ALL_EVENTS);
    }
}

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

//sleep之前的回调函数
void aeSetBeforeSleepProc(aeEventLoop *eventLoop, aeBeforeSleepProc *beforesleep) {
    eventLoop->beforesleep = beforesleep;
}

 

这就是ae文件里大体的几个api,其他的没理解的还在研究。

 

我的微信公众号:

技术分享

对于redis框架的理解(三)

标签:

原文地址:http://www.cnblogs.com/secondtonone1/p/5473324.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!