Linux 内核定时器 一 函数简介

Linux 内核定时器 一 函数简介

Linux 内核定时器 二 例子demo

 

我们在编写内核驱动的时候,有时候需要挂载驱动的一段时间后执行某项任务,或者周期行的执行某项任务。

这种时候需要借助内核定时器来协助我们。(类似“软件中断”)

定时器调用流程:

1. 初始化

    a. 宏 init_timer

    b. 宏DEFINE_TIMER

    c. 宏  setup_timer

2.向内核中添加定时器

     a.  add_timer - 初始化完成后,向内核中添加定时器

     b. mod_timer - 如果需要周期性执行任务,在定时器回调函数中添加 mod_timer

3. 手动/自动释放

     a. 定时器运行后,不会再运行,类似自动注销;

     b.  定时器未运行,可手动释放 -  del_timer

 

源码:  linux-3.10.y

struct timer_list

// linux-3.10.y/include/linux\timer.h
struct timer_list
{
    /*
     * All fields that change during normal runtime grouped to the
     * same cacheline
     */
    struct list_head entry; // 定时器列表
    unsigned long expires;  // 期望定时器执行的jiffies值
    struct tvec_base *base;

    void (*function)(unsigned long); // 定时器处理函数
    unsigned long data;  // 作为参数被传入定时器处理函数

    int slack;

#ifdef CONFIG_TIMER_STATS
    int start_pid;
    void *start_site;
    char start_comm[16];
#endif
#ifdef CONFIG_LOCKDEP
    struct lockdep_map lockdep_map;
#endif
};

重点 :

  • expires,定时器的到期时间,单位是jiffies 
  • function,定时器到期,要执行的函数 
  • data,传入要执行的函数的参数

 

初始化定时器 - 三种方法

方法一 : 宏 init_timer  初始化 struct timer_list 

init_timer(timer)  // 传参 time 是 struct timer_list 指针

// linux-3.10.y/include/linux\timer.h
// 功能是初始化 timer_list 结构体的 entry 的next 为 NULL,并给 base 指针赋值
#define init_timer(timer)                      \
    __init_timer((timer), 0)
 
// linux-3.10.y/kernel/timer.c
void init_timer_key(struct timer_list *timer, unsigned int flags,
            const char *name, struct lock_class_key *key)
{
    debug_init(timer);
    do_init_timer(timer, flags, name, key);
}
EXPORT_SYMBOL(init_timer_key);
 
static inline void debug_init(struct timer_list *timer)
{
    debug_timer_init(timer);
    trace_timer_init(timer);
}
 
static void do_init_timer(struct timer_list *timer, unsigned int flags,
              const char *name, struct lock_class_key *key)
{
    struct tvec_base *base = __raw_get_cpu_var(tvec_bases);
 
    timer->entry.next = NULL;
    timer->base = (void *)((unsigned long)base | flags);
    timer->slack = -1;
#ifdef CONFIG_TIMER_STATS
    timer->start_site = NULL;
    timer->start_pid = -1;
    memset(timer->start_comm, 0, TASK_COMM_LEN);
#endif
    lockdep_init_map(&timer->lockdep_map, name, key, 0);
}

 

方法二 :宏DEFINE_TIMER 初始化 struct timer_list

DEFINE_TIMER 中创建 struct timer_list 型变量,无需再外部定义 timer_list 变量

// linux-3.10.y/include/linux\timer.h
#define __TIMER_INITIALIZER(_function, _expires, _data, _flags) { \
		.entry = { .prev = TIMER_ENTRY_STATIC },	\
		.function = (_function),			\
		.expires = (_expires),				\
		.data = (_data),				\
		.base = (void *)((unsigned long)&boot_tvec_bases + (_flags)), \
		.slack = -1,					\
		__TIMER_LOCKDEP_MAP_INITIALIZER(		\
			__FILE__ ":" __stringify(__LINE__))	\
	}

#define TIMER_INITIALIZER(_function, _expires, _data)		\
	__TIMER_INITIALIZER((_function), (_expires), (_data), 0)

#define TIMER_DEFERRED_INITIALIZER(_function, _expires, _data)	\
	__TIMER_INITIALIZER((_function), (_expires), (_data), TIMER_DEFERRABLE)

#define DEFINE_TIMER(_name, _function, _expires, _data)		\
	struct timer_list _name =				\
		TIMER_INITIALIZER(_function, _expires, _data)

 

方法三 :宏  setup_timer  初始化 struct timer_list

setup_timer 和 init_timer 类似。

// linux-3.10.y/include/linux\timer.h
#define __setup_timer(_timer, _fn, _data, _flags)           \
    do {                               \
        __init_timer((_timer), (_flags));          \
        (_timer)->function = (_fn);                \
        (_timer)->data = (_data);              \
    } while (0)
 
#define __setup_timer_on_stack(_timer, _fn, _data, _flags)      \
    do {                               \
        __init_timer_on_stack((_timer), (_flags));     \
        (_timer)->function = (_fn);                \
        (_timer)->data = (_data);              \
    } while (0)
 
#define setup_timer(timer, fn, data)                 \
    __setup_timer((timer), (fn), (data), 0)

 

增加/修改定时器

先看函数声明:

void add_timer(struct timer_list *timer)   // 增加定时器, 定时器运行后,自动释放
int mod_timer(struct timer_list *timer, unsigned long expires) // 重设,增加定时器

源码如下:

// linux-3.10.y/kernel/timer.c
// 注册内核定时器,将定时器加入到内核动态定时器链表,即启动定时器
void add_timer(struct timer_list *timer)
{
    BUG_ON(timer_pending(timer));
    mod_timer(timer, timer->expires);
}
EXPORT_SYMBOL(add_timer);
 
// 重设延时时间,启动定时器
int mod_timer(struct timer_list *timer, unsigned long expires)
{
    expires = apply_slack(timer, expires);
 
    /*
     * This is a common optimization triggered by the
     * networking code - if the timer is re-modified
     * to be the same thing then just return:
     */
    if(timer_pending(timer) && timer->expires == expires)
        return 1;
 
    return __mod_timer(timer, expires, false, TIMER_NOT_PINNED);
}
EXPORT_SYMBOL(mod_timer);
 
 
static inline int
__mod_timer(struct timer_list *timer, unsigned long expires,
            bool pending_only, int pinned)
{
    struct tvec_base *base, *new_base;
    unsigned long flags;
    int ret = 0, cpu;
 
    timer_stats_timer_set_start_info(timer);
    BUG_ON(!timer->function);
 
    base = lock_timer_base(timer, &flags);
 
    ret = detach_if_pending(timer, base, false);
    if(!ret && pending_only)
        goto out_unlock;
 
    debug_activate(timer, expires);
 
    cpu = smp_processor_id();
 
#if defined(CONFIG_NO_HZ_COMMON) && defined(CONFIG_SMP)
    if(!pinned && get_sysctl_timer_migration() && idle_cpu(cpu))
        cpu = get_nohz_timer_target();
#endif
    new_base = per_cpu(tvec_bases, cpu);
 
    if(base != new_base)
    {
        /*
         * We are trying to schedule the timer on the local CPU.
         * However we can't change timer's base while it is running,
         * otherwise del_timer_sync() can't detect that the timer's
         * handler yet has not finished. This also guarantees that
         * the timer is serialized wrt itself.
         */
        if(likely(base->running_timer != timer))
        {
            /* See the comment in lock_timer_base() */
            timer_set_base(timer, NULL);
            spin_unlock(&base->lock);
            base = new_base;
            spin_lock(&base->lock);
            timer_set_base(timer, base);
        }
    }
 
    timer->expires = expires;
    internal_add_timer(base, timer);
 
out_unlock:
    spin_unlock_irqrestore(&base->lock, flags);
 
    return ret;
}

 

删除定时器

函数声明:

// 直接删除
int del_timer(struct timer_list * timer); 

源码:

// linux-3.10.y/kernel/timer.c
/**
 * del_timer - deactive a timer.
 * @timer: the timer to be deactivated
 *
 * del_timer() deactivates a timer - this works on both active and inactive
 * timers.
 *
 * The function returns whether it has deactivated a pending timer or not.
 * (ie. del_timer() of an inactive timer returns 0, del_timer() of an
 * active timer returns 1.)
 */
int del_timer(struct timer_list *timer)
{
    struct tvec_base *base;
    unsigned long flags;
    int ret = 0;
 
    debug_assert_init(timer);
 
    timer_stats_timer_clear_start_info(timer);
    if (timer_pending(timer)) {
        base = lock_timer_base(timer, &flags);
        ret = detach_if_pending(timer, base, true);
        spin_unlock_irqrestore(&base->lock, flags);
    }
 
    return ret;
}
EXPORT_SYMBOL(del_timer);

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值