• 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 }
  • 相关阅读:
    UIWebView 视频播放获取开始播放和结束播放通知
    显示图像数据的高级接口 UIImage
    如何跳到系统设置里的WiFi界面
    Objective-C 去掉NSString 前后中空格
    iOS 属性修饰符的区别
    iOS 线程锁同步机制
    XCode 6 以后使用编程处理一些图片效果
    iOS 精益编程
    iOS7以后UITextView 技巧
    2016年12月英语六级阅读真题及答案 第3套
  • 原文地址:https://www.cnblogs.com/likui360/p/5298080.html
Copyright © 2020-2023  润新知