1. jiffies
HZ是每秒产生的时钟中断数。
jiffies是系统启动后,时钟中断的次数可通过它来计算时间。可见分辨率低。
系统通过它来取得当前时间,也用来处理一些低分辨率的时间处理,如鼠标双击。
2. 高精度计数
绝大多数cpu有一个随着时钟周期不断递增的计数寄存器,这是完成高分辨率计数的唯一方法。比如x86上有名的TSC时间戳计数器。
内核提供了 cycles_t get_cycles(void) ,它可在任何平台上取得计数寄存器。如果没有则返回0。
3. 延迟执行代码
1) 长延时:需要推后执行的时间要多个时钟ticks
----忙等jiffies:
-
while (time_before(jiffies, j1))
-
cpu_relax();
问题:严重降低性能:如果内核非抢占,此代码会锁住系统;如果进入代码前禁用了中断,则jiffies不更新,系统挂死。
----让出处理器:
-
while (time_before(jiffies, j1)) {
-
schedule();
-
}
虽然貌似让系统重新调度,但实际上此进程仍处于可运行态,仍可能被调度到。
----超时等待
利用等待队列,可将等待队列等待的条件划明界限。即jiffies到则从等待队列上唤醒。内核函数为:
long wait_event_timeout(wait_queue_head_t q, condition, long timeout);
内核还提供了 schedule_timeout(),避免手工申请等待队列。但它需要先设置进程状态,如:
-
set_current_state(TASK_INTERRUPTIBLE);
-
schedule_timeout (delay);
2) 短延迟
内核提供udelay实现微秒级的延迟。它根据系统引导时计算出的处理器速度确定循环忙等的次数。
毫秒级的延迟还可以调用sleep系函数,这些函数不忙等。
4. 内核定时器
与延迟执行区别是,定时器设置后本身流程继续,定时到走的流程与本身无关,为异步运行。所以定时器函数执行时,可能处于非进程上下文中。in_interrupt()判断是否处理中断上下文。in_atomic()则是不可调度点的标志(中断,软中断,自旋锁)。非进程上下文的函数需要按以下规则处理:
a. 不可访问用户空间,因为无进程上下文;
b. current无意义;
c. 不可睡眠或调度,比如调用kmalloc(..., GFP_KERNEL)、信号量等
定时函数要额外注意并发处理保护。
5. tasklet
用于稍后某时执行函数,不指定时间。也通过软中断实现。
同一tasklet执行不会在多cpu上同时进行。
执行的时机:如果不忙则立即执行;最晚不超过一个tick
6. 工作队列
功能类似tasklet,但区别如下:
a. 工作队列运行在内核线程中,因此可以睡眠;
b. 工作队列可以更长的延迟。
阅读(634) | 评论(0) | 转发(0) |