自旋鎖常用api
1,為什么除了spin_lock() api還定義了spin_lock_irq()等翅睛。
因為:spin_lock()可以防止線程調(diào)度,但不能防止硬件中斷的到來鸣皂,以及隨后的中斷處理函數(shù)(hardirq)的執(zhí)行。
假設一個CPU上的線程T持有了一個spinlock习柠,發(fā)生中斷后芳来,該CPU轉而執(zhí)行對應的hardirq梆暮。如果該hardirq也試圖去持有這個spinlock捉超,那么將無法獲取成功胧卤,導致hardirq無法退出。在hardirq主動退出之前拼岳,線程T是無法繼續(xù)執(zhí)行以釋放spinlock的枝誊,最終將導致該CPU上的代碼不能繼續(xù)向前運行,形成死鎖(dead lock)裂问,
因此如果spin_lock()鎖住得臨界區(qū)可能被中斷打斷侧啼,要使用spin_lock_irq()或者spin_lock_irqsave()
但是即便使用了spin_lock_irqsave()只能關閉本CPU中斷,如果其他CPU上發(fā)生了中斷堪簿,那么這些CPU上的hardirq,也有可能試圖去獲取一個被本地CPU上運行的線程T占有的spinlock皮壁。
不過沒有關系椭更,因為此時hardirq和線程T運行在不同的CPU上,等到線程T繼續(xù)運行釋放了這個spinlock蛾魄,hardirq就有機會獲取到虑瀑,不至于造成死鎖。
2滴须,單核cpu使用spin_lock()會出現(xiàn)死鎖嗎舌狗。
不會,因為spin_lock()關閉了搶占扔水,只能按照順序執(zhí)行痛侍,只要不發(fā)生中斷是不會發(fā)生死鎖的,但是若臨界區(qū)可能發(fā)生中斷仍然可能死鎖魔市。
3主届,自旋鎖是怎么搶占的赵哲。
4,自旋鎖與互斥鎖的區(qū)別
自旋鎖和互斥鎖用于處理內(nèi)核中并發(fā)訪問君丁,它們有各自的使用對象枫夺。·
互斥鎖保護進程的關鍵資源绘闷,而自旋鎖保護IRQ處理程序的關鍵部分橡庞。·互斥鎖讓競爭者在獲得鎖之前睡眠印蔗,而自旋鎖在獲得鎖之前一直自旋循環(huán)(消耗CPU)毙死。·
鑒于上一點喻鳄,自旋鎖不能長時間持有扼倘,因為等待者在等待取鎖期間會浪費CPU時間;而互斥鎖則可以長時間持有除呵,只要保護資源需要再菊,
因為競爭者被放入等待隊列中進入睡眠狀態(tài)。[插圖]當處理自旋鎖時颜曾,
請牢記:只是持有自旋鎖線程搶占被禁止纠拔,而自旋鎖的等待者沒有禁止搶占。
自旋鎖內(nèi)核實現(xiàn)
自旋鎖結構體定義
typedef struct spinlock {
union {
struct raw_spinlock rlock;
#ifdef CONFIG_DEBUG_LOCK_ALLOC
# define LOCK_PADSIZE (offsetof(struct raw_spinlock, dep_map))
struct {
u8 __padding[LOCK_PADSIZE];
struct lockdep_map dep_map;
};
#endif
};
} spinlock_t;
typedef struct raw_spinlock {
arch_spinlock_t raw_lock;
#ifdef CONFIG_DEBUG_SPINLOCK
unsigned int magic, owner_cpu;
void *owner;
#endif
#ifdef CONFIG_DEBUG_LOCK_ALLOC
struct lockdep_map dep_map;
#endif
} raw_spinlock_t;
typedef struct {
union {
u32 slock;
struct __raw_tickets {
#ifdef __ARMEB__
u16 next;
u16 owner;
#else
u16 owner;
u16 next;
#endif
} tickets;
};
} arch_spinlock_t;
spin_lock_irqsave實現(xiàn)
#define spin_lock_irqsave(lock, flags) \
do { \
raw_spin_lock_irqsave(spinlock_check(lock), flags); \
} while (0)
#define raw_spin_lock_irqsave(lock, flags) \
do { \
typecheck(unsigned long, flags); \
flags = _raw_spin_lock_irqsave(lock); \
} while (0)
對于單核
/*
* 定義在include/linux/spinlock_api_up.h中
* 對于單核自旋鎖的功能就被弱化為禁止搶占泛豪,
* 最終實際只執(zhí)行的是preempt_disable()-關閉搶占
*/
#define _raw_spin_lock_irqsave(lock, flags) __LOCK_IRQSAVE(lock, flags)
#define __LOCK_IRQSAVE(lock, flags) \
do { local_irq_save(flags); __LOCK(lock); } while (0)
/*
* 在arm體系結構中定義如下
* In the UP-nondebug case there's no real locking going on, so the
* only thing we have to do is to keep the preempt counts and irq
* flags straight, to suppress compiler warnings of unused lock
* variables, and to add the proper checker annotations:
*/
#define ___LOCK(lock) \
do { __acquire(lock); (void)(lock); } while (0)
#define __LOCK(lock) \
do { preempt_disable(); ___LOCK(lock); } while (0)
對于多核
/*
* 定義在include/linux/spinlock_api_smp.h中
* 多核比較復雜稠诲,
*/
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_);
LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock);
return flags;
}
static inline void do_raw_spin_lock(raw_spinlock_t *lock) __acquires(lock)
{
__acquire(lock);
arch_spin_lock(&lock->raw_lock);
mmiowb_spin_lock();
}
/*
* 在arm體系結構中
*ARMv6 ticket-based spin-locking.
* A memory barrier is required after we get a lock, and before we
* release it, because V6 CPUs are assumed to have weakly ordered
* memory.
*/
static inline void arch_spin_lock(arch_spinlock_t *lock)
{
unsigned long tmp;
u32 newval;
arch_spinlock_t lockval;
prefetchw(&lock->slock);
__asm__ __volatile__(
"1: ldrex %0, [%3]\n"
" add %1, %0, %4\n"
" strex %2, %1, [%3]\n"
" teq %2, #0\n"
" bne 1b"
: "=&r" (lockval), "=&r" (newval), "=&r" (tmp)
: "r" (&lock->slock), "I" (1 << TICKET_SHIFT)
: "cc");
while (lockval.tickets.next != lockval.tickets.owner) {
wfe();
lockval.tickets.owner = READ_ONCE(lock->tickets.owner);
}
smp_mb();
}
參考:
https://www.ixigua.com/6940602677994717708?id=6872657862988923392&logTag=79b91f342c90aac06619
https://www.cnblogs.com/sky-heaven/p/13602357.html
https://mp.weixin.qq.com/s/viUgMAnVgC_bHyVifkHqsQ
https://mp.weixin.qq.com/s/mosYi_W-Rp1-HgdtxUqSEg