Spin_lock 分析
#define spin_lock (lock ) PICK_OP (_lock, lock )
#define TYPE_EQUAL (lock , type ) /
248 __builtin_types_compatible_p(typeof(lock ), type *)
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_RT , spinlock_t 就是下面的这个:
typedef struct {
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 (); /
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 {
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");
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 中断;把对irq 的trace 关掉;
# 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 到:
unsigned long __lockfunc __spin_lock_irqsave (raw_spinlock_t *lock )
131 {
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
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 , spsr 和cpsr 。Cpsr :current program status register, spsr: saved program status register; 详见 arm_architesture_reference_manual.pdf