Spin lock 详解

Spin_lock 分析

#define spin_lock (lock )         PICK_OP (_lock, lock )

 

#define TYPE_EQUAL (lock , type ) /

248                  __builtin_types_compatible_p(typeof(lock ), type *)

249

250 #define PICK_OP (op , lock )                                              

251 do {                                                                   

252          if (TYPE_EQUAL ((lock ), raw_spinlock_t ))                        

253                  __spin##op((raw_spinlock_t *)(lock ));                  

254          else if (TYPE_EQUAL (lock , spinlock_t ))                          

255                  _spin##op((spinlock_t *)(lock ));                       

256          else __bad_spinlock_type ();                                    

257 } while (0)

 

__builtin_types_compatible_p 这是一个gcc build in 函数,具体可查gcc.pdf, 这个函数是比较两个type 是否相同。PICK_OP 是看lock 的类型,spinlock_t 是在实时可抢占内核中用的,raw_spinlock_t 是在非抢占或者抢占非实时内核中用的;我们的内核是用raw_spinlock_t , kconfig 中的配置是CONFIG_PREEMPT_DESKTOP ,如果是PREEMPT_RT , 会更加彻底,为什么不用?see next part

# CONFIG_PREEMPT_RT is not set

174 CONFIG_PREEMPT=y

 

typedef struct {

  9          volatile unsigned int lock ;

  10 } raw_spinlock_t ;

如果是定义了CONFIG_PREEMPT_RTspinlock_t 就是下面的这个:

typedef struct {

  22          struct rt_mutex          lock ;

  23          unsigned int            break_lock;

  24 #ifdef CONFIG_DEBUG_LOCK_ALLOC

  25          struct lockdep_map       dep_map;

  26 #endif

  27 } spinlock_t ;

 

然后来看__spin_lock

void __lockfunc __spin_lock (raw_spinlock_t *lock )

230 {

231          preempt_disable ();

232          spin_acquire (&lock ->dep_map, 0, 0, _RET_IP_ );

233          _raw_spin_lock (lock );

234 }

 

如果定义了CONFIG_PREEMPT ,那么是下面,否则就什么都不做,是一个do{}while(0);

 

#define preempt_disable () /

  47 do { /

  48          inc_preempt_count (); /

  49          barrier (); /

  50 } while (0)

 

#define inc_preempt_count () add_preempt_count (1)

如果不是在debug 的话,调用下列函数,

# define add_preempt_count (val ) do { preempt_count () += (val ); } while (0)

current_thread_info ()->preempt_count 直接加1

struct thread_info {

int                     preempt_count ;  /* 0 => preemptable, <0 => bug */

}

preempt_count 不为0 ,内核就不会容许preempt

 

如果不是debug mode,

  # define spin_acquire (l, s , t, i )               do { } while (0)

如果不是dubug mode

define _raw_spin_lock (lock )           __raw_spin_lock (&(lock )->raw_lock)

static inline void __raw_spin_lock (raw_spinlock_t *lock )

  27 {

  28          unsigned long tmp ;

  29

  30          __asm__ __volatile__(

  31 "1:     ldrex   %0, [%1]/n"

  32 "       teq     %0, #0/n"

  33 #ifdef CONFIG_CPU_32v6K

  34 "       wfene/n"

  35 #endif

  36 "       strexeq %0, %2, [%1]/n"

  37 "       teqeq   %0, #0/n"

  38 "       bne     1b"

  39          : "=&r"

  40           : "r" (&lock ->lock ), "r" (1)

  41          : "cc");

  42

  43          smp_mb ();

  44 }

Ldrex 这是一个exclusive ldr ,也就是原子操作,如果lock 不为0 就一直循环。

结论: spinlock 做的事就是禁止schedule ,然后一个死循环;

 

spin_lock_irq 同样也会call __spin_lock_irq, 如下:

void __lockfunc __spin_lock_irq (raw_spinlock_t *lock )

152 {

153          local_irq_disable ();

154          preempt_disable ();

155          spin_acquire (&lock ->dep_map, 0, 0, _RET_IP_ );

156          _raw_spin_lock (lock );

157 }

可见就多了一个local_irq_disable ();

#define local_irq_disable () /

  66          do { raw_local_irq_disable (); trace_hardirqs_off (); } while (0)

#define raw_local_irq_disable () __asm__("cpsid i        @ __cli" : : : "memory", "cc")

Disable 中断;把对irqtrace 关掉;

 

spin_lock_irqsave

# define spin_lock_irqsave (lock , flags )                         /

524 do {                                                             /

525          BUILD_CHECK_IRQ_FLAGS (flags );                           /

526          flags = PICK_OP_RET (_lock_irqsave, lock );               /

527 } while (0)

 

#define BUILD_CHECK_IRQ_FLAGS (flags )                                     /

  15          do {                                                            /

  16                  BUILD_BUG_ON (sizeof(flags ) != sizeof(unsigned long));   /

  17                  typecheck (unsigned long, flags );                        /

  18          } while (0)

这些都很熟悉了,就不再写了;再后面肯定是call 到:

__spin_lock_irqsave

unsigned long __lockfunc __spin_lock_irqsave (raw_spinlock_t *lock )

131 {

132          unsigned long flags ;

133

134          local_irq_save (flags );

135          preempt_disable ();

136          spin_acquire (&lock ->dep_map, 0, 0, _RET_IP_ );

137          /*

138           * On lockdep we dont want the hand-coded irq-enable of

139           * _raw_spin_lock_flags() code, because lockdep assumes

140           * that interrupts are not re-enabled during lock-acquire:

141           */

142 #ifdef CONFIG_PROVE_LOCKING

143          _raw_spin_lock (lock );

144 #else

145          _raw_spin_lock_flags (lock , &flags );

146 #endif

147          return flags ;

148 }

只有local_irq_save 不同:

#define local_irq_save (flags ) /

  68          do {                                    /

  69                  BUILD_CHECK_IRQ_FLAGS (flags );   /

  70                  raw_local_irq_save (flags );      /

  71                  trace_hardirqs_off ();           /

  72          } while (0)

 

#define raw_local_save_flags (x )                                  /

110          ({                                                      /

111          __asm__ __volatile__(                                   /

112          "mrs    %0, cpsr                @ local_save_flags"      /

113          : "=r" (x ) : : "memory", "cc");                         /

114          })

 

cpsr 存起来,MSR 是专门的存psr spsrcpsrCpsrcurrent program status register, spsr: saved program status register; 详见 arm_architesture_reference_manual.pdf

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值