Redis事件管理(三)

 Redis的事件管理和定时器的管理都是自己来实现的,Redis的事件管理分为两部分,一部分是封装了系统的异步事件API,还有一部分是在这基础上封装了一个通用的事件管理器,根据具体的系统来决定具体使用哪个异步管理API。

先来说说Redis支持哪些异步的系统API。Redis内部封装了epoll,evport,kqueue,select这四个原始的事件管理器。

那epoll举个例子解析一下吧。

1 typedef struct aeApiState 
2 {
3     int epfd; //文件描述符
4     struct epoll_event *events;//epoll实例
5 } aeApiState;

这个结构体封装了一个具体的事件实例。

封装的接口函数:

1 static int aeApiCreate(aeEventLoop *eventLoop) //创建一个事件管理器
2 static int aeApiResize(aeEventLoop *eventLoop, int setsize) //重置事件管理器管理事件的个数
3 static void aeApiFree(aeEventLoop *eventLoop) //删除一个事件管理器
4 static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask)//向事件管理器中添加一个事件 
5 static void aeApiDelEvent(aeEventLoop *eventLoop, int fd, int delmask) //从时间管理器中删除一个事件
6 static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp)//激活事件管理器,返回已经触发的事件的个数
7 static char *aeApiName(void) //获取当前使用的是什么事件模型
1 static int aeApiCreate(aeEventLoop *eventLoop) //创建一个事件管理器
 1 /*创建成功返回0,否则返回-1*/
 2 static int aeApiCreate(aeEventLoop *eventLoop) 
 3 {
 4     aeApiState *state = zmalloc(sizeof(aeApiState));
 5 
 6     if (!state) return -1;
 7     /*直接按size申请内存*/
 8     state->events = zmalloc(sizeof(struct epoll_event) * eventLoop->setsize);
 9     /*事件内存失败时要释放结构体的内存,防止出现内存泄露*/
10     if (!state->events) 
11     {
12         zfree(state);
13         return -1;
14     }
15     /*创建epoll描述符,如果创建失败,记得把上面申请的内存释放掉*/
16     state->epfd = epoll_create(1024); /* 1024 is just a hint for the kernel */
17     if (state->epfd == -1) 
18     {
19         zfree(state->events);
20         zfree(state);
21         return -1;
22     }
23     eventLoop->apidata = state;
24     return 0;
25 }
2 static int aeApiResize(aeEventLoop *eventLoop, int setsize) //重置事件管理器管理事件的个数
/*重置可接受事件的个数,这个函数不能直接调用,因为没有检查新size和旧size的大小关系,如果小了,直接重置会出问题*/
static int aeApiResize(aeEventLoop *eventLoop, int setsize) 
{
    aeApiState *state = eventLoop->apidata;

    state->events = zrealloc(state->events, sizeof(struct epoll_event)*setsize);
    return 0;
}
4 static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask)//向事件管理器中添加一个事件
 1 /*向epoll中增加事件,需要注册新的文件描述符和需要监控的事件类型*/
 2 static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask) 
 3 {
 4     aeApiState *state = eventLoop->apidata;
 5     struct epoll_event ee;
 6     /*因为epoll的维护是用数组维护的,通过下标的方式可以直接访问,省时省力。如果这个节点已经激活了,那新事件添加就好了*/
 7     int op = eventLoop->events[fd].mask == AE_NONE ? EPOLL_CTL_ADD : EPOLL_CTL_MOD;
 8 
 9     ee.events = 0;
10     mask |= eventLoop->events[fd].mask; /* Merge old events */
11     if (mask & AE_READABLE) ee.events |= EPOLLIN;
12     if (mask & AE_WRITABLE) ee.events |= EPOLLOUT;
13     ee.data.u64 = 0; /* avoid valgrind warning */
14     ee.data.fd = fd;
15     if (epoll_ctl(state->epfd,op,fd,&ee) == -1) return -1;
16     return 0;
17 }
6 static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp)//激活事件管理器,返回已经触发的事件的个数
/*获取事件队列*/
static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) 
{
    aeApiState *state = eventLoop->apidata;
    int retval, numevents = 0;

    retval = epoll_wait(state->epfd,state->events,eventLoop->setsize,tvp ? (tvp->tv_sec*1000 + tvp->tv_usec/1000) : -1);
    if (retval > 0) 
    {
        int j;

        numevents = retval;
        /*将满足条件的文件描述符和状态保存到fired中,后期逐个处理*/
        for (j = 0; j < numevents; j++) 
        {
            int mask = 0;
            struct epoll_event *e = state->events+j;

            if (e->events & EPOLLIN) mask |= AE_READABLE;
            if (e->events & EPOLLOUT) mask |= AE_WRITABLE;
            if (e->events & EPOLLERR) mask |= AE_WRITABLE;
            if (e->events & EPOLLHUP) mask |= AE_WRITABLE;
            eventLoop->fired[j].fd = e->data.fd;
            eventLoop->fired[j].mask = mask;
        }
    }
    return numevents;
}

 

posted @ 2016-03-20 14:32  扫地猿  阅读(432)  评论(0编辑  收藏  举报