【openwrt】libubox组件——uloop_timeout

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);

//添加一个定时器,并设置超时时间,单位ms
int uloop_timeout_set(struct uloop_timeout *timeout, int msecs);

//删除一个定时器
int uloop_timeout_cancel(struct uloop_timeout *timeout);

//计算一个定时器还有多久超时,单位ms
int uloop_timeout_remaining(struct uloop_timeout *timeout);
Libubox 提供的定时器都是一次性定时器,如果需要循环触发,需要重复设置定时器。

定时器工具原理

uloop.c中有维护一条定时器链表timeouts

static struct list_head timeouts = LIST_HEAD_INIT(timeouts);

uloop_timeout_setuloop_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;
	
	//遍历timeouts链表,找到超时时间比新增的定时器长的成员
	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中第一个成员(不是一次性处理完链表中所有的定时器),但是这个函数本身会被循环调用。

  • uloop_timeout_cancel
int uloop_timeout_cancel(struct uloop_timeout *timeout)
{
	if (!timeout->pending)
		return -1;

	list_del(&timeout->list);
	timeout->pending = false;

	return 0;
}

uloop_timeout_cancel会将定时器从全局链表中删除,但是不会释放定时器本身的资源,如果是动态申请的内存,需要手动释放。

uloop_timeout定时器的缺陷

uloop_timeout定时器的缺陷在于struct uloop_timeout结构体中没有一个存放私有数据的指针。
因此这个定时器只能实现一些简单的定时任务。

定时器工具实例

如下实例定义一个超时时间为2s的定时器u_tim ,并在回调函数中重新设置超时时间,使其循环触发。
循环3次后,取消这个定时器。

#include "stdio.h"
#include "uloop.h" //uloop_timeout_xxx
#include <sys/time.h> // struct timeval

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;
}

  • 6
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值