`

Linux kernel之内核定时器

阅读更多

内核定时器 (也称为动态定时器)是内核在以后某一个时刻运行一段程序或进程的基础,软件定时器可以在一个确切的时间点上(更严格地说是一个时间点以后)激活相应的程序段或进程。软件定时器在设备驱动程序中被大量应用以检测设备的状态。

使用一个软件定时器很简单,只需做一些初始化工作,设置一个相对于当前时刻的超时时间和超时处理函数,将其插入到内核定时器队列中即可,设置的超时处理函数会在定时器超时时自动运行。下面介绍如何使用内核定时器和实现内核定时器的内部架构。

 

1.内核定时器的使用方法

内核定时器由数据结构timer_list表示,该结构表示了一个待处理的延迟任务,我们称该数据结构为内核定时器节点。该数据结构的详细内容请看下面的代码清单。

代码清单--数据结构timer_list

功能简介:该数据结构保存了内核定时器节点的相关信息,包括定时器超时时间和超时处理函数等。

 

文件:src/include/Linux/timer.h 
11  struct timer_list {    
12       struct list_head entry;   
13       unsigned long expires;   
14       void (*function)(unsigned long); 
15       unsigned long data;    
16       struct timer_base_s *base;  
};

 

成员变量entry:该内核链表表头类型成员变量用于将该内核定时器节点连接到系统中的定时器链表中。

成员变量expires:该无符号长整型变量保存了该定时器的超时时间,用于和系统核心变量jiffies进行比较。

成员变量function:该函数指针变量保存了内核定时器超时后要执行的函数,即定时器超时处理函数。

成员变量data:该无符号长整型变量用作定时器超时处理函数的参数。

成员变量base:该指针变量表明了该内核定时器节点归属于系统中哪一个处理器,在使用函数init_timer()初始化内核定时

                       器节点的过程中,将该指针指向了一个每处理器变量tvec_bases的成员变量t_base。

 

在了解了内核定时器节点数据结构的相关内容之后,下面来看如何在自己的代码中使用一个内核定时器节点,实现在一段时间后执行一个延迟处理任务。

① 首先,使用下面语句声明一个内核定时器数据结构。

struct timer_list my_timer;

 

② 使用函数init_timer()对上一步声明的内核定时器结构进行初始化。函数init_timer()主要设置该内核定时器归属系统中哪一个处理,并初始化内核定时器链表指针的next域为NULL。

init_timer(&my_timer);

 

③ 使用下面的语句来设置内核定时器的超时时间expires、超时处理函数function、超时处理函数所使用的参数data。

my_timer.expires = jiffies + delay; 
my_timer.data = 0;     
my_timer.function = my_function; 

 

④ 也是最后一步,通过函数add_timer()来激活内核定时器,使用的语句如下:

add_timer(&my_timer);

 

通过上面4步,我们就创建了一个内核定时器节点my_timer。该内核定时器在当前时刻以后delay个时钟中断后超时,执行超时处理函数my_function,传给超时处理函数的参数为0。

 

除了上述过程中介绍的内核定时器接口函数之外,内核同时提供了以下接口函数来辅助对内核定时器的操作。

int mod_timer(struct timer_list *timer,unsigned long expires):该函数负责修改内核定时器timer的超时字段expires。该函数可以修改激活和没有激活的内核定时器的超时时间,并把它们都设置为激活状态;返回值为0表示修改的内核定时器在修改之前处于未激活状态,返回值为1表示修改的内核定时器在修改之前处于已激活状态。

 

int del_timer(structtimer_list* timer)、int del_timer_sync(structtimer_list* timer):这两个函数负责从链表中删除内核定时器timer。它们的区别在于,后者在多处理器系统中会确保其他处理器上没有处理或者处理完毕当前内核定时器timer时才退出。

 

2.内核定时器架构

与softirq、工作队列两种中断下半部的处理方法类似,每一个内核定时器节点与系统中的处理器通过一个每处理器变量联系起来。内核在文件 src/kernel/timer.c中的第88行使用下面的语句分配了一个名称为tvec_bases、类型为tvec_base_t的每处理器变量。

static DEFINE_PER_CPU(tvec_base_t, tvec_bases);

 

其中,tvec_base_t是数据结构struct tvec_t_base_s通过语句typedef定义的一个别名,数据结构struct tvec_t_base_s用来记录系统中每一个处理器上待处理内核定时器节点的相关信息。有关该数据结构的详细内容请看下面的代码清单。

 

代码清单--数据结构tvec_t_base_s

功能简介:该数据结构用于有效组织当前处理器上所有待处理内核定时器节点,以支持快速访问超时内核定时器节点。

该数据结构在同一文件中的第77行开始定义,代码如下。接下来是对这些成员用途的分析、说明。

struct tvec_t_base_s {
struct timer_base_s t_base;
unsigned long timer_jiffies;
tvec_root_t tv1;
tvec_t tv2;
tvec_t tv3;
tvec_t tv4;
tvec_t tv5;
} ____cacheline_aligned_in_smp;

 

成员变量t_base的数据类型为struct timer_base_s,它在文件src/kernel/timer.c中的第64行开始定义,代码如下:

truct timer_base_s {
spinlock_t lock;
struct timer_list *running_timer;
);

 

其中,成员变量running_timer记录了正在本地处理器上进行超时处理的内核定时器;另外一个自旋锁成员变量lock用于保护每处理器变量tvec_bases的本地拷贝。

无符号长整型变量timer_jiffies记录了该数据结构中所包含的定时器中最早超时时间,根据该变量可以计算出超时定时器节点所在链表的表头。

变量tv1的类型为tvec_root_t,该数据结构在文件src/kernel/timer.c中的第73行开始定义,代码如下。该数据结构中包含了TVR_SIZE个链表表头指针。

typedef struct tvec_root_s {
struct list_head vec[TVR_SIZE];
} tvec_root_t;

 

变量tv2、tv3、tv4、tv5的类型为tvec_t,该数据结构在文件src/kernel/timer.c中的第69行开始定义,代码如下:

 ypedef struct tvec_s {
struct list_head vec[TVN_SIZE];
)tvec_t;

 

该数据结构中包含了TVN_SIZE个链表表头指针,其中TVR_SIZE、TVN_SIZE的值在没有选中内核选项 CONFIG_BASE_SMALL时分别为256、64;否则分别为64、16。内核选项CONFIG_BASE_SMALL用于为系统资源匮乏的计算机系统进行优化,选中该内核选项后,可以减小系统核心对内存的使用量。通常个人计算机中不会选中该内核选项。

 

这5个变量一共包含了256+64×4=512个链表表头,每个链表表头指针指向了一个待处理内核定时器链表。由当前处理器处理的内核定时器根据其超时时间的不同分布在这512个链表上。通过上面的分析,可以用一个形象化的示意图来描述内核定时器的架构,如图所示。

 
内核定时器架构示意图
分享到:
评论

相关推荐

    Professional Linux Kernel Architecture

    《Professional Linux Kernel Architecture》是一本全面深入地介绍Linux内核架构的专业书籍,由Wolfgang Mauerer编写,Wiley Publishing, Inc.出版。本书不仅适合对Linux内核感兴趣的开发者,也适合希望深入了解操作...

    linux kernel development 3rd edition

    《Linux Kernel Development》第三版详细阐述了Linux内核的设计和实现原理,对内核程序员以及想要深入了解操作系统原理以提高编码效率的程序员提供了宝贵的学习资源。 本书首先介绍了Linux内核的主要子系统和特点,...

    Linux Kernel(中文版)

    ### Linux Kernel(中文版)知识点概述 #### 一、硬件基础 1. **CPU**: CPU是计算机的大脑,负责执行指令。Linux内核通过各种机制来管理CPU资源,包括但不限于调度算法、上下文切换等。 2. **内存**: 内存是计算机的...

    Linux Kernel 2.4 Internals

    **知识点:Linux Kernel 2.4 内部结构与操作** **一、引导过程(Booting)** 在深入了解Linux Kernel 2.4的内部工作原理时,首先关注的是其引导过程。这一部分涵盖从硬件初始化到操作系统完全启动的整个流程。 1....

    Understanding the Linux Kernel

    - **书籍简介**:“Understanding the Linux Kernel”是一本经典的计算机科学著作,它深入浅出地讲解了Linux内核的工作原理及其核心技术。本书由Daniel P. Bovet和Marco Cesati撰写,首次出版于2000年10月,由O'...

    Professional Linux Kernel Architecture, 精通Linux内核架构

    - **知识点**:描述了Linux内核内部的一些关键活动,如中断处理、定时器机制等。 - **重要性**:这些底层机制支撑着整个系统的正常运行。 - **第15章:时间管理** - **知识点**:讨论了Linux内核如何管理时间和...

    Understanding the Linux Kernel, 3rd Edition.pdf

    Linux内核的内存管理是其核心功能之一,它负责处理所有与CPU和外部世界之间的交互。内核决定哪些程序将共享处理器时间,以及它们执行的顺序,同时高效地管理有限的内存资源,使得数百个进程能够共享系统资源而不造成...

    Linux Kernel中文版

    ### Linux Kernel中文版知识点概述 #### 一、硬件基础 **1.1 CPU** - **定义**: 中央处理器(Central Processing Unit),是计算机的核心部件之一,负责执行指令。 - **功能**: 解释计算机指令以及处理计算机软件...

    Understanding_The_Linux_Kernel.pdf

    通过以上知识点的梳理,《Understanding the Linux Kernel》这本书不仅提供了深入的技术细节,还涵盖了广泛的实践应用案例,是了解和学习Linux内核不可或缺的经典之作。对于希望深入理解Linux内部机制的专业人士来说...

    Understanding.the.Linux.Kernel, 3rd.Ed

    Linux内核的内存管理是其核心功能之一,它确保了系统资源的有效利用和多进程间的高效共享。书中详细介绍了文件缓冲、进程交换和Direct Memory Access(DMA)等技术,这些技术使得系统能够在有限的物理内存下支持数百...

    Linux下的系统调用和进程

    内核线程是Linux内核内部创建和维护的一种特殊进程,主要用于执行内核级的任务,如定时器处理、软中断等。`kernel_thread`函数是创建内核线程的一个关键函数,它允许在内核空间中启动一个新的线程,执行特定的函数并...

Global site tag (gtag.js) - Google Analytics