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