新闻资讯
Group news
青岛广盛源肥业有限公司    您的位置: 首页  >  新闻资讯  >  正文

Linux 2.6内核中的计时器和列表

2019年10月12日 文章来源:网络整理 热度:196℃ 作者:刘英

计时器是所有操作系统的一个必要组成部分,您将发现多个计时器机制。我们将首先简要介绍一些 Linux 计时器模式,然后深入研究它们的运行方式。

(Linux)时间的起源

在 Linux 内核中,时间由一个名为 jiffies 的全局变量衡量,该变量标识系统启动以来经过的滴答数。在最低的级别上,计算滴答数的方式取决于正在运行的特定硬件平台;但是,滴答计数通常在一次中断期间仍然继续进行。滴答速率(jiffies 的最不重要的位)可以配置,但在最近针对 x86 的 2.6 内核中,一次滴答等于 4ms(250Hz)。jiffies 全局变量在内核中广泛使用,目的有几个,其中之一是提供用于计算一个计时器的超时值的当前绝对时间(稍后将展示一个例子)。

回页首

内核计时器

最近的 2.6 内核中有几个不同的计时器模式,其中最简单、最不精确(但适用于大多数实例)的模式就是计时器 API。这个 API 允许构造在 jiffies 域(最低 4ms 超时)中运行的计时器。还有一个高精确度计时器 API,它允许构造在以纳秒定义的时间中运行的计时器。根据您的处理器和处理器运行的速度,您的里程(mileage)可能会不同,但这个 API 的确提供了一种方法来在 jiffies 滴答间隔下调度超时。

标准计时器

标准计时器 API 作为 Linux 内核的一部分已经有很长一段时间了(自从 Linux 内核的早期版本开始)。尽管它提供的精确性比高精确度计时器要低,但它对于在处理物理设备时提供错误覆盖的传统驱动程序超时来说比较理想。在很多情况下,这些超时实际上从不触发,而是被启动,然后被删除。

简单内核计时器使用计时器轮(timer wheel) 实现。这个主意是由 Finn Arne Gangstad 在 1997 年首次引入的。它不理睬管理大量计时器的问题,而是很好地管理数量合理的计时器 — 典型情况。(原始计时器实现只是按照过期顺序将计时器实现双重链接。尽管在概念上比较简单,但这种方法是不可伸缩的。)时间轮是一个 buckets 集合,其中每个 bucker 表示将来计时器过期的一个时间块。这些 buckets 使用基于 5 个 bucket 的对数时间定义。使用 jiffies 作为时间粒度,定义了几个组,它们表示将来的过期时段(其中每个组通过一列计时器表示)。计时器插入使用具有 O(1) 复杂度的列表操作发生,过期发生在 O(N) 时间内。计时器过期以串联的形式出现,其中计时器被从高粒度 buckets 删除,然后随着它们的过期时间的下降被插入到低粒度 buckets 中。现在我们查看一下针对这个计时器实现的 API。

计时器 API

Linux 提供了一个简单的 API 来构造和管理计时器。它包含一些函数(和助手函数),用于创建、取消和管理计时器。

计时器通过 TImer_list 结构定义,该结构包括实现一个计时器所需的所有数据(其中包括列表指针和在编译时配置的可选计时器统计数据)。从用户角度看,TImer_list 包含一个过期时间,一个回调函数(当/如果计时器过期),以及一个用户提供的上下文。用户必须初始化计时器,可以采取几种方法,最简单的方法是调用 setup_TImer,该函数初始化计时器并设置用户提供的回调函数和上下文。或者,用户可以设置计时器中的这些值(函数和数据)并简单地调用 init_TImer。注意,init_timer 由 setup_timer 内部调用。

voidinit_timer( struct timer_list *timer );voidsetup_timer( struct timer_list *timer, void (*function)(unsigned long), unsigned long data );

拥有一个经过初始化的计时器之后,用户现在需要设置过期时间,这通过调用 mod_timer 来完成。由于用户通常提供一个未来的过期时间,他们通常在这里添加 jiffies 来从当前时间偏移。用户也可以通过调用 del_timer 来删除一个计时器(如果它还没有过期):

intmod_timer( struct timer_list *timer, unsigned long expires );voiddel_timer( struct timer_list *timer );

最后,用户可以通过调用 timer_pending(如果正在等待,将返回 1)来发现计时器是否正在等待(还没有发出):

inttimer_pending( const struct timer_list *timer );

计时器示例

我们来检查一下这些 API 函数的实际运行情况。清单 1 提供了一个简单的内核模块,用于展示简单计时器 API 的核心特点。在 init_module 中,您使用 setup_timer 初始化了一个计时器,然后调用 mod_timer 来启动它。当计时器过期时,将调用回调函数 my_timer_callback。最后,当您删除模块时,计时器删除(通过 del_timer)发生。(注意来自 del_timer 的返回检查,它确定计时器是否还在使用。)


清单 1. 探索简单计时器 API

上一篇:学会用Linux C文件读写函数


下一篇:详细了解Linux设备模型中的input子系统

友情链接
Links