3.7.4 event_request_timer:安排定时事件

来源:互联网 发布:全网视频自动采集源码 编辑:程序博客网 时间:2024/05/08 16:11

定时事件指的是预计在某段时间过后将要发生的事件。与读写事件不同,定时事件不通过I/O多路复用函数触发。

 

postfix对定时事件要进行两个基本操作:安排和执行。

 

首先使用event_request_timer函数安排定时事件,也就重置或新建EVENT_TIMER结构体,并将其加入链表表头。

 

在event_loop事件循环中将执行定时事件的回调函数。event_loop事件循环既执行定时事件,也执行I/O时间。多路复用函数的等待参数可能会影响时间事件的执行,所以要小心设置该参数,避免多路复用函数的阻塞耽误了定时事件的执行。

 

postfix使用了很多定时事件,典型的如qmgr和pickup模块会被定时唤醒,则需要用event_request_timer函数为其安排定时事件。定时事件在event_loop中执行。

 

在event_init中,初始化了一个RING节点构成的双向链表。这个链表在event_loop函数中将转化为EVENT_TIMER链表。我们看一下相关的结构体和宏:

/util/event.c501  /* 502   *Timer events. Timer requests are kept sorted, in a circular list. We use 503   *the RING abstraction, so we get to use a couple ugly macros. 504   * 505   *When a call-back function adds a timer request, we label the request with 506   *the event_loop() call instance that invoked the call-back. We use this to 507   *prevent zero-delay timer requests from running in a tight loop and 508   *starving I/O events. 509   */ 510typedef struct EVENT_TIMER EVENT_TIMER; 511 512struct EVENT_TIMER { 513    time_t  when;                       /* when event is wanted*/ 514     EVENT_NOTIFY_TIME_FN callback;      /* callback function */ 515    char   *context;                    /* callback context */ 516    long    loop_instance;              /* event_loop() call instance */ 517    RING    ring;                       /* linkage */ 518}; 519 520static RING event_timer_head;          /* timer queue head */522 #define RING_TO_TIMER(r) \523         ((EVENT_TIMER *)((void *) (r) - offsetof(EVENT_TIMER, ring))) 529#define FIRST_TIMER(head) \ 530        (ring_succ(head) != (head) ? RING_TO_TIMER(ring_succ(head)) : 0)

 

    EVENT_TIMER结构体定义了回调函数,在定时事件到来时触发。

在RING_TO_TIMER宏中将RING结构体通过offsetof强转为EVENT_TIMER结构体。

在FIRST_TIMER宏中可以看到,只有当对event_timer_head链表进行过增加节点操作后,才会进行RING_TO_TIMER宏所定义的转化。

 

对event_timer_head链表增加节点,也就是安排新的时间事件(或更新现有时间事件)的函数是event_request_timer:

/util/event.c892 /* event_request_timer - (re)set timer */ 893 894 time_t event_request_timer(EVENT_NOTIFY_TIME_FN callback, void *context, intdelay) 895 { 896    const char *myname = "event_request_timer"; 897    RING   *ring; 898    EVENT_TIMER *timer; 899 900    if (EVENT_INIT_NEEDED()) 901        event_init(); 902 903    /* 904     * Sanity checks. 905     */ 906    if (delay < 0) 907        msg_panic("%s: invalid delay: %d", myname, delay); 908 909    /* 910     * Make sure we schedule this event at the right time. 911     */ 912    time(&event_present); 913 914    /* 915     * See if they are resetting an existing timer request. If so, take the 916     * request away from the timer queue so that it can be inserted at the 917     * right place. 918     */ 919    FOREACH_QUEUE_ENTRY(ring, &event_timer_head) { 920        timer = RING_TO_TIMER(ring); 921        if (timer->callback == callback && timer->context ==context) { 922            timer->when = event_present + delay; 923            timer->loop_instance = event_loop_instance; 924            ring_detach(ring); 925            if (msg_verbose > 2) 926                 msg_info("%s: reset 0x%lx0x%lx %d", myname, 927                          (long) callback,(long) context, delay); 928            break; 929        } 930    } 931 932    /* 933     * If not found, schedule a new timer request. 934     */ 935    if (ring == &event_timer_head) { 936        timer = (EVENT_TIMER *) mymalloc(sizeof(EVENT_TIMER)); 937        timer->when = event_present + delay; 938        timer->callback = callback; 939        timer->context = context; 940        timer->loop_instance = event_loop_instance; 941        if (msg_verbose > 2) 942            msg_info("%s: set 0x%lx 0x%lx %d", myname,943                      (long) callback, (long)context, delay); 944    }<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> </span>

919-944 如果某个时间事件是已经存在的,即在特定上下文中挂载特定回调函数的EVENT_TIMER节点存在,则重置其超时时间等项,否则建立新的EVENT_TIMER节点。

FOREACH_QUEUE_ENTRY宏定义如下:

#defineFOREACH_QUEUE_ENTRY(entry, head) \         for (entry = ring_succ(head); entry !=(head); entry = ring_succ(entry))  945 946    /* 947     * Timer requests are kept sorted to reduce lookup overhead in the event 948     * loop. 949     * 950     * XXX Append the new request after existing requests for the same time 951     * slot. The event_loop() routine depends on this to avoid starving I/O 952     * events when a call-back function schedules a zero-delay timer request. 953     */ 954    FOREACH_QUEUE_ENTRY(ring, &event_timer_head) { 955        if (timer->when < RING_TO_TIMER(ring)->when) 956            break; 957    } 958    ring_prepend(ring, &timer->ring); 959 960    return (timer->when); 961 }

958 ring_prepend将新建的时间节点加入链表头。

0 0
原创粉丝点击