Redis源码分析系列九:aeMain(server.el)

很高兴,我们历尽艰难险阻,来到了函数aeMain(server.el)

这个函数是主循环函数,源码如下:

void aeMain(aeEventLoop *eventLoop)
{
    eventLoop->stop = 0;
    while (!eventLoop->stop) {
        if (eventLoop->beforesleep != NULL)
            eventLoop->beforesleep(eventLoop);
        aeProcessEvents(eventLoop, AE_ALL_EVENTS);
    }
}

 

~~~~~~~~~~~~~~

eventLoop->stop = 0;//设置stop标志为0

 eventLoop->beforesleep(eventLoop);还不到分析的时候,暂且不分析。 

毕竟现在还没有数据,现在分析也没法分析,后面就可以了。

aeProcessEvents(eventLoop, AE_ALL_EVENTS);//处理各种事件

让我们去关注如何执行的。

~~~~~~~~~~~~~~~~~

/* Nothing to do? return ASAP */
    if (!(flags & AE_TIME_EVENTS) && !(flags & AE_FILE_EVENTS)) return 0;

//如果任何一种事件都不处理,则返回

其实这个函数是处理2种行为的,来看具体的原理。

有些地方暂时不说,

主要先关注aeApiPoll(eventLoop, tvp);

显然是从之前的监听端口中accept出一个连接来处理。

这个函数内部通过retval = epoll_wait(state->epfd,state->events,eventLoop->setsize,
            tvp ? (tvp->tv_sec*1000 + tvp->tv_usec/1000) : -1);

来获取可accept的对象。

重点关注下面两行:

eventLoop->fired[j].fd = e->data.fd;
eventLoop->fired[j].mask = mask;

也就是先把可以处理的socket存储在fired数组里。

~~~~~~~~~~~~~~~

接着执行下面这个代码:

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++;
        }

我们来看具体的执行过程。

aeFileEvent *fe = &eventLoop->events[eventLoop->fired[j].fd];

这个代码的作用是取出events对象,如果读者这个时候去观察events数组,就知道之前这个数组的样子是这样的:

aeFileEvent *events; /* Registered events */
 //( server.maxclients+REDIS_EVENTLOOP_FDSET_INCR )  *  sizeof(aeFileEvent)
 //下标与句柄ID相同
 //且每个event.mask = AE_NONE|AE_READABLE 、、
 //           .rfileProc = acceptTcpHandler
    //.clientData= NULL

也就是说,存储了mask和读处理函数。

~~~~~~

int mask = eventLoop->fired[j].mask;

mask标志了当前socket可以做的事情。

 int fd = eventLoop->fired[j].fd;、、标志了当前socket的句柄号。

~~~~

if (fe->mask & mask & AE_READABLE)
   {
    //如果可以读

    
                rfired = 1;//记忆是否曾经有可读的socket

    
                fe->rfileProc(eventLoop,fd,fe->clientData,mask);

                    //触发读函数。
 }
对于监听server socket来说,读函数为:acceptTcpHandler

显然里面会调用accept来获取客户连接服务器的连接并加入到server->el.apidata.fd中去监听。

洗澡,然后睡觉!

转载于:https://my.oschina.net/qiangzigege/blog/170670

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值