来源:《深入Linux设备驱动程序内核机制》第8章时间管理,本章将讨论这两类时间上的操作的技术细节,设备驱动程序员在掌握了这些幕后的技术之后可以更好地理解设备驱动是如何对时间进行掌控的,当程序中需要对时间进行管理时选择最合适的解决方案。本节为大家介绍时间转换。
时间转换
有时候,设备驱动程序可能需要将用jiffies表达的时间间隔转化成毫秒ms或者是微秒us的形式,这种情况大多出现在需要将时钟滴答这种形式转化成人类易于理解的ms或者是us这样的时间形式下,比如为了在驱动程序中打印出一次DMA传输所花费的时间,在DMA传输开始前记录start_jiffies = jiffies,然后进行DMA传输,在DMA传输结束后记录下end_jiffies = jiffies,这样本次的DMA传输所花费的时间将为time = jiffies_to_msecs(end_jiffies - start_jiffies),这里time的单位将会是ms。
Linux内核源码为此提供了一组相关的转换函数:
- <include/linux/jiffies.h>
- unsigned int jiffies_to_msecs(const unsigned long j);
- unsigned int jiffies_to_usecs(const unsigned long j);
- unsigned long msecs_to_jiffies(const unsigned int m);
- unsigned long usecs_to_jiffies(const unsigned int u);
从这些函数的命名上已经可以很清楚地知道其各自的功能,此处不再赘述。时间转换的另一种情形发生在用户态程序和设备驱动程序的交互上,应用程序员更多地使用秒以及毫秒等时间形式。此种情形下,内核定义了struct timeval和struct timespec两种数据结构:
- <include/linux/time.h>
- struct timespec {
- __kernel_time_t tv_sec; /* seconds */
- long tv_nsec; /* nanoseconds */
- };
- struct timeval {
- __kernel_time_t tv_sec; /* seconds */
- __kernel_suseconds_t tv_usec; /* microseconds */
- };
可见timespec用秒和纳秒来描述时间,而timeval则采用秒和毫秒的形式。内核同样提供了jiffies变量和这两个数据结构的实例间相互转换的函数:
- <include/linux/jiffies.h>
- unsigned long timespec_to_jiffies(const struct timespec *value);
- void jiffies_to_timespec(const unsigned long jiffies, struct timespec *value);
- unsigned long timeval_to_jiffies(const struct timeval *value);
- void jiffies_to_timeval(const unsigned long jiffies, struct timeval *value);
这些函数的用法也是很明显的。
到目前为止,已经讨论了基于jiffies的时间度量的方法,鉴于jiffies自身精度的局限性,如果需要使用更高精度的时间度量方法,也许要借助于某些体系架构特定的计时寄存器,例如很有名的时间戳计数器TSC(Time Stamp Counter),但是使用这些寄存器的程序代码将失去在不同平台之间的可移植性。因为用jiffies来衡量一个时间间隔在绝大多数的情况下已经足以满足需要,所以本书将不再讨论其他的时间度量方法。