内核空间几种长延时函数实现策略的优劣讨论 (2012-02-27 22:04)
这里所谓的长延时,是指其实现时间延时的粒度可以在HZ这一水准上。《深入Linux设备驱动程序内核机制》第8章"时间管理"中提到了好几种实现延时功能的机制,包括长延时短延时等,对每一种延时机制的优劣都有理论上的分析。
本帖旨在从另一个角度探讨一下其中所提到的“长延时”的三个实现方式,这些延时方式都试图让出处理器,换句话说都是基于非忙等待的实现(因为长延时若是忙等待,将极大浪费处理器的资源)与书中的原理分析不同之处在于,我希望在本帖中以实际的代码验证的方式来使那种理论上的分析更加直观化:我们在一个内核模块,比如demodev.ko的初始化函数中调用这些延时函数,然后通过ps命令来查看延时期间insmod进程的状态。
首先我们看第一种实现(为了有足够的时间让我们去查看进程的状态,我将这种“长延时”延时间隔设定30S,这样足够我们在此延时的窗口期间观察insmod进程的状态):
- void delay_30s(void){
- unsigned long j = jiffies + 30 * HZ;
- while(time_before(jiffies, j))
- schedule();
- }
root@build-server:/home/dennis/book_2nd_edition/book_sourcecode# ps aux | grep insmod
root 6491 100 0.0 4420 576 pts/2 R+ 21:55 0:28 insmod demodev.ko
root 6514 0.0 0.0 13448 872 pts/3 S+ 21:56 0:00 grep --color=auto insmod
insmod进程的R+状态意味着当前进程处在后台一个运行的状态下。
再来看一个改进版:
- void delay_30s(void){
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(30 * HZ);
- }
root@build-server:/home/dennis/book_2nd_edition/book_sourcecode# ps aux | grep insmod
root 6300 0.0 0.0 4420 580 pts/2 S+ 21:53 0:00 insmod demodev.ko
root 6306 0.0 0.0 13448 868 pts/3 S+ 21:53 0:00 grep --color=auto insmod
insmod进程的S+状态意味着当前进程处在后台一个睡眠的状态下。 如果你的调用上下文允许当前进程进入睡眠,那么这是一个非常完美的实现:睡眠的进程不占用处理器资源,同时延时的目的也达到了。
最后,我们来试图改进第一种的那个方案,代码如下:
- void delay_30s(void){
- unsigned long j = jiffies + 30 * HZ;
- while(time_before(jiffies, j)){
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule();
- }
最后我想提一下那个schedule_timeout函数,如果调用该函数前没有用改变进程的状态,那么这个函数基本上是瞬间返回(其实取决于当前处理器运行队列及调度器行为),虽然它初始化并提交了一个定时器结点,但是它调用schedule时基本上是很快会被调度器再次调度,然后它有个 del_singleshot_timer_sync(&timer)调用,后者将把之前提交的定时器结点从定时器管理队列中摘除,因为如果当前进程一旦结束,放到此前提交的定时器结点中的current将指向无意义的空间。
博客推荐文章
- Linux设备驱动程序学习(17)-USB 驱动程序(一) (2011-10-27 23:59:07)
- Linux设备驱动程序学习 (2011-03-18 20:17:45)
- linux设备驱动程序第三版 (2011-04-22 17:48:51)
- Linux设备驱动程序编写 (2011-05-10 13:40:04)
- Linux设备驱动程序学习 (2011-09-12 08:26:53)
我把第三个例子的结果给弄混了。看到最后的时候,以为第一个例子也是这个结果。所以想不明白了。多谢
这是第一个例子:
void delay_30s(void){
unsigned.....
这是第一个例子:
void delay_30s(void){
unsigned long j = jiffies + 30 * HZ;
while(time_before(jiffies, j))
schedule();
}
这里也没有设置TASK_(UN)INTERRUPTIBLE,与cpu_idle很类似啊。为什么结果不同呢?
调度器不管这个事情,那么就需要明确的将current放到某个等待队列中吗?
那为什么其它内核的线程,如cpu_idle可以.....
调度器不管这个事情,那么就需要明确的将current放到某个等待队列中吗?
那为什么其它内核的线程,如cpu_idle可以直接调用schedule而没有其它操作呢?cpu_idle会在schedule后,仍然有运行的机会呢。
当前进程从处理器运行队列中移开,一旦移开,current进程将处于流浪状态,谁会去收留它呢?它将永远失去被处理器调度的机会。
被调度出去.....
当前进程从处理器运行队列中移开,一旦移开,current进程将处于流浪状态,谁会去收留它呢?它将永远失去被处理器调度的机会。
被调度出去以后,为什么永远不会被执行呢?