- /* File event structure */
- /* 文件事件结构体 */
- typedef struct aeFileEvent {
- //只为读事件或者写事件中的1种
- int mask; /* one of AE_(READABLE|WRITABLE) */
- //读方法
- aeFileProc *rfileProc;
- //写方法
- aeFileProc *wfileProc;
- //客户端数据
- void *clientData;
- } aeFileEvent;
- /* Time event structure */
- /* 时间事件结构体 */
- typedef struct aeTimeEvent {
- //时间事件id
- long long id; /* time event identifier. */
- //时间秒数
- long when_sec; /* seconds */
- //时间毫秒
- long when_ms; /* milliseconds */
- //时间事件中的处理函数
- aeTimeProc *timeProc;
- //被删除的时候将会调用的方法
- aeEventFinalizerProc *finalizerProc;
- //客户端数据
- void *clientData;
- //时间结构体内的下一个结构体
- struct aeTimeEvent *next;
- } aeTimeEvent;
- /* A fired event */
- /* fired结构体,用来表示将要被处理的文件事件 */
- typedef struct aeFiredEvent {
- //文件描述符id
- int fd;
- int mask;
- } aeFiredEvent;
这些事件都存在于一个aeEventLoop的结构体内:
- /* State of an event based program */
- typedef struct aeEventLoop {
- //目前创建的最高的文件描述符
- int maxfd; /* highest file descriptor currently registered */
- int setsize; /* max number of file descriptors tracked */
- //下一个时间事件id
- long long timeEventNextId;
- time_t lastTime; /* Used to detect system clock skew */
- //3种事件类型
- aeFileEvent *events; /* Registered events */
- aeFiredEvent *fired; /* Fired events */
- aeTimeEvent *timeEventHead;
- //事件停止标志符
- int stop;
- //这里存放的是event API的数据,包括epoll,select等事件
- void *apidata; /* This is used for polling API specific data */
- aeBeforeSleepProc *beforesleep;
- } aeEventLoop;
- /* Prototypes */
- aeEventLoop *aeCreateEventLoop(int setsize); /* 创建aeEventLoop,内部的fileEvent和Fired事件的个数为setSize个 */
- void aeDeleteEventLoop(aeEventLoop *eventLoop); /* 删除EventLoop,释放相应的事件所占的空间 */
- void aeStop(aeEventLoop *eventLoop); /* 设置eventLoop中的停止属性为1 */
- int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask,
- aeFileProc *proc, void *clientData); /* 在eventLoop中创建文件事件 */
- void aeDeleteFileEvent(aeEventLoop *eventLoop, int fd, int mask); /* 删除文件事件 */
- int aeGetFileEvents(aeEventLoop *eventLoop, int fd); //根据文件描述符id,找出文件的属性,是读事件还是写事件
- long long aeCreateTimeEvent(aeEventLoop *eventLoop, long long milliseconds,
- aeTimeProc *proc, void *clientData,
- aeEventFinalizerProc *finalizerProc); /* 在eventLoop中添加时间事件,创建的时间为当前时间加上自己传入的时间 */
- int aeDeleteTimeEvent(aeEventLoop *eventLoop, long long id); //根据时间id,删除时间事件,涉及链表的操作
- int aeProcessEvents(aeEventLoop *eventLoop, int flags); /* 处理eventLoop中的所有类型事件 */
- int aeWait(int fd, int mask, long long milliseconds); /* 让某事件等待 */
- void aeMain(aeEventLoop *eventLoop); /* ae事件执行主程序 */
- char *aeGetApiName(void);
- void aeSetBeforeSleepProc(aeEventLoop *eventLoop, aeBeforeSleepProc *beforesleep); /* 每次eventLoop事件执行完后又重新开始执行时调用 */
- int aeGetSetSize(aeEventLoop *eventLoop); /* 获取eventLoop的大小 */
- int aeResizeSetSize(aeEventLoop *eventLoop, int setsize); /* EventLoop重新调整大小 */
在了解了3种事件模型的原理之后,我们看看ae.c在Redis中是如何调用的呢,
- //这里存放的是event API的数据,包括epoll,select等事件
- void *apidata; /* This is used for polling API specific data */
- typedef struct aeApiState {
- int epfd;
- struct epoll_event *events;
- } aeApiState;
- static int aeApiCreate(aeEventLoop *eventLoop)
- static int aeApiResize(aeEventLoop *eventLoop, int setsize)
- static void aeApiFree(aeEventLoop *eventLoop)
- static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask)
- static void aeApiDelEvent(aeEventLoop *eventLoop, int fd, int delmask)
- static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp)
- static char *aeApiName(void)
- state->epfd = epoll_create(1024); /* 1024 is just a hint for the kernel */
- if (state->epfd == -1) {
- zfree(state->events);
- zfree(state);
- return -1;
- }
- //最后将state的数据赋值到eventLoop的API data中
- eventLoop->apidata = state;
- return 0;
- 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) {
- .....
aeCreateFileEvent
对于创建文件事件,需要传入一个该事件对应的处理程序,当事件发生时,会调用对应的回调函数。这里设计的aeFileEvent结构体就是将事件源(FD),事件,事件处理程序关联起来
zmalloc除了提供标准的zamlloc,zcalloc,zrealloc,zfree功能之外还提供了dump内存数据到字符串的函数zstrdup,获得已经使用的内存总量的zmalloc_used_memory函数以及设置内存溢出处理函数的zmalloc_set_oom_handler。同时还提供了用于获得系统中的RSS,即程序所占用的实际的物理内存大小。