Libubox 是 OpenWrt 的一个必备的基础库,包含大小端转换、链表、MD5 、定时器等实用工具基础库。 Libubox提供的定时器工具用来实现一些简单的定时任务十分方便。 下面介绍其定时器工具的使用方法:
定时器工具主要数据结构和函数
struct uloop_timeout
{
struct list_head list;
bool pending;
uloop_timeout_handler cb;
struct timeval time;
};
struct uloop_timeout 用来描述一个定时器,cb 是该定时器的超时回调函数,time 是定时器超时时间,它是一个未来的时间。
int uloop_timeout_add(struct uloop_timeout *timeout);
int uloop_timeout_set(struct uloop_timeout *timeout, int msecs);
int uloop_timeout_cancel(struct uloop_timeout *timeout);
int uloop_timeout_remaining(struct uloop_timeout *timeout);
Libubox 提供的定时器都是一次性定时器,如果需要循环触发,需要重复设置定时器。
定时器工具原理
uloop.c 中有维护一条定时器链表timeouts
static struct list_head timeouts = LIST_HEAD_INIT(timeouts);
uloop_timeout_set 和uloop_timeout_add 会将新的定时器添加到链表,并且新的定时器按照超时时间由近到远的顺序被添加进链表
- timer1 3s后超时
- timer2 6s后超时
- timer3 10后超时
它的实现方式如下:
int uloop_timeout_add(struct uloop_timeout *timeout)
{
struct uloop_timeout *tmp;
struct list_head *h = &timeouts;
if (timeout->pending)
return -1;
list_for_each_entry(tmp, &timeouts, list) {
if (tv_diff(&tmp->time, &timeout->time) > 0) {
h = &tmp->list;
break;
}
}
list_add_tail(&timeout->list, h);
timeout->pending = true;
return 0;
}
uloop_run 中会遍历定时器链表,对于已经超时的定时器会执行其回调函数。
static void uloop_process_timeouts(struct timeval *tv)
{
struct uloop_timeout *t;
while (!list_empty(&timeouts)) {
t = list_first_entry(&timeouts, struct uloop_timeout, list);
if (tv_diff(&t->time, tv) > 0)
break;
uloop_timeout_cancel(t);
if (t->cb)
t->cb(t);
}
}
uloop_process_timeouts() 每次只处理timeouts 中第一个成员(不是一次性处理完链表中所有的定时器),但是这个函数本身会被循环调用。
定时器工具实例
如下实例定义一个超时时间为2s的定时器u_tim ,并在回调函数中重新设置超时时间,使其循环触发。 循环3次后,取消这个定时器。
#include "stdio.h"
#include "uloop.h"
#include <sys/time.h>
static void u_tim_cb(struct uloop_timeout *timeout)
{
static int cnt = 0;
printf("Enter timer cb! second %ld cnt=%d\n",timeout->time.tv_sec,cnt);
uloop_timeout_set(timeout, 2000);
cnt++;
if( cnt == 3 )
{
uloop_timeout_cancel(timeout);
printf("timer cancel!\n");
}
}
static struct uloop_timeout u_tim = {
.cb = u_tim_cb,
};
int main()
{
uloop_init();
uloop_timeout_set(&u_tim, 2000);
printf("Enter uloop run!\n");
uloop_run();
return 0;
}
|