Linux(驱动中) 时间管理和内核定时器(学习总结)

        在Linux内核中,时间管理和内核定时是非常重要的功能,用于实现定时任务、延时操作和周期性事件处理等。内核提供了多种机制来处理时间相关的任务,包括软件定时器(software timers)、硬件定时器(hardware timers)、定时函数(timer functions)等。

一、时间管理     

        Linux内核中的时间管理主要涉及到系统时间的获取、更新和同步,以及提供精确的延时和调度功能。时间管理主要由以下几个部分组成:

  1. 实时时钟(RTC)
    • RTC是硬件设备,用于在系统关机时保持时间信息。
    • 它通过CMOS电池供电,确保在系统重启后能够恢复上一次的系统时间。
    • 内核在启动时读取RTC中的时间信息来初始化系统时间。
  2. 系统定时器
    • 系统定时器是内核中用于产生时钟中断的硬件设备或软件模拟设备。
    • 它以固定的频率(节拍率,Hz)产生中断,内核在中断处理程序中更新系统时间并执行与时间相关的任务。
  3. 全局变量jiffies:
    • jiffies是内核中用于记录自系统启动以来时钟中断次数的全局变量。
    • 它以无符号长整数形式存储,每次时钟中断发生时增加1。
    • jiffies的值可以用于计算系统已经运行的时间(通过jiffies / HZ得到秒数)。
  4. 时间同步
    • 为了确保系统时间的准确性,Linux提供了网络时间协议(NTP)来与其他时间服务器同步时间。
    • NTP客户端会定期向NTP服务器发送请求,并根据服务器的响应调整系统时间。

二、内核定时器

        在 Linux 内核中,定时器机制是一个非常重要的功能,用于在特定时间后执行某些任务或周期性地执行任务。与裸机编程中直接操作硬件定时器不同,Linux 内核提供了一套更为抽象和易用的定时器接口。

软件定时器

        Linux 内核定时器是基于系统时钟实现的,而不是直接基于硬件定时器如 PIT(Programmable Interval Timer)等。内核定时器的使用相对简单,开发者只需提供超时时间和定时处理函数即可。当超时时间到达时,内核会自动调用设置的定时处理函数。

在 Linux 内核中,timer_list 结构体(在较新的内核版本中,通常使用 struct timer_list)用于表示一个内核定时器。这个结构体定义在内核源码的某个头文件中,通常是 <linux/timer.h>

以下是 struct timer_list 结构体的大致定义(具体定义可能因内核版本而异):

struct timer_list {  
    /* ... 其他成员变量 ... */  
    struct list_head entry;    /* 定时器链表入口 */  
    unsigned long expires;     /* 定时器超时时间(以 jiffies 为单位)*/  
    void (*function)(unsigned long); /* 定时器处理函数 */  
    unsigned long data;        /* 传递给处理函数的数据 */  
    /* ... 可能还有其他成员变量,如定时器状态、回调参数等 ... */  
};
主要API函数:
  • TIMER_INITIALIZER(name, function, expires, data):宏定义,用于静态初始化定时器。
  • INIT_TIMER(&timer):函数,用于动态初始化定时器。
  • del_timer_sync(&timer):删除并同步定时器,确保定时器不再被执行。
  • del_timer(&timer):删除定时器,但不等待定时器完成。
  • add_timer(&timer):添加定时器,使其在指定时间后启动。
  • mod_timer(&timer, expires):修改定时器的过期时间。
  • timer_setup(&timer, function, expires):设置定时器回调函数和过期时间。
  1. 使用内核定时器的步骤
    • 定义timer_list结构体变量。
    • 使用init_timer函数初始化定时器。
    • 设置定时器的到期时间(通过expires成员)和处理函数(通过function成员)。
    • 使用add_timer函数将定时器添加到内核中并启动它。
    • 如果需要,可以使用mod_timer函数修改定时器的到期时间。
    • 当不再需要定时器时,使用del_timer函数从内核中删除它。

示例:

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

static struct timer_list my_timer;

static unsigned int interval = 1;  // 定时器间隔,单位为秒

static void timer_callback(unsigned long data)
{
    printk(KERN_INFO "Timer expired!\n");
    // 在这里执行定时任务
    mod_timer(&my_timer, jiffies + interval * HZ);
}

