redis文件事件结构体

  1. /* File event structure */  
  2. /* 文件事件结构体 */  
  3. typedef struct aeFileEvent {  
  4.     //只为读事件或者写事件中的1种  
  5.     int mask; /* one of AE_(READABLE|WRITABLE) */  
  6.     //读方法  
  7.     aeFileProc *rfileProc;  
  8.     //写方法  
  9.     aeFileProc *wfileProc;  
  10.     //客户端数据  
  11.     void *clientData;  
  12. } aeFileEvent;  
  13.   
  14. /* Time event structure */  
  15. /* 时间事件结构体 */  
  16. typedef struct aeTimeEvent {  
  17.     //时间事件id  
  18.     long long id; /* time event identifier. */  
  19.     //时间秒数  
  20.     long when_sec; /* seconds */  
  21.     //时间毫秒  
  22.     long when_ms; /* milliseconds */  
  23.     //时间事件中的处理函数  
  24.     aeTimeProc *timeProc;  
  25.     //被删除的时候将会调用的方法  
  26.     aeEventFinalizerProc *finalizerProc;  
  27.     //客户端数据  
  28.     void *clientData;  
  29.     //时间结构体内的下一个结构体  
  30.     struct aeTimeEvent *next;  
  31. } aeTimeEvent;  
  32.   
  33. /* A fired event */  
  34. /* fired结构体,用来表示将要被处理的文件事件 */  
  35. typedef struct aeFiredEvent {  
  36.     //文件描述符id  
  37.     int fd;  
  38.     int mask;  
  39. } aeFiredEvent;  
FireEvent只是用来标记要处理的文件Event。

这些事件都存在于一个aeEventLoop的结构体内:

  1. /* State of an event based program */  
  2. typedef struct aeEventLoop {  
  3.     //目前创建的最高的文件描述符  
  4.     int maxfd;   /* highest file descriptor currently registered */  
  5.     int setsize; /* max number of file descriptors tracked */  
  6.     //下一个时间事件id  
  7.     long long timeEventNextId;  
  8.     time_t lastTime;     /* Used to detect system clock skew */  
  9.     //3种事件类型  
  10.     aeFileEvent *events; /* Registered events */  
  11.     aeFiredEvent *fired; /* Fired events */  
  12.     aeTimeEvent *timeEventHead;  
  13.     //事件停止标志符  
  14.     int stop;  
  15.     //这里存放的是event API的数据,包括epoll,select等事件  
  16.     void *apidata; /* This is used for polling API specific data */  
  17.     aeBeforeSleepProc *beforesleep;  
  18. } aeEventLoop;  
在每种事件内部,都有定义相应的处理函数,把函数当做变量一样存在结构体中。下面看下ae.c中的一些API的组成:

  1. /* Prototypes */  
  2. aeEventLoop *aeCreateEventLoop(int setsize); /* 创建aeEventLoop,内部的fileEvent和Fired事件的个数为setSize个 */  
  3. void aeDeleteEventLoop(aeEventLoop *eventLoop); /* 删除EventLoop,释放相应的事件所占的空间 */  
  4. void aeStop(aeEventLoop *eventLoop); /* 设置eventLoop中的停止属性为1 */  
  5. int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask,  
  6.         aeFileProc *proc, void *clientData); /* 在eventLoop中创建文件事件 */  
  7. void aeDeleteFileEvent(aeEventLoop *eventLoop, int fd, int mask); /* 删除文件事件 */  
  8. int aeGetFileEvents(aeEventLoop *eventLoop, int fd); //根据文件描述符id,找出文件的属性,是读事件还是写事件  
  9. long long aeCreateTimeEvent(aeEventLoop *eventLoop, long long milliseconds,  
  10.         aeTimeProc *proc, void *clientData,  
  11.         aeEventFinalizerProc *finalizerProc); /* 在eventLoop中添加时间事件,创建的时间为当前时间加上自己传入的时间 */  
  12. int aeDeleteTimeEvent(aeEventLoop *eventLoop, long long id); //根据时间id,删除时间事件,涉及链表的操作  
  13. int aeProcessEvents(aeEventLoop *eventLoop, int flags); /* 处理eventLoop中的所有类型事件 */  
  14. int aeWait(int fd, int mask, long long milliseconds); /* 让某事件等待 */  
  15. void aeMain(aeEventLoop *eventLoop); /* ae事件执行主程序 */  
  16. char *aeGetApiName(void);  
  17. void aeSetBeforeSleepProc(aeEventLoop *eventLoop, aeBeforeSleepProc *beforesleep); /* 每次eventLoop事件执行完后又重新开始执行时调用 */  
  18. int aeGetSetSize(aeEventLoop *eventLoop); /* 获取eventLoop的大小 */  
  19. int aeResizeSetSize(aeEventLoop *eventLoop, int setsize); /* EventLoop重新调整大小 */ 



在了解了3种事件模型的原理之后,我们看看ae.c在Redis中是如何调用的呢,

  1. //这里存放的是event API的数据,包括epoll,select等事件  
  2.     void *apidata; /* This is used for polling API specific data */  
就是上面这个属性,在上面的4种事件中,分别对应着3个文件,分别为ae_poll.c,ae_select.c,但是他们的API结构是类似的,我举其中一个例子,epoll的例子,首先都会有此事件特定的结构体:
  1. typedef struct aeApiState {  
  2.     int epfd;  
  3.     struct epoll_event *events;  
  4. } 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)  
在创建的时候赋值到eventloop的API data里面去:
  1. state->epfd = epoll_create(1024); /* 1024 is just a hint for the kernel */  
  2.    if (state->epfd == -1) {  
  3.        zfree(state->events);  
  4.        zfree(state);  
  5.        return -1;  
  6.    }  
  7.    //最后将state的数据赋值到eventLoop的API data中  
  8.    eventLoop->apidata = state;  
  9.    return 0;  
在取出事件的poll方法的时候是这些方法的一个区分点:
  1. static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) {  
  2.     aeApiState *state = eventLoop->apidata;  
  3.     int retval, numevents = 0;  
  4.   
  5.     retval = epoll_wait(state->epfd,state->events,eventLoop->setsize,  
  6.             tvp ? (tvp->tv_sec*1000 + tvp->tv_usec/1000) : -1);  
  7.     if (retval > 0) {  
  8. ..... 


aeCreateFileEvent

    对于创建文件事件,需要传入一个该事件对应的处理程序,当事件发生时,会调用对应的回调函数。这里设计的aeFileEvent结构体就是将事件源(FD),事件,事件处理程序关联起来

zmalloc除了提供标准的zamlloczcalloczrealloczfree功能之外还提供了dump内存数据到字符串的函数zstrdup,获得已经使用的内存总量的zmalloc_used_memory函数以及设置内存溢出处理函数的zmalloc_set_oom_handler。同时还提供了用于获得系统中的RSS,即程序所占用的实际的物理内存大小



猜你喜欢

转载自blog.csdn.net/tuxedolinux/article/details/80317123