Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1586727
  • 博文数量: 77
  • 博客积分: 1205
  • 博客等级: 少尉
  • 技术积分: 4476
  • 用 户 组: 普通用户
  • 注册时间: 2010-04-22 21:48
文章分类
文章存档

2018年(1)

2017年(1)

2015年(1)

2014年(18)

2013年(12)

2012年(44)

分类: LINUX

2012-10-09 13:21:41

前阵子有网友发短消息问:“...在研究自旋锁的时候,发现在 spin_lock_irq函数,也就是在自旋锁中关闭中的这类函数中,既然已经关闭了本地中断,再禁止抢占有没有多余。也就是说,既然本地中断已经禁止 了,在本处理器上是无法被打断的,本地调度器也无法运行,也就不可以被本地调度程序调度出去..."

从spinlock设计原理看,使用它的时候,在临界区间是务必确保不会发生进程切换。现在的问题是,如果已经关闭了中断,在同一处理器上如果不关掉内核抢占的特性,会不会有进程调度的情况发生,如果没有,那我个人的理解是,在local_irq_disable之后再使用peempt_disable就多此一举了。

这个在SMP系统上最好理解了,假设有A和B两个处理器,使用spin lock的进程(简称"焦点进程"好了)运行在处理器A上,一种很明显的情形就是如果有个进程(简称“睡眠进程”好了)先于焦点运行,但是因为等待网卡的一个数据包,它进入了sleep状态,然后焦点开始被调度运行,后者在spin lock获得锁后进入临界区,此时网卡收到了"睡眠进程“的数据包,因为焦点只是关闭了A上的中断,所以B还是会接收并处理该中断,然后唤醒“睡眠进程“,后者进入运行队列,此时出现一个调度点,如果”睡眠“的优先级高于”焦点“,那么就有进程切换发生了,但是如果焦点所使用的spin lock中关闭了内核抢占,那么就使得先前的进程切换成为不可能。

如果是在单处理器系统上,local_irq_disable实际上关闭了所有(其实就一个)处理器的中断,所有有中断引起的调度点都不可能存在,此时有无其他与中断无关的调度点出现呢?在2.4上,因为没有抢占,这种情形绝无可能,事实上,早期的内核很大程度上是依赖local_irq_disable来做资源保护,这个看看2.4的内核源码就很清楚了,里面有大量的对local_irq_disable函数的直接调用。2.6有了抢占的概念,UP下关闭中断,如前所述,实际上已经杜绝了内部因素导致的“就绪队列中加入一个进程”这个调度点的可能(内部因素实际上只剩下了一个处理器的异常,但是关中断的情形下,即便有异常也不会导致进程的切换),因此到这里我们可以这样说,在UP上关闭中断情形下,preempt_disable其实是多余的。但是我们知道,spin lock是一种内核API,不只是kernel的开发者在用,更多的内核模块(.ko,实际当中更多地表现形式是设备驱动程序)开发者也在使用。内核的设计者总是试图将其不能控的代码(所谓的外部因素了)可能给内核带来的损失降低至最小的程度,这个表现在内核对中断处理框架的设计时尤其明显,所以在UP系统下先后使用local_disable_irq和preempt_disable,只是尽量让你我可能在spin lock/unlock的临界区中某些混了头的代码不至于给系统带来灾难,因为难保某些人不会在spin lock的临界区中,比如去wake_up_interruptible()一个进程,而被唤醒的进程在可抢占的系统里就是一个打开的潘多拉盒子。



阅读(13376) | 评论(17) | 转发(11) |
给主人留下些什么吧!~~

MagicBoy20102013-08-01 05:43:03

Z_H_Z1102:假如我设计一个极限情况,如果一个进程被spin锁住的进程,占用CPU的时间超过了0.95 s,如果不进行进程调度的话是会饿死普通进程吧?
我觉得进程调度应该是一个绝对的方法,一个进程时间片用完了就要换到低优先级的进程以保证其他进程不被饿死,阻止了中断和抢占,但应该并不能进程schedule()的发生;
如果spin_lock_irqsave能够阻止进程调度的话,那么为何只说阻止了中断和抢占,直接说阻止了进程调度不是更easy一些?

如果一个进程时间片用完当然会导致进程的切换,但是进程时间片需要时钟中断去更新,local_irq_disable实际上阻止了这种可能性。抢占意味着当中断发生时,一个进程被投入到当前cpu的运行队列,调度器需要检查它与被中断进程的优先级以确定是否要抢占它。可以简单做个试验,你写一个内核模块,在模块(test.ko)的初始化函数中这样做:
spin_lock_irqsave(...);
unsigned long j = jiffies + 300 * HZ;
while (time_before (jiffies, j));
spin_unlock_irqsave(...);

在多处理系统中你可以将insmod进程绑定到cpu 0上:
#taskset 0x000000001 insmod test.ko

这样你应该有机会从其他cpu上去察看cpu0上task switch发生的次数(/proc?),在cpu0上insmod进程在模块的初始化函数中在spin_lock_irqsave下面忙等待5分钟,这个时间远大于一个进程所拥有的时间

回复 | 举报

Z_H_Z11022013-07-31 16:44:27

MagicBoy2010:spin_lock_irqsave内含preempt_disable和local_irq_disable,在本地CPU中断关闭的情形下你能想到的进程调度的情形是什么呢?不太明白你困惑的原因...

假如我设计一个极限情况,如果一个进程被spin锁住的进程,占用CPU的时间超过了0.95 s,如果不进行进程调度的话是会饿死普通进程吧?
我觉得进程调度应该是一个绝对的方法,一个进程时间片用完了就要换到低优先级的进程以保证其他进程不被饿死,阻止了中断和抢占,但应该并不能进程schedule()的发生;
如果spin_lock_irqsave能够阻止进程调度的话,那么为何只说阻止了中断和抢占,直接说阻止了进程调度不是更easy一些?

回复 | 举报

MagicBoy20102013-07-31 10:53:27

Z_H_Z1102:Hi   博主:
   从这篇博文中,其一的论点就是“spin_lock_irqsave保护的临界区内容是禁止本地CPU的进程调度的”。这个问题困扰了我很久,我也在网上搜了很多,总之大家的众说风云,我也在我们开发的双核安卓手机上面做过实验,但无法设计出来一个很好的实验,总之还是无法证明此问题。
    对于这个问题,博主是否有进一步的论点能够支持此论点,我想进一步和你探讨一下,谢谢

spin_lock_irqsave内含preempt_disable和local_irq_disable,在本地CPU中断关闭的情形下你能想到的进程调度的情形是什么呢?不太明白你困惑的原因...

回复 | 举报

Z_H_Z11022013-07-30 20:12:33

Hi   博主:
   从这篇博文中,其一的论点就是“spin_lock_irqsave保护的临界区内容是禁止本地CPU的进程调度的”。这个问题困扰了我很久,我也在网上搜了很多,总之大家的众说风云,我也在我们开发的双核安卓手机上面做过实验,但无法设计出来一个很好的实验,总之还是无法证明此问题。
    对于这个问题,博主是否有进一步的论点能够支持此论点,我想进一步和你探讨一下,谢谢

MagicBoy20102012-10-12 13:26:12

tekkamanninja: 我也不太确定,所以请教下陈老师~~~~~
RTFSCing~~~.....
刚看了一下3.4.3的内核代码, 在内核路径中,如果在中断关闭的情形下发生异常,异常返回时应是不会发生进程切换(都是在preempt enable的情况下)arch/x86/kernel/entry_32.S:

ret_from_exception:
    ...
    cmpl $USER_RPL, %eax
    jb resume_kernel
...
ENTRY(resume_kernel)
   ...
need_resched:   /*我们假设在关闭中断时没有关闭内核抢占*/
   ..