Linux内核中自旋锁同步分析

<Linux内核设计与实现>6-7-8章关于自旋锁同步中提出
”中断处理下半部的操作中使用自旋锁尤其需要小心:下半部处理和进程上下文共享数据时,由于下半部的处理可以抢占进程上下文的代码,
  所以进程上下文在对共享数据加锁前要禁止下半部的执行,解锁时再允许下半部的执行“
  以下为此处提出的注意点的个人理解,水平有限希望路过的大神能留下宝贵的点评 谢谢~
  1.首先看下in_interrupt()的定义:
  #define in_interrupt()        (irq_count())
  #define irq_count()    (preempt_count() & (HARDIRQ_MASK | SOFTIRQ_MASK \
                 | NMI_MASK))
                 
  2.再看下preempt_count()的定义:
  #define preempt_count()    (current_thread_info()->preempt_count)
  preempt_count分4个域:NMI-HARDIRQ-SOFTIRQ-PREEMPT 整个字段跟抢占相关.当preempt_count!=0禁止抢断,
  否则允许抢断
 
  3.上文提到自旋锁,来看下自旋锁的操作
  spin_lock(spinlock_t* lock)
  {
    raw_spin_lock(&lock->rlock);
  }
  raw_spin_lock(raw_spinlock_t* lock)
  {
    //抢占相关,
    preempt_disable();
    //x86上是锁总线操作
    do_raw_spin_lock(lock);
  }
  preempt_disable()->inc_preempt_count()->add_preempt_count(1)->
  #define add_preempt_count(val) \
  do{ \
  preempt_count() += (val); \
  } while (0);
 执行preempt_count() += (val); 后,spin_lock()使得current_thread_info()->preempt_count字段中的PREEMPT域不为零,进一步说,它禁止进程抢断。


结合上面的分析,来看下共享数据时可能发生抢占的情景:

  1)进程与中断共享数据:中断没有task结构,不接受进程调度,用mutex等互斥睡去后,再也醒不来,因此只能选择自旋锁;
  由于进程随时会被中断打断,自旋锁不能保护共享数据,因此进程在进入临界区前用spin_lock_irq屏蔽中断来替换spin_lock。
  2)进程与tasklet共享数据:tasklet有时是在do_irq中运行的(虽然有时候由ksoftirqd运行),还未完全退出到中断恢复之后,所以
  也是一睡就醒不过来;tasklet被执行的条件是if(!in_interrupt()&&local_softirq_pending()){...}。
  如果进程被中断打断,执行到do_softirq中,进程还是被打断的状态,虽然上了互斥锁(即preempt_count的PREEMPT+1),但是按上文分析in_interrupt()
  只使用NMI-HARDIRQ-SOFTIRQ这3个字段,因此顺利通过if判断,开始执行软中断,使得保护共享数据的原意失败。如果,进程为了保护共享数据,得调用local_bh_disable();
  增加preempt_count:SOFTIRQ域的值,使!in_interrupt()失败;
  3)tasklet-中断共享数据:只能屏蔽中断了吧
 
  附注:IN_INTERRUPT的作用怎么看都觉得跟windows中的IRQL相似,等组织好语句,更新一篇IRQL相关日志
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值