内核通过定时器中断来跟踪时间变化。时钟中断的间隔为HZ。
unsigend long jiffies (只读)记录了自最近一次系统启动之后的时钟滴答数。大约五十天左右会出现一次溢出,需要在使用时进行处理。因为jiffies 通过时钟中断进行数据更新,因此当禁用中断的情况下,该数值无法更新。需要格外注意由此造成死循环的可能性!
jiffies 表示未来N秒后的时间: jiffies + N × HZ 转换为毫秒值:( jiffies + N * HZ ) * 1000
时间戳计数器:TSC 随时钟周期不断递增。rdtsc ( low 32 , high 32 ) ,rdtscl ( low 32 ) 或者 rdtscll ( var 64 )进行读取。
获取当前时间,时间转换:
绝对时间jiffies 值 = unigned long mktime ( unsigned int year , unsigned int month , unsigned int day , unsigned int hour , unsigned int min , unsigned int second ).
反向 do_gettimeofday ( struct timeval * tv )或者 struct timespec current_kernel_time( void )
延迟执行:
while ( timebefore ( jiffies , j1 ) )
{
schedul ();
}
这种情况下,进程会在等待时释放CPU。但是并不是最优化方案。因此当前进程依然在运行队列中。因此依然会被系统二次调度运行,然后再次让出。
超时:
long wait_event_timeout ( wait_queue_head_t q , condition , long timeout )
long wait_event_interruptible_timeout ( wait_queue_head_t q , condition , long timeout )
这里timeout是指jiffies 而不是绝对时间。
此时进程在等待队列上休眠,但是会在超时到期时返回。
set_current_state( Task_interruptible );//设置程序状态。这样只有当超时到达且程序状态变为task_running才会运行这个进程。
schedule _timeout ( delay );
ndelay ( unsigned long nsec )纳秒
udelay ( unsigned long usec )微妙
mdelay( unsigned long usec ) 毫秒
定时器:
tasklet :允许内核申请某段代码在未来某个时刻运行。因为该代码是在中断上下文中运行,因此必须为原子操作,不可休眠;必须运行在提交代码的处理器上;
工作队列workqueue :允许内核申请某段代码在未来的某个时刻运行。非原子化,且可以在指定处理器运行。
共享队列:各驱动不需要定义自己的工作队列,而使用所有模块共享队列。但是,不可长期占用此队列。