Redis实现了自己的一套和libevent类似的事件驱动机制,主要用于处理时间事件和文件事件。文件事件底层主要是指网络IO事件的处理,底层使用的可能是select,epoll,或者是kqueue。Redis使用自己实现的AE而不是像memcache使用的libevent使得其性能更好,因为libevent为了其通用性增加了很多扩展功能显然会降低使用它的性能。
主要结构体
typedef struct aeFileEvent {//文件事件结构体
int mask; /* one of AE_(READABLE|WRITABLE) */
aeFileProc *rfileProc;
aeFileProc *wfileProc;
void *clientData;
} aeFileEvent;
时间事件结构体
typedef struct aeTimeEvent {
long long id; /* time event identifier. */
long when_sec; /* seconds */
long when_ms; /* milliseconds */
aeTimeProc *timeProc;
aeEventFinalizerProc *finalizerProc;
void *clientData;
struct aeTimeEvent *next;
} aeTimeEvent;
固定的事件
typedef struct aeFiredEvent {
int fd;
int mask;
} aeFiredEvent;
事件处理器
/* State of an event based program */
typedef struct aeEventLoop{
int maxfd; /* highest filedescriptor currently registered当前注册的事件的最大文件描述符 */
int setsize; /* max number of file descriptors tracked */
long long timeEventNextId;
time_t lastTime; /* Used todetect system clock skew */
aeFileEvent *events;/* Registered events */(setsize个文件事件)
aeFiredEvent *fired; /* Fired events */(setsize个文件事件)
aeTimeEvent *timeEventHead;
int stop;//stop=1表示停止
void *apidata; /* This is used for polling API specific data */
aeBeforeSleepProc *beforesleep;
} aeEventLoop;
函数 prototypes
aeEventLoop *aeCreateEventLoop(intsetsize);
分配给aeEventLoop对象的空间和aeFileEvent对象的一个数组空间(数组大小为setsize),aeFiredEvent对象的一个数组空间。并完成aeEventLoop对象的其他字段的初始化。
for (i = 0; i < setsize; i++)
eventLoop->events[i].mask = AE_NONE;
还包含 aeApiCreate(eventLoop)
int aeGetSetSize(aeEventLoop *eventLoop);
获取aeEventLoop字段中的setsize的值。
int aeResizeSetSize(aeEventLoop *eventLoop,int setsize);
void aeDeleteEventLoop(aeEventLoop*eventLoop);
调用aeApiFree(eventLoop),并释放eventloop->events和eventloop->fired空间,最后释放eventloop所占的空间。
void aeStop(aeEventLoop *eventLoop);
令eventLoop的字段stop=1
文件事件相关的函数
int aeCreateFileEvent(aeEventLoop*eventLoop, int fd, int mask,
aeFileProc *proc, void *clientData);
将mask, proc, clientData信息更新到eventLoop->events[fd]上,并且fd不能大于eventLoop->setsize。并调用(aeApiAddEvent(eventLoop, fd, mask)
并判断,如果fd > eventLoop->maxfd,则eventLoop->maxfd= fd;
void aeDeleteFileEvent(aeEventLoop *eventLoop,int fd, int mask);(mask为屏蔽码)
修改eventLoop->events[fd]的mask字段
aeFileEvent *fe =&eventLoop->events[fd]; fe->mask = fe->mask & (~mask);
并判断,如果其更新之后的mask字段为AE_NONE,则更新max fd
并调用aeApiDelEvent(eventLoop, fd, mask);
int aeGetFileEvents(aeEventLoop *eventLoop,int fd);
返回eventLoop->events[fd]中的mask字段
时间事件相关的函数
static void aeGetTime(long *seconds, long*milliseconds)
获取当前事件的秒数,和毫秒数,保存在参数seconds,milliseconds中
static void aeAddMillisecondsToNow(longlong milliseconds, long *sec, long *ms)
在目前的时间上加上milliseconds毫秒。计算之后的时间保存在参数sec 和ms上
long long aeCreateTimeEvent(aeEventLoop*eventLoop, long long milliseconds,
aeTimeProc *proc, void *clientData,
aeEventFinalizerProc *finalizerProc);
创建时间事件,并对aeTimeEvent对象进行初始化,并将eventLoop->teimEventHead = te;
int aeDeleteTimeEvent(aeEventLoop*eventLoop, long long id);
删除指定id的时间事件,并调用te->finalizerProc(eventLoop, te->clientData)进行处理。
static aeTimeEvent*aeSearchNearestTimer(aeEventLoop *eventLoop)
static int processTimeEvents(aeEventLoop*eventLoop)
int aeProcessEvents(aeEventLoop *eventLoop,int flags);
int aeWait(int fd, int mask, long long milliseconds);
利用poll() 等待milliseconds直到给定的fd变成可读、可写,或者出错。
void aeMain(aeEventLoop *eventLoop);
如果eventLoop->stop=0则一直循环。循环体里执行
eventLoop->beforesleep(eventLoop);
aeProcessEvents(eventLoop, AE_ALL_EVENTS);//AE_ALL_EVENTS为文件事件和时间事件
char *aeGetApiName(void);
调用aeApiName()
void aeSetBeforeSleepProc(aeEventLoop*eventLoop, aeBeforeSleepProc *beforesleep);
eventLoop->beforesleep= beforesleep;