我是靠谱客的博主 自由路灯,最近开发中收集的这篇文章主要介绍Linux内核定时器1.内核定时器2.内核定时器数据结构3.内核定时器API4.相关概念介绍5. 实例,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

文章目录

  • 1.内核定时器
  • 2.内核定时器数据结构
  • 3.内核定时器API
    • 3.1 timer_setup()
    • 3.2 add_timer()
    • 3.3 mod_timer()
    • 3.4 del_timer()
    • 3.5 del_timer_sync
  • 4.相关概念介绍
    • 4.1 节拍率
    • 4.2 节拍数
  • 5. 实例

1.内核定时器

  在Linux 内核中有大量的函数需要时间管理,比如周期性的调度程序、延时程序等。
  Linux内核定时器就是timer_list。硬件定时器提供时钟源,时钟源的频率可以设置,设置好以后就周期性的产生定时中断,系统使用定时中断来计时。

2.内核定时器数据结构

	struct timer_list {
    struct list_head entry, /*定时器列表*/
    unsigned long expires, /*定时器到期时间,单位为节拍数*/
    void (*function) (unsigned long), /*定时器处理函数*/
    unsigned long data,/*作为参数被传入定时器处理函数*/
    struct timer_base_s *base,
    ...
  };

expires 字段表示期望定时器执行的 jiffies 值,到达该 jiffies 值时,将调用 function 函数,并传递 data 作为参数

3.内核定时器API

作用API
初始化定时器void timer_setup(struct timer_list *timer, void (*func)(struct timer_list *), unsigned int flags)
注册定时器void add_timer(struct timer_list *timer)
修改或再次启动定时器int mod_timer(struct timer_list *timer, unsigned long expires)
删除定时器int del_timer(struct timer_list * timer)
等待删除定时器int del_timer_sync(struct timer_list *timer)

3.1 timer_setup()

作用:
	timer_setup函数负责初始化timer_list类型变量,当我们定义了一个timer_list变量以后一定要先用timer_setup初始化一下。
参数:
	timer:要初始化定时器。
	func:定时器的回调函数,此函数的形参是当前定时器的变量。
	flags: 标志位,直接给0就行。
返回值:
	无

3.2 add_timer()

作用:
	add_timer函数用于向Linux内核注册定时器,使用add_timer函数向内核注册定时器以后,定时器就会开始运行。
参数:
	timer:要注册的定时器。
返回值:
	无

3.3 mod_timer()

作用:
	mod_timer函数用于修改定时值,如果定时器还没有激活的话,mod_timer函数会激活定时器。
参数:
	timer:要修改超时时间(定时值)的定时器。
	expires:修改后的超时时间。
返回值:
	0,调用mod_timer函数前定时器未被激活;
	1,调用mod_timer函数前定时器已被激活。

3.4 del_timer()

作用:
	del_timer函数用于删除一个定时器,不管定时器有没有被激活,都可以使用此函数删除。在多处理器系统上,定时器可能会在其他的处理器上运行,因此在调用del_timer函数删除定时器之前要先等待其他处理器的定时处理器函数退出。
参数:
	timer:要删除的定时器。
返回值:
	0,定时器还没被激活;
	1,定时器已经激活。

3.5 del_timer_sync

作用:
	del_timer_sync函数是del_timer函数的同步版,会等待其他处理器使用完定时器再删除,del_timer_sync不能使用在中断上下文中
参数:
	timer:要删除的定时器。
返回值:
	0,定时器还没被激活;
	1,定时器已经激活。

4.相关概念介绍

4.1 节拍率

  内核中有一个宏HZ,表示一秒所对应的节拍数,可以通过这个宏来把时间转换成节拍数,1秒的表示如下:

mytimer.expires = jiffies+HZ;

HZ的值也可以通过make menuconfig自己设置:
在这里插入图片描述

  但是为什么系统节拍率有这么多呢,为什么默认的节拍率这么小?为什么不选择大一点的呢?这里就引出了一个问题:高节拍率和低节拍率的优缺点。

