一、内核中如何记录时间
任何程序都需要时间控制,其主要目的是:
1.测量时间流逝和比较时间
2.知道当前时间
3.指定时间量的延时操作
为达到这个目的,应用程序使用日历时间(年月日时分秒)或者自1970年1月1日零时零分零秒到当前的秒数来度量时间的流逝,但内核中需要更加有精度的时间度量,因此内核使用时钟嘀嗒来记录时间。时钟中断发生后内核内部时间计数器增加1(即:增加1个时钟嘀嗒),系统引导时为0,当前值为自上次系统引导以来的时钟滴答数,程序可通过内核定义的全局变量jiffies_64或jiffies来访问。真实硬件上每秒的嘀嗒数从
50 到 1200 不等
,x86上默认为1000,而tiny4412上默认为200,出于统一编程接口的考虑,内核定义了一个宏HZ(可通过make menuconfig更改),它表示1秒钟的嘀嗒数,可供程序使用。内核一般通过jiffies值来获取当前时间。
Jiffies 和 jiffies_64是 unsigned long 类型只读变量。(1秒加HZ次)
补充:板子默认jiffies初值并不是0,而是-5分钟
比较2个时间的大小,常用内核的如下宏定义:
#include
int time_after(unsigned long a, unsigned long b);
int time_before(unsigned long a, unsigned long b);
int time_after_eq(unsigned long a, unsigned long b);
int time_before_eq(unsigned long a, unsigned long b);
二、内核时间
1.忙等延时
2.睡眠延时
短延时
当一个设备驱动需要等待硬件的反应时间, 涉及到的延时常常是最多几个毫秒
。此种延时就是短延时,一般采用忙等待。相关函数如下:
-
#include
-
void ndelay(unsigned long
nsecs);
-
void udelay(unsigned long
usecs);
-
void mdelay(unsigned long
msecs);
长延时
如果需要延后较长时间,就可以采用长延时。长延时可分为忙等待和睡眠等待两种方式。
struct timeval {
__kernel_time_t tv_sec; /* seconds */
__kernel_suseconds_t tv_usec; /* microseconds */
};
struct timespec {
long ts_sec;
long ts_nsec;
};
获取当前时间
void do_gettimeofday(struct timeval *tv)
void getnstimeofday(struct timespec *ts)
signed long __sched schedule_timeout(signed long timeout)
高精度定时器是采用红黑树实现的,而普通的定时器是采用时间轮循算法实现的
3.内核定时器(基于软中断)
struct timer_list {
struct list_head entry;
unsigned long expires;
struct tvec_base *base;
void (*function)(unsigned long);
unsigned long data;
int slack;
.......
};
//初始化定时器
init_timer(&timer);
timer.expires = jiffies + HZ * 5;
timer.function = fun;
timer.data = 100;
//把定时器插入相应的链表中
add_timer(&timer);
del_timer(&timer);
4.高精度定时器
单纯的在高精度定时器模式下操作高精度定时器,整个操作框架如下:
初始化hrtimer_init,通过hetimer结构体设置相关数据,比如定时时长等->开启定时器hrtimer_start->运行高精度定时器hrtimer_run_queues->触发中断,调用中断回调函数,hrtimer_interrupt->移除高精度定时器remove_hrtimer.
高分辨率定时器可以基于两种时钟(时钟基础,clock base):一种是单调时钟(CLOCK_MONOTONIC),在系统启动时,从0开始;另一种时钟(CLOCK_REALTIME)表示系统的实际时间。
struct hrtimer {
struct timerqueue_node node;
ktime_t _softexpires;
enum hrtimer_restart (*function)(struct hrtimer *);
struct hrtimer_clock_base *base;
unsigned long state;
.......
};
enum hrtimer_restart {
HRTIMER_NORESTART, /* Timer is not restarted */
HRTIMER_RESTART, /* Timer must be restarted */
};
static inline u64 hrtimer_forward_now(struct hrtimer *timer, ktime_t interval)
hrtimer_init – 给定时钟初始化定时器
@timer: 将要被初始化的定时器
@clock_id: 将要被用到的时钟
@mode: 定时器模式 abs/rel
mode可以使用五个常数,如下:
enum hrtimer_mode {
HRTIMER_MODE_ABS = 0x0, /* 时间是绝对的 */
HRTIMER_MODE_REL = 0x1, /*时间是相对的 */
HRTIMER_MODE_PINNED = 0x02, /* 定时器被绑定到CPU */
HRTIMER_MODE_ABS_PINNED = 0x02,
HRTIMER_MODE_REL_PINNED = 0x03,
};
hrtimer_start(struct hrtimer *timer,
ktime_t tim, const enum hrtimer_mode
mode),
@timer代表将要被添加的定时器
@tim代表到期时间
@mode代表定时器模式
如果启动成功,则返回0,否则返回1。
int hrtimer_cancel(struct hrtimer *timer)(一直等处理程序执行完毕)
int hrtimer_try_to_cancel(struct hrtimer *timer)(正在执行因而无法停止,则返回-1)
hrtimer_interrupt(struct clock_event_device *dev)
阅读(2296) | 评论(0) | 转发(1) |