自旋鎖常用api

1,為什么除了spin_lock() api還定義了spin_lock_irq()等。
因?yàn)椋簊pin_lock()可以防止線程調(diào)度,但不能防止硬件中斷的到來,以及隨后的中斷處理函數(shù)(hardirq)的執(zhí)行。
假設(shè)一個CPU上的線程T持有了一個spinlock,發(fā)生中斷后,該CPU轉(zhuǎn)而執(zhí)行對應(yīng)的hardirq。如果該hardirq也試圖去持有這個spinlock,那么將無法獲取成功,導(dǎo)致hardirq無法退出。在hardirq主動退出之前,線程T是無法繼續(xù)執(zhí)行以釋放spinlock的,最終將導(dǎo)致該CPU上的代碼不能繼續(xù)向前運(yùn)行,形成死鎖(dead lock),
因此如果spin_lock()鎖住得臨界區(qū)可能被中斷打斷,要使用spin_lock_irq()或者spin_lock_irqsave()
但是即便使用了spin_lock_irqsave()只能關(guān)閉本CPU中斷,如果其他CPU上發(fā)生了中斷,那么這些CPU上的hardirq,也有可能試圖去獲取一個被本地CPU上運(yùn)行的線程T占有的spinlock。
不過沒有關(guān)系,因?yàn)榇藭rhardirq和線程T運(yùn)行在不同的CPU上,等到線程T繼續(xù)運(yùn)行釋放了這個spinlock,hardirq就有機(jī)會獲取到,不至于造成死鎖。
2,單核cpu使用spin_lock()會出現(xiàn)死鎖嗎。
不會,因?yàn)閟pin_lock()關(guān)閉了搶占,只能按照順序執(zhí)行,只要不發(fā)生中斷是不會發(fā)生死鎖的,但是若臨界區(qū)可能發(fā)生中斷仍然可能死鎖。
3,自旋鎖是怎么搶占的。

4,自旋鎖與互斥鎖的區(qū)別
自旋鎖和互斥鎖用于處理內(nèi)核中并發(fā)訪問,它們有各自的使用對象?!?br>
互斥鎖保護(hù)進(jìn)程的關(guān)鍵資源,而自旋鎖保護(hù)IRQ處理程序的關(guān)鍵部分?!せコ怄i讓競爭者在獲得鎖之前睡眠,而自旋鎖在獲得鎖之前一直自旋循環(huán)(消耗CPU)。·
鑒于上一點(diǎn),自旋鎖不能長時間持有,因?yàn)榈却咴诘却℃i期間會浪費(fèi)CPU時間;而互斥鎖則可以長時間持有,只要保護(hù)資源需要,
因?yàn)楦偁幷弑环湃氲却?duì)列中進(jìn)入睡眠狀態(tài)。[插圖]當(dāng)處理自旋鎖時,
請牢記:只是持有自旋鎖線程搶占被禁止,而自旋鎖的等待者沒有禁止搶占。
自旋鎖內(nèi)核實(shí)現(xiàn)

自旋鎖結(jié)構(gòu)體定義
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實(shí)現(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中
* 對于單核自旋鎖的功能就被弱化為禁止搶占,
* 最終實(shí)際只執(zhí)行的是preempt_disable()-關(guān)閉搶占
*/
#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體系結(jié)構(gòu)中定義如下
* 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中
* 多核比較復(fù)雜,
*/
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體系結(jié)構(gòu)中
*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