高节拍优点:
  高节拍率会提高系统时间精度,如果采用100Hz的节拍率,时间精度就是10ms,采用1000Hz的话时间精度就是1ms,精度提高了10倍。

  • 提高内核定时器定时的准确度;
  • 系统时间测量更精细;
  • 系统调用poll()和select()能更高的精度运行;
  • 提高进程抢占的准确度。

高节拍缺点:
  高节拍率会导致中断的产生更加频繁,频繁的中断会加剧系统的负担,1000Hz和100Hz的系统节拍率相比,系统要花费10倍的“精力”去处理中断。

  • 中断频率增高,系统负担增加;
  • 中断处理程序占用处理器时间增多;
  • 频繁打断处理器高速缓存。

4.2 节拍数

  jiffies:全局变量,用来记录自系统启动以来产生的节拍总数。启动时内核将该变量初始化为0,jiffies定义在文件include/linux/jiffies.h中。
  前面说了HZ表示每秒的节拍数,jiffies表示系统运行的jiffies节拍数,所以jiffies/HZ就是系统运行时间,单位为秒。
  不管是32位还是64位的jiffies,都有溢出的风险,溢出以后会重新从0开始计数,相当于绕回来了,因此有些资料也将这个现象也叫做绕回。假如HZ为最大值1000的时候,32位的jiffies只需要49.7天就发生了绕回,对于64位的jiffies来说大概需要5.8亿年才能绕回,因此jiffies_64的绕回忽略不计。(处理32位jiffies的绕回显得尤为重要,内核有专门的处理函数,此文不再深究。)

5. 实例

源文件

#include <linux/init.h>
#include <linux/module.h>
#include <linux/timer.h>

struct timer_list timer;

void timer_interrupt(struct timer_list* timer_01)
{
    printk("%s: %lu, %sn", __func__, jiffies, "hello");
    //到时后再次调用
    mod_timer(&timer, jiffies+HZ);
}
static int __init mycdev_init(void)
{
    printk(KERN_EMERG "%s : %s : %d - ok.n", __FILE__, __func__, __LINE__);
    printk(KERN_EMERG "hello");
    //初始化定时器
    timer.expires = jiffies + HZ;//定时1s
    timer_setup(&timer, timer_interrupt, 0);
    //注册定时器
    add_timer(&timer);
    return 0;
}

static void __exit mycdev_exit(void)
{
    //删除定时器
    del_timer(&timer);
}

module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

Makefile

modname ?= 

arch ?= x86
ifeq ($(arch),x86)
	KERNELDIR := /lib/modules/$(shell uname -r)/build
	CROSS_COMPILE := 
else
	KERNELDIR := /home/linux/linux-stm32mp-5.10.61-stm32mp-r2-r0/linux-5.10.61/
	CROSS_COMPILE := arm-linux-gnueabihf-
endif

CURRENTDIR := $(shell pwd)

CC := $(CROSS_COMPILE)gcc
all:
	make -C $(KERNELDIR) M=$(CURRENTDIR) modules
	#$(CC) test.c -o test
install:
	@cp *.ko  ~/nfs/rootfs/ 
	#@cp test ~/nfs/rootfs

help:
	@echo "make arch=arm|x86 modname=modules drivers source file name"

clean:
	make -C $(KERNELDIR) M=$(CURRENTDIR) clean
	#rm test
 
obj-m := $(modname).o

使用dmesg命令查看
在这里插入图片描述

最后

以上就是自由路灯为你收集整理的Linux内核定时器1.内核定时器2.内核定时器数据结构3.内核定时器API4.相关概念介绍5. 实例的全部内容,希望文章能够帮你解决Linux内核定时器1.内核定时器2.内核定时器数据结构3.内核定时器API4.相关概念介绍5. 实例所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(50)

评论列表共有 0 条评论

立即
投稿
返回
顶部