static int __init timer_example_init(void)
{
    printk(KERN_INFO "Timer example module loaded.\n");

    // 初始化定时器
    INIT_TIMER(&my_timer);
    my_timer.function = timer_callback;
    my_timer.expires = jiffies + interval * HZ;
    my_timer.data = 0;

    // 添加定时器
    add_timer(&my_timer);

    return 0;
}

static void __exit timer_example_exit(void)
{
    del_timer_sync(&my_timer);  // 删除并同步定时器
    printk(KERN_INFO "Timer example module unloaded.\n");
}

module_init(timer_example_init);
module_exit(timer_example_exit);
MODULE_LICENSE("GPL");
 硬件定时器:

        硬件定时器通常由硬件提供支持,例如ARM平台上的RTC(实时时钟)。硬件定时器可以提供更精确的定时服务,并且通常独立于操作系统的工作。

示例:

#include <linux/hrtimer.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>

struct hrtimer my_hrtimer;

static unsigned int interval_ns = 1000000000;  // 定时器间隔,单位为纳秒

static enum hrtimer_restart hrtimer_callback(struct hrtimer *hrt)
{
    printk(KERN_INFO "High-resolution timer expired!\n");
    // 在这里执行定时任务
    hrtimer_forward(&my_hrtimer, hrt_get_base_now(), ns_to_ktime(interval_ns));
    return HRTIMER_RESTART;
}

static int __init hrtimer_example_init(void)
{
    printk(KERN_INFO "High-resolution timer example module loaded.\n");

    // 初始化高分辨率定时器
    INIT_HRTIMER(&my_hrtimer);
    my_hrtimer.function = hrtimer_callback;

    // 启动定时器
    hrtimer_start(&my_hrtimer, ns_to_ktime(interval_ns), HRTIMER_MODE_RELATIVE);

    return 0;
}

static void __exit hrtimer_example_exit(void)
{
    hrtimer_cancel(&my_hrtimer);  // 取消定时器
    printk(KERN_INFO "High-resolution timer example module unloaded.\n");
}

module_init(hrtimer_example_init);
module_exit(hrtimer_example_exit);
MODULE_LICENSE("GPL");

        除了上述的软件定时器和硬件定时器外,Linux内核还提供了一些辅助函数来处理定时任务,如delay()系列函数和schedule_timeout()函数。

延迟函数:
  • msleep(msec):休眠指定的毫秒数。
  • usleep(usec):休眠指定的微秒数。
  • mdelay(msec):延迟指定的毫秒数。
  • udelay(usec):延迟指定的微秒数。

示例:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>

static void delay_example(void)
{
    printk(KERN_INFO "Before delay.\n");
    msleep(1000);  // 延迟1秒
    printk(KERN_INFO "After delay.\n");
}

static int __init delay_example_init(void)
{
    printk(KERN_INFO "Delay example module loaded.\n");
    delay_example();
    return 0;
}

static void __exit delay_example_exit(void)
{
    printk(KERN_INFO "Delay example module unloaded.\n");
}

module_init(delay_example_init);
module_exit(delay_example_exit);
MODULE_LICENSE("GPL");
定时等待函数:
  • schedule_timeout(timeout):等待指定的时间后调度其他任务。
  • schedule_timeout_uninterruptible(timeout):不可中断地等待指定的时间后调度其他任务。

示例:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>

static void timeout_example(void)
{
    printk(KERN_INFO "Before timeout.\n");
    schedule_timeout(1 * HZ);  // 延迟1秒
    printk(KERN_INFO "After timeout.\n");
}

static int __init timeout_example_init(void)
{
    printk(KERN_INFO "Timeout example module loaded.\n");
    timeout_example();
    return 0;
}

static void __exit timeout_example_exit(void)
{
    printk(KERN_INFO "Timeout example module unloaded.\n");
}

module_init(timeout_example_init);
module_exit(timeout_example_exit);
MODULE_LICENSE("GPL");

小结 

        在Linux系统及其驱动开发中,软件定时器和硬件定时器各有优缺点,适用于不同的场景。软件定时器具有跨平台性好、灵活性高的特点,但精度受限;而硬件定时器则具有高精度和稳定性好的特点,但跨平台性差。在实际应用中,开发者应根据具体需求选择合适的定时器实现方式。

ps:在学习工程中的简单记录,作为学习记录,不够严谨,欢迎指正

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值