spin_lock 相关 -- 原子上下文

18 篇文章 0 订阅

在前面文章描述spin_lock的时候,  要求spin_lock/unlock中间的代码不能有主动放弃cpu,  进入睡眠的函数。 (如sleep, schedule()等)

 

下面提一个问题?

Q: 那在spin_lock/unlock中间代码段执行时, 时间片到了怎么办?

A: spin_lock和spin_unlock中间代码是原子上下文。 故时间片轮转到了, 也不会调度。。。


类似中断上下文, 软中断/task_let内(还是在中断上下文), 以及spin_lock保护的区域内, 都是原子上下文,  无法睡眠。

 

因为如果睡眠了.... 中断上下文就回不来了....


对应的,  进程上下文可以睡眠, 调度,  故有些中断下半部使用工作队列, irq_thread等机制,  使下半部存在于进程上下文, 可以睡眠。


贴一个别人的描述:

内核的一个基本原则就是:在中断或者说原子上下文中,内核不能访问用户空间,而且内核是不能 睡眠的。也就是说在这种情况下,内核是不能调用有可能引起睡眠的任何函数。一般来讲原子上下文指的是在中断或软中断中,以及在持有自旋锁的时候。内核提供 了四个宏来判断是否处于这几种情况里:

#define in_irq()     (hardirq_count()) //在处理硬中断中
#define in_softirq()     (softirq_count()) //在处理软中断中
#define in_interrupt()   (irq_count()) //在处理硬中断或软中断中
#define in_atomic()     ((preempt_count() & ~PREEMPT_ACTIVE) != 0) //包含以上所有情况

这四个宏所访问的count都是thread_info->preempt_count。这个变量其实是一个位掩码。最低8位表示抢占计数,通常由spin_lock/spin_unlock修改,或程序员强制修改,同时表明内核容许的最大抢占深度是256。
8-15位表示软中断计数,通常由local_bh_disable/local_bh_enable修改,同时表明内核容许的最大软中断深度是256。
位16-27是硬中断计数,通常由enter_irq/exit_irq修改,同时表明内核容许的最大硬中断深度是4096。
第28位是PREEMPT_ACTIVE标志。用代码表示就是:
PREEMPT_MASK: 0x000000ff
SOFTIRQ_MASK: 0x0000ff00
HARDIRQ_MASK: 0x0fff0000
凡是上面4个宏返回1得到地方都是原子上下文,是不容许内核访问用户空间,不容许内核睡眠的,不容许调用任何可能引起睡眠的函数。而且代表thread_info->preempt_count不是0,这就告诉内核,在这里面抢占被禁用。
但 是,对于in_atomic()来说,在启用抢占的情况下,它工作的很好,可以告诉内核目前是否持有自旋锁,是否禁用抢占等。但是,在没有启用抢占的情况 下,spin_lock根本不修改preempt_count,所以即使内核调用了spin_lock,持有了自旋锁,in_atomic()仍然会返回 0,错误的告诉内核目前在非原子上下文中。所以凡是依赖in_atomic()来判断是否在原子上下文的代码,在禁抢占的情况下都是有问题的。


链接:

https://blog.csdn.net/yuesichiu/article/details/22206175

另外还有宋宝华的<<是谁关闭了Linux抢占,而抢占又关闭了谁?>>

https://mp.weixin.qq.com/s/wQ8kj_OMngk2pVz9fA-RQA

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值