zoukankan      html  css  js  c++  java
  • 【linux】驱动-15-定时器


    前言

    15. 定时器

    本章内容为驱动基石之一
    驱动只提供功能,不提供策略

    原文:https://www.cnblogs.com/lizhuming/p/14922233.html

    参考源码路径:includelinux imer.h

    参考例子就明白如何使用了。

    15.1 内核函数汇总

    KERNEL 使用

    说明:以下只是给出部分 API 而已。为 Linux5.12.8 版本。还有其它 API 可以实现内核定时器功能,具体参考内核文档。

    • setup_timer(): 设置定时器。
    • add_timer(): 向内核添加定时器。
    • mod_timer(): 修改定时器超时时间。
    • del_timer(): 删除定时器。

    15.2 内核滴答

    获取 CONFIG_HZ:

    1. 在 Linux 内核源码根目录上找到 .config 配置文件。打开该文件找到宏 CONFIG_HZ ,该宏定义了内核滴答(tick)频率。
    2. 命令行:进入 /boot,查找文件 config-5.8.0-53-geberic(各个系统,文件名不一样,看前缀即可) 内容。
    • 如命令:grep ^CONFIG_HZ /boot/config-$(uname -r)
    1. APP:sysconf(_SC_CLK_TCK)

    内核 tick
    每跳动一次,内核全局值 jiffies 就会累加 1。

    定时器的时间值就是基于 jiffies 的。

    所以,其实也可以比较设定的 滴答值 和 jiffies 来判断是否超时。由此,内核推荐使用以下 4 个 API:

    /*
     *	These inlines deal with timer wrapping correctly. You are 
     *	strongly encouraged to use them
     *	1. Because people otherwise forget
     *	2. Because if the timer wrap changes in future you won't have to
     *	   alter your driver code.
     *
     * time_after(a,b) returns true if the time a is after time b.
     *
     * Do this with "<0" and ">=0" to only test the sign of the result. A
     * good compiler would generate better code (and a really good compiler
     * wouldn't care). Gcc is currently neither.
     */
    #define time_after(a,b)		
    	(typecheck(unsigned long, a) && 
    	 typecheck(unsigned long, b) && 
    	 ((long)((b) - (a)) < 0))
    #define time_before(a,b)	time_after(b,a)
    
    #define time_after_eq(a,b)	
    	(typecheck(unsigned long, a) && 
    	 typecheck(unsigned long, b) && 
    	 ((long)((a) - (b)) >= 0))
    #define time_before_eq(a,b)	time_after_eq(b,a)
    

    15.3 相关结构体

    timer_list:

    struct timer_list {
    	/*
    	 * All fields that change during normal runtime grouped to the
    	 * same cacheline
    	 */
    	struct hlist_node	entry;
    	unsigned long		expires; // 超时时间
    	void			        (*function)(struct timer_list *); // 回调函数
    	u32			            flags; // 标志
    
    #ifdef CONFIG_LOCKDEP
    	struct lockdep_map	lockdep_map;
    #endif
    };
    

    15.4 setup_timer() 设置定时器

    功能:设置定时器。初始化 timer_list 结构体。

    函数原型

    /**
     * timer_setup - prepare a timer for first use
     * @timer: the timer in question
     * @callback: the function to call when timer expires
     * @flags: any TIMER_* flags
     *
     * Regular timer initialization should use either DEFINE_TIMER() above,
     * or timer_setup(). For timers on the stack, timer_setup_on_stack() must
     * be used and must be balanced with a call to destroy_timer_on_stack().
     */
    #define timer_setup(timer, callback, flags)			
    	__init_timer((timer), (callback), (flags))
    

    15.5 add_timer() 向内核添加定时器

    功能:向内核添加定时器。

    函数原型

    /**
     * add_timer - start a timer
     * @timer: the timer to be added
     *
     * The kernel will do a ->function(@timer) callback from the
     * timer interrupt at the ->expires point in the future. The
     * current time is 'jiffies'.
     *
     * The timer's ->expires, ->function fields must be set prior calling this
     * function.
     *
     * Timers with an ->expires field in the past will be executed in the next
     * timer tick.
     */
    void add_timer(struct timer_list *timer)
    {
    	BUG_ON(timer_pending(timer));
    	__mod_timer(timer, timer->expires, MOD_TIMER_NOTPENDING);
    }
    EXPORT_SYMBOL(add_timer);
    

    15.6 mod_timer() 修改定时器超时时间

    功能:修改定时器超时时间。

    :注释说明中,修改超时时间相当于删除定时器再重新添加到内核。说明,在添加到内核后就不能简单的使用 imer->expires = expires; 来修改超时时间啦。

    函数原型

    /**
     * mod_timer - modify a timer's timeout
     * @timer: the timer to be modified
     * @expires: new timeout in jiffies
     *
     * mod_timer() is a more efficient way to update the expire field of an
     * active timer (if the timer is inactive it will be activated)
     *
     * mod_timer(timer, expires) is equivalent to:
     *
     *     del_timer(timer); timer->expires = expires; add_timer(timer);
     *
     * Note that if there are multiple unserialized concurrent users of the
     * same timer, then mod_timer() is the only safe way to modify the timeout,
     * since add_timer() cannot modify an already running timer.
     *
     * The function returns whether it has modified a pending timer or not.
     * (ie. mod_timer() of an inactive timer returns 0, mod_timer() of an
     * active timer returns 1.)
     */
    int mod_timer(struct timer_list *timer, unsigned long expires)
    {
    	return __mod_timer(timer, expires, 0);
    }
    EXPORT_SYMBOL(mod_timer);
    

    15.7 del_timer 删除定时器

    功能:删除定时器。

    函数原型

    /**
     * del_timer - deactivate 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 timer_base *base;
    	unsigned long flags;
    	int ret = 0;
    
    	debug_assert_init(timer);
    
    	if (timer_pending(timer)) {
    		base = lock_timer_base(timer, &flags);
    		ret = detach_if_pending(timer, base, true);
    		raw_spin_unlock_irqrestore(&base->lock, flags);
    	}
    
    	return ret;
    }
    EXPORT_SYMBOL(del_timer);
    
  • 相关阅读:
    automatic preferred max layout width
    UIActivityIndicatorView
    collectionview不能拖动
    消除找不到文件路径的警告
    保存图片到本地和相册
    svn上传.a文件
    UILabel copyWithZone:]: unrecognized selector sent to instance 0x7fd662d8f9b0
    NSString NSURL
    iOS 定位功能
    前端实现左右翻页功能Demo
  • 原文地址:https://www.cnblogs.com/lizhuming/p/14922233.html
Copyright © 2011-2022 走看看