目录
1、设置系统节拍率
在编译 Linux 内核的时候可以通过图形化界面设置系统节拍率。
-> Kernel Features
-> Timer frequency
1.1、CONFIG_HZ
HZ 表示一秒的节拍数,Linux 内核会使用 CONFIG_HZ 来设置自己的系统时钟(include/asm-generic/param.h)
#undef HZ
#define HZ CONFIG_HZ
#define USER_HZ 100
#define CLOCKS_PER_SEC (USER_HZ)
2、jiffies
Linux 内核使用全局变量 jiffies 来记录系统从启动以来的系统节拍数(jiffies 定义在文件 include/linux/jiffies.h 中)。
#define __jiffy_data __attribute__((section(".data")))
extern u64 __jiffy_data jiffies_64;
extern unsigned long volatile __jiffy_data jiffies;
2.1、jiffies_64
jiffies_64 用于 64 位系统,而 jiffies 用于 32 位系统。为了兼容不同的硬件, jiffies 其实就是 jiffies_64 的低 32 位。
2.2、系统运行时间
HZ 表示每秒的节拍数, jiffies 表示系统运行的 jiffies 节拍数,所以 jiffies/HZ 就是系统运行时间,单位为秒。
2.3、时间绕回
不管是 32 位还是 64 位的 jiffies,都有溢出的风险,溢出以后会重新从 0 开始计数。假如 HZ 为最大值 1000 的时候, 32 位的 jiffies 只需要 49.7 天就发生了wrap,对于 64 位的 jiffies 来说大概需要5.8 亿年才能绕回,因此 jiffies_64 的wrap忽略不计。
3、API函数
时间比较函数 | |
time_after(unkown, known) | 如果 unkown 超过 known 的话,返回真,否则返回假。 |
time_before(unkown, known) | 如果 unkown 没有超过 known 的话,返回真,否则返回假。 |
time_after_eq(unkown, known) | 如果 unkown 超过或等于 known 的话,返回真,否则返回假。 |
time_before_eq(unkown, known) | 如果 unkown 没有超过或等于 known 的话,返回真,否则返回假。 |
jiffies 和 ms、 us、 ns 之间的转换函数 | |
int jiffies_to_msecs(const unsigned long j) | 将 jiffies 类型转换为对应的毫秒。 |
int jiffies_to_usecs(const unsigned long j) | 将 jiffies 类型转换为对应的微秒。 |
u64 jiffies_to_nsecs(const unsigned long j) | 将 jiffies 类型转换为对应的毫秒纳秒。 |
long msecs_to_jiffies(const unsigned int m) | 将毫秒转换为 jiffies 类型。 |
long usecs_to_jiffies(const unsigned int u) | 将微秒转换为 jiffies 类型。 |
unsigned long nsecs_to_jiffies(u64 n) | 将纳秒转换为 jiffies 类型。 |
4、内核定时器
内核定时器并不是周期性运行的,超时以后就会自动关闭,因此如果想要实现周期性定时,那么就需要在定时处理函数中重新开启定时器(定义在include/linux/timer.h中)。
4.1、timer_list结构体
Linux 内核使用 timer_list 结构体表示内核定时器。
struct timer_list {
struct list_head entry;
unsigned long expires;
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
}
entry | 链表节点 |
expires | 定时器超时时间,单位为节拍数 |
function | 定时处理函数 |
data | 要传递给 function 函数的参数 |
4.2、init_timer()函数
init_timer 函数负责初始化 timer_list 类型变量。
void init_timer(struct timer_list *timer)
参数 timer:要初始化定时器。
4.3、add_timer()函数
add_timer 函数用于向 Linux 内核注册定时器。
void add_timer(struct timer_list *timer)
参数 timer:要注册的定时器。
4.4、del_timer()函数
del_timer 函数用于删除一个定时器,不管定时器有没有被激活,都可以使用此函数删除。
int del_timer(struct timer_list * timer)
timer:要删除的定时器。
返回值: 0,定时器还没被激活; 1,定时器已经激活。
注:在多处理器系统上,定时器可能会在其他的处理器上运行,因此在调用 del_timer 函数删除定时器之前要先等待其他处理器的定时处理器函数退出。
4.5、del_timer_sync()函数
del_timer_sync 函数是 del_timer 函数的同步版,会等待其他处理器使用完定时器再删除,
del_timer_sync 不能使用在中断上下文中。
int del_timer_sync(struct timer_list *timer)
timer:要删除的定时器。
返回值: 0,定时器还没被激活; 1,定时器已经激活。
4.6、mod_timer()函数
mod_timer 函数用于修改定时值,如果定时器还没有激活的话, mod_timer 函数会激活定时器
int mod_timer(struct timer_list *timer, unsigned long expires)
timer:要修改超时时间(定时值)的定时器。
expires:修改后的超时时间。
返回值: 0,调用 mod_timer 函数前定时器未被激活; 1,调用 mod_timer 函数前定时器已
被激活。
5、Linux 内核短延时函数
void ndelay(unsigned long nsecs) | 纳秒延时函数。 |
void udelay(unsigned long usecs) | 微秒延时函数。 |
void mdelay(unsigned long mseces) | 毫秒延时函数。 |