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将新建的时间节点加入链表头。
- 3.7.4 event_request_timer:安排定时事件
- 定时事件
- 定时事件
- ASP定时触发事件
- Delphi定时Showmessage事件
- 定时周期事件
- 控制台定时执行事件
- mysql EVENT定时事件
- Ext4 定时事件
- mysql 创建定时事件
- mysql 创建定时事件
- mysql 创建定时事件
- mysql 事件(定时任务)
- mysql 定时事件(定时任务)
- 【规划】4月安排
- 安排
- Mysql编写定时任务事件
- Android 中的定时事件使用
- [POJ 2391]Ombrophobic Bovines[最大流][二分答案]
- 使用ToolRunner运行Hadoop程序基本原理分析
- poj1458 LCS
- C#像QQ一样隐藏窗体
- 全国和国际天气预报API免费接口
- 3.7.4 event_request_timer:安排定时事件
- Spring源代码解析(二):IoC容器在Web容器中的启动
- C#创建不规则窗体-图片
- hdu1167 dp
- 介绍call,callee,caller,apply的区别与应用
- 在eclipse中查看android源码
- 每天laravel-20160704|CahceHit
- 要不要接这个项目?
- C#messagebox汇总