在阅读driver 源码时,经常看到spin_lock, spin_lock_irq,spin_lock_irqsave 这几个同步方法,那当要使用spinlock的时候,需要怎么选择呢?看一下它们实现的差异:
spin_lock() ->_raw_spin_lock(&lock->rlock)
static inline void __raw_spin_lock(raw_spinlock_t *lock) { preempt_disable(); spin_acquire(&lock->dep_map, 0, 0, _RET_IP_); LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock); }
可以看到先禁止了调度,再去拿锁。这个过程仅仅禁止调度,如果有中断进来,还是可以被打断,切换到中断上下文运行。
spin_lock_irq() -> _raw_spin_lock_irq(&lock->rlock)
static inline void __raw_spin_lock_irq(raw_spinlock_t *lock) { local_irq_disable(); preempt_disable(); spin_acquire(&lock->dep_map, 0, 0, _RET_IP_); LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock); }
首先disable local irq(禁止当前cpu的中断),再禁止调度,此时没有任何情况可以打断,是完全安全的。如果临界资源中断处理函数也会使用,需要使用spin_lock_irq来保证同步。
spin_lock_irqsave() -> _raw_spin_lock_irqsave(&lock->rlock)
static inline unsigned long __raw_spin_lock_irqsave(raw_spinlock_t *lock) { unsigned long flags; local_irq_save(flags); preempt_disable(); spin_acquire(&lock->dep_map, 0, 0, _RET_IP_); /* * On lockdep we dont want the hand-coded irq-enable of * do_raw_spin_lock_flags() code, because lockdep assumes * that interrupts are not re-enabled during lock-acquire: */ #ifdef CONFIG_LOCKDEP LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock); #else do_raw_spin_lock_flags(lock, &flags); #endif return flags; }
local_irq_save -> arch_local_irq_save 这里面会将irq flag保存起来,然后再disable local irq, 最后会将当前irq flags返回。在spin_unlock_irqrestore的时候,返回的flags会当作参数传下去,unlock的同时,会将lock前的irq状态还原。
static inline void __raw_spin_lock_bh(raw_spinlock_t *lock) { __local_bh_disable_ip(_RET_IP_, SOFTIRQ_LOCK_OFFSET); spin_acquire(&lock->dep_map, 0, 0, _RET_IP_); LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock); }
bh是bottom half的意思,__local_bh_disable_ip 会禁止softirq,但是硬中断可以响应。这个比较少见,在阅读上面三个spinlock函数时看到这个,顺便查看了一下。
spinlock翻译成中文叫做自旋锁,在等待过程中,它是忙等,不会发生睡眠(因为获取锁前先禁止调度,别人是无法抢占的),所以它适合在中断上下文这种不能发生睡眠的地方使用。但由于是禁止抢占,那么临界区执行的代码需要简短,不能够长时间禁止调度,否则系统将出现性能问题。如果怀疑有这类问题,可以使用ftrace的irqoff/preemptoff/preemptirqoff 来检查,会记录一次关闭中断或者抢占最长时间的操作。
spin_lock, spin_lock_irq, spin_lock_irqsave, spin_lock_bh
原文:https://www.cnblogs.com/hyyft/p/14825163.html