redis中epoll事件怎样与读写回调函数绑定

epoll多路分离机制虽然以数组的形式返回所有激活事件的fd及属性(读写),但没有指定对每个事件的操作。事实上,如果需要读写不同激活的fd,只能根据fd、属性来再次判断自己操作的是哪一个事件。在读操作的执行函数一致、写操作的执行函数一致时,这种做法是可行的。但如果读或写操作属性的事件具有不同的执行函数,就不能单纯根据事件的属性决定执行函数了。为了解决这个问题,redis提供了读写回调函数与注册事件绑定的方法,可以根据需求给相应的事件绑定相应的回调函数。

为了将fd与回调函数绑定,redis定义了aeFileEvent,如下:

/* File event structure */
typedef struct aeFileEvent {
    int mask; /* one of AE_(READABLE|WRITABLE|BARRIER) */
    aeFileProc *rfileProc;
    aeFileProc *wfileProc;
    void *clientData;
} aeFileEvent;

在aeFileEvent中,存储了事件的属性、读写回调函数、待操作的客户端数据。并且在初始化时,通过aeFileEvent定义了events数组。

我们知道epoll_wait可以得到的是激活事件的fd、mask数组,那如何将激活的fd与注册事件时的回调函数联系起来呢?

先看一下添加文件事件时的函数,如下:

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

在aeCreateFileEvent函数中,根据添加事件的fd,将读写回调函数写到events[fd]中。也就是说,如果知道了fd,就可以在events中找到对应的读写回调函数了。这样就解决了fd与回调函数的联系问题。

最后,再看看redis中怎样使用注册fd与回调函数绑定的方式执行回调函数,如下:

int aeProcessEvents(aeEventLoop *eventLoop, int flags)
{
    ...
        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 fired = 0; /* Number of events fired for current fd. */

            int invert = fe->mask & AE_BARRIER;

            if (!invert && fe->mask & mask & AE_READABLE) {
                fe->rfileProc(eventLoop,fd,fe->clientData,mask);
                fired++;
            }

            /* 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->mask & mask & AE_READABLE) {
                if (!fired || fe->wfileProc != fe->rfileProc) {
                    fe->rfileProc(eventLoop,fd,fe->clientData,mask);
                    fired++;
                }
            }

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

在aeProcessEvents中,aeApiEpoll会将激活事件的fd、mask存储到fired数组中;

然后遍历fired中所有的激活事件,并根据索引fd定位到events的该fd的注册位置;

之后根据fired中的mask,决定使用events[fd]中的哪个回调函数,如果该fd同时具有读写属性,会先进行读操作,在进行写操作;如果设置了invert,则执行顺序相反。

总结:

1,事件在注册时,在events数组的fd索引处定义了读写回调函数;

2,epoll_wait可以返回激活事件的fd、mask;

3,在events[fd]处,根据mask的属性选择执行回调函数。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值