Redis事件管理(一)
Redis统一的时间管理器,同时管理文件事件和定时器,
这个管理器的定义:
#if defined(__APPLE__) #define HAVE_TASKINFO 1 #endif /* Test for backtrace() */ #if defined(__APPLE__) || (defined(__linux__) && defined(__GLIBC__)) #define HAVE_BACKTRACE 1 #endif /* Test for polling API */ #ifdef __linux__ #define HAVE_EPOLL 1 #endif #if (defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined (__NetBSD__) #define HAVE_KQUEUE 1 #endif #ifdef __sun #include <sys/feature_tests.h> #ifdef _DTRACE_VERSION #define HAVE_EVPORT 1 #endif #endif /*检查具体使用哪个时间模型,Redis支持四个事件模型*/ #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
#define AE_NONE 0 /*该状态表示事件中该位置没使用*/ #define AE_READABLE 1/*设置了读事件*/ #define AE_WRITABLE 2/*设置了写事件*/ #define AE_FILE_EVENTS 1/*需要监控文件的读事件*/ #define AE_TIME_EVENTS 2/*需要监控文件的写事件*/ #define AE_ALL_EVENTS (AE_FILE_EVENTS|AE_TIME_EVENTS)/*读写事件同事监控*/ #define AE_DONT_WAIT 4/*处理事件时是否设置延迟时间*/
定时器结构体和文件事件结构体
1 /* File event structure */ 2 typedef struct aeFileEvent 3 { 4 int mask; /*需要监控的读写事件标志位*/ 5 aeFileProc *rfileProc;/*读写事件处理函数*/ 6 aeFileProc *wfileProc; 7 void *clientData;/*事件参数*/ 8 } aeFileEvent; 9 10 /* Time event structure */ 11 typedef struct aeTimeEvent 12 { 13 long long id; /*定时器事件的ID*/ 14 long when_sec; /*触发的秒*/ 15 long when_ms; /*触发的毫秒*/ 16 aeTimeProc *timeProc;/*指定处理函数*/ 17 aeEventFinalizerProc *finalizerProc;/*// 定时事件清理函数,当删除定时事件的时候会被调用*/ 18 void *clientData; 19 struct aeTimeEvent *next;/*下一个定时器对象,整体采用链表维护,作者好像知道链表维护的效率不是很高,推荐使用跳表,为啥不推荐使用红黑树嘞。*/ 20 } aeTimeEvent;
事件管理器的定义,在结构体中维护了两个数组,一个存放设置的文件描述符和设置,一个存放经过检测,满足条件的文件描述符和对应的触发状态,在处理的时候直接处理
fired中的数据就好。
typedef struct aeEventLoop { int maxfd; /*事件管理器能管理的文件描述符的最大值*/ int setsize; /*管理器能管理的文件描述符的个数*/ long long timeEventNextId; /*定时器用的*/ time_t lastTime; /*定时器最后一次处理时间,定时器中用的,防止修改了系统时间,影响了定时器的判断。*/ aeFileEvent *events; /*原始事件数组,这里面存放的是开始的文件事件,保存文件描述符,需要监控的事件等信息*/ aeFiredEvent *fired; /*触发事件数组,这里面放的是经过系统判断,有对应事件发生的文件描述符的存放数组,和上面一样,都采用数组维护*/ aeTimeEvent *timeEventHead;/*定时器链表*/ int stop;/*该事件管理器是否有效*/ void *apidata; /*因为事件管理器支持很多模型,每个模型都有自己的特殊数据格式,这个变量就是用来存储模型自己的数据,拿epoll举个例子,这个地方会存储aeApiState节点的信息*/ aeBeforeSleepProc *beforesleep; } aeEventLoop;
具体的接口函数:
/*创建一个事件管理器,需要初始化文件事件,触发事件,定时器事件等,stop值默认为0,最大文件描述符值为-1,并将所有的文件描述符的监控事件类型设置为NULL。 */
1 aeEventLoop *aeCreateEventLoop(int setsize) 2 { 3 aeEventLoop *eventLoop; 4 int i; 5 6 if ((eventLoop = zmalloc(sizeof(*eventLoop))) == NULL) 7 goto err; 8 eventLoop->events = zmalloc(sizeof(aeFileEvent)*setsize);/*给文件事件申请空间*/ 9 eventLoop->fired = zmalloc(sizeof(aeFiredEvent)*setsize); 10 if (eventLoop->events == NULL || eventLoop->fired == NULL) 11 goto err; 12 eventLoop->setsize = setsize;/*设置可处理的事件个数*/ 13 eventLoop->lastTime = time(NULL); 14 eventLoop->timeEventHead = NULL;/*定时器链表初始化*/ 15 eventLoop->timeEventNextId = 0; 16 eventLoop->stop = 0;/*设置停用表示为无效*/ 17 eventLoop->maxfd = -1;/*设置最大文件描述符的初始化*/ 18 eventLoop->beforesleep = NULL; 19 if (aeApiCreate(eventLoop) == -1) 20 goto err; 21 /* Events with mask == AE_NONE are not set. So let's initialize the 22 * vector with it. */ 23 for (i = 0; i < setsize; i++) 24 eventLoop->events[i].mask = AE_NONE;/*AE_NONE代表这个事件没有启用*/ 25 return eventLoop; 26 27 err: 28 if (eventLoop) { 29 zfree(eventLoop->events); 30 zfree(eventLoop->fired); 31 zfree(eventLoop); 32 } 33 return NULL; 34 }
/*返回管理器能管理的事件的个数*/ int aeGetSetSize(aeEventLoop *eventLoop) { return eventLoop->setsize; }
1 /*重置管理器能管理的事件个数*/ 2 int aeResizeSetSize(aeEventLoop *eventLoop, int setsize) 3 { 4 int i; 5 /*如果新大小等于现有的大小则直接返回成*/ 6 if (setsize == eventLoop->setsize) 7 return AE_OK; 8 /*如果重置的大小小于当前管理器中最大的文件描述符大小,则不能进行重置,否则会丢失已经注册的事件。*/ 9 if (eventLoop->maxfd >= setsize) 10 return AE_ERR; 11 /*调用已经封装好的重置大小函数*/ 12 if (aeApiResize(eventLoop,setsize) == -1) 13 return AE_ERR; 14 /*重置记录内存块大小*/ 15 eventLoop->events = zrealloc(eventLoop->events,sizeof(aeFileEvent)*setsize); 16 eventLoop->fired = zrealloc(eventLoop->fired,sizeof(aeFiredEvent)*setsize); 17 eventLoop->setsize = setsize; 18 19 /*将新增部分的事件标记置为无效*/ 20 for (i = eventLoop->maxfd+1; i < setsize; i++) 21 eventLoop->events[i].mask = AE_NONE; 22 return AE_OK; 23 }
1 /*删除事件控制器*/ 2 void aeDeleteEventLoop(aeEventLoop *eventLoop) 3 { 4 /*调用封装好的删除事件函数*/ 5 aeApiFree(eventLoop); 6 /*逐个释放内存*/ 7 zfree(eventLoop->events); 8 zfree(eventLoop->fired); 9 zfree(eventLoop); 10 }
/*增加一个文件事件,参数为事件控制器,文件描述符,事件掩码,处理函数,函数参数,对一个描述符添加多个事件的时候要挨个添加*/ 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; }
1 /*删除文件事件中指定文件描述符的指定事件*/ 2 void aeDeleteFileEvent(aeEventLoop *eventLoop, int fd, int mask) 3 { 4 /*检查文件描述符是否超限*/ 5 if (fd >= eventLoop->setsize) return; 6 /*检查该位置是否启用了*/ 7 aeFileEvent *fe = &eventLoop->events[fd]; 8 if (fe->mask == AE_NONE) return; 9 10 /*先把事件从处理模型中去掉*/ 11 aeApiDelEvent(eventLoop, fd, mask); 12 fe->mask = fe->mask & (~mask);/*去掉读写掩码*/ 13 /*检查是否需要更新管理器中的最大文件描述符的值*/ 14 if (fd == eventLoop->maxfd && fe->mask == AE_NONE) 15 { 16 /* Update the max fd */ 17 int j; 18 /*从最大位置反向找启用的位置,更新最大文件描述符*/ 19 for (j = eventLoop->maxfd-1; j >= 0; j--) 20 if (eventLoop->events[j].mask != AE_NONE) break; 21 eventLoop->maxfd = j; 22 } 23 }
/*获取某个文件描述符的注册事件*/ int aeGetFileEvents(aeEventLoop *eventLoop, int fd) { if (fd >= eventLoop->setsize) return 0; aeFileEvent *fe = &eventLoop->events[fd]; return fe->mask; }
1 /*处理控制器中的所有时间,算是最核心的函数了,参数2为要处理的事件类型*/ 2 int aeProcessEvents(aeEventLoop *eventLoop, int flags) 3 { 4 int processed = 0, numevents; 5 6 /*参数2设置的是不处理任何事件就直接返回*/ 7 if (!(flags & AE_TIME_EVENTS) && !(flags & AE_FILE_EVENTS)) 8 return 0; 9 10 /* Note that we want call select() even if there are no 11 * file events to process as long as we want to process time 12 * events, in order to sleep until the next time event is ready 13 * to fire. */ 14 if (eventLoop->maxfd != -1 || ((flags & AE_TIME_EVENTS) && !(flags & AE_DONT_WAIT))) 15 { 16 int j; 17 aeTimeEvent *shortest = NULL; 18 struct timeval tv, *tvp; 19 20 /*处理文件时间事件,先检查是否需要设置延时时间, 21 延时时间的计算方法,如果有定时器事件,就设定定时器事件里面距离触发事件最近的时间? 22 否则设置成NULL,无限期等待。*/ 23 if (flags & AE_TIME_EVENTS && !(flags & AE_DONT_WAIT)) 24 shortest = aeSearchNearestTimer(eventLoop); 25 if (shortest) 26 { 27 long now_sec, now_ms; 28 29 /* Calculate the time missing for the nearest 30 * timer to fire. */ 31 aeGetTime(&now_sec, &now_ms); 32 tvp = &tv; 33 tvp->tv_sec = shortest->when_sec - now_sec; 34 if (shortest->when_ms < now_ms) 35 { 36 tvp->tv_usec = ((shortest->when_ms+1000) - now_ms)*1000; 37 tvp->tv_sec --; 38 } 39 else 40 { 41 tvp->tv_usec = (shortest->when_ms - now_ms)*1000; 42 } 43 if (tvp->tv_sec < 0) tvp->tv_sec = 0; 44 if (tvp->tv_usec < 0) tvp->tv_usec = 0; 45 } 46 else 47 { 48 /* If we have to check for events but need to return 49 * ASAP because of AE_DONT_WAIT we need to set the timeout 50 * to zero */ 51 if (flags & AE_DONT_WAIT) 52 { 53 tv.tv_sec = tv.tv_usec = 0; 54 tvp = &tv; 55 } 56 else 57 { 58 /* Otherwise we can block */ 59 tvp = NULL; /* wait forever */ 60 } 61 } 62 63 /*调用统一的事件监控接口,并处理*/ 64 numevents = aeApiPoll(eventLoop, tvp); 65 for (j = 0; j < numevents; j++) 66 { 67 aeFileEvent *fe = &eventLoop->events[eventLoop->fired[j].fd]; 68 int mask = eventLoop->fired[j].mask; 69 int fd = eventLoop->fired[j].fd; 70 int rfired = 0; 71 72 /* note the fe->mask & mask & ... code: maybe an already processed 73 * event removed an element that fired and we still didn't 74 * processed, so we check if the event is still valid. */ 75 if (fe->mask & mask & AE_READABLE) 76 { 77 rfired = 1; 78 fe->rfileProc(eventLoop,fd,fe->clientData,mask); 79 } 80 if (fe->mask & mask & AE_WRITABLE) 81 { 82 if (!rfired || fe->wfileProc != fe->rfileProc) 83 fe->wfileProc(eventLoop,fd,fe->clientData,mask); 84 } 85 processed++; 86 } 87 } 88 /*检查处理定时器事件*/ 89 if (flags & AE_TIME_EVENTS) 90 processed += processTimeEvents(eventLoop); 91 92 return processed; /* return the number of processed file/time events */ 93 }
1 /*事件管理器总函数,没啥可说的*/ 2 void aeMain(aeEventLoop *eventLoop) 3 { 4 eventLoop->stop = 0; 5 while (!eventLoop->stop) 6 { 7 if (eventLoop->beforesleep != NULL) 8 eventLoop->beforesleep(eventLoop); 9 aeProcessEvents(eventLoop, AE_ALL_EVENTS); 10 } 11 }