【linux】驅動-15-定時器

李柱明發表於2021-06-23


前言

15. 定時器

本章內容為驅動基石之一
驅動只提供功能,不提供策略

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

參考原始碼路徑:include\linux\timer.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);

相關文章