一、自旋鎖 自旋鎖是專為防止多處理器并發(fā)而引入的一種鎖,它在內(nèi)核中大量應(yīng)用于中斷處理等部分(對(duì)于單處理器來(lái)說(shuō),防止中斷處理中的并發(fā)可簡(jiǎn)單采用關(guān)閉中斷的方式,即在標(biāo)志寄存器中關(guān)閉/打開(kāi)中斷標(biāo)志位,不需要自旋鎖)。 自旋就是自己連續(xù)的循環(huán)等待。如果你有抱著你的愛(ài)人旋轉(zhuǎn)的經(jīng)歷,那么你應(yīng)該知道一件事情,為了安全,你不能旋轉(zhuǎn)太久,你的愛(ài)人如果頭昏,也想你早日釋放。是的,自旋的缺點(diǎn),就是它頻繁的循環(huán)直到等待鎖的釋放,將它用于可以快速完成的代碼中才好。 自旋不能搶占,但能中斷。 相關(guān)話題:SMP和cpu。多個(gè)cpu和單個(gè)cpu。很多書說(shuō)自旋鎖只能在多處理機(jī)中使用,這是不正確的。 首先定義 Spinlock_t lock; 對(duì)不起,我只能找到arm平臺(tái)的鎖了 /* * ARMv6 Spin-locking. * * We (exclusively) read the old value, and decrement it. If it * hits zero, we may have won the lock, so we try (exclusively) * storing it. * * Unlocked value: 0 * Locked value: 1 */ typedef struct { volatile unsigned int lock; #ifdef CONFIG_PREEMPT unsigned int break_lock; #endif } spinlock_t; #define SPINLOCK_MAGIC0x1D244B3C typedef struct { unsigned long magic; volatile unsigned long lock; volatile unsigned int babble; const char *module; // 所屬模塊 char *owner; int oline; } spinlock_t; Lock為0時(shí)可以用,1是等待。0像鎖孔,當(dāng)沒(méi)有鑰匙插進(jìn)去時(shí),它才可以插進(jìn)去 怎么初始化呢? #define spin_lock_init(x) do { (x)->magic = SPINLOCK_MAGIC; (x)->lock = 0; ;0初始化,表示可用 (x)->babble = 5; (x)->module = __FILE__; (x)->owner = NULL; (x)->oline = 0; } while (0) 定義一個(gè)自旋鎖的方法很有意思,Spinlock_t lock=????? 可以通過(guò)spin_lock Spin_lock_irqsave 來(lái)調(diào)用自旋鎖,后者不允許中斷。前者有可能在上鎖中發(fā)生中斷。 還有spin_trylock 這是一個(gè)絕不妥協(xié)的函數(shù),它不等待。 恢復(fù)為spin_unlock Spin_unlock_irqrestore 考查下面代碼 #define spin_lock_irqsave(lock, flags)_spin_lock_irqsave(lock, flags) #define _spin_lock_irqsave(lock, flags) do { local_irq_save(flags); 保存中斷請(qǐng)求標(biāo)志 preempt_disable(); 不允許搶占 _raw_spin_lock(lock); __acquire(lock); } while (0) 二、自旋鎖綜合使用 下面是一個(gè)使用的例子,你可以使用source insight查到它 /* never called when PTRS_PER_PMD > 1 */ void pgd_dtor(void *pgd, kmem_cache_t *cache, unsigned long unused) { unsigned long flags; /* can be called from interrupt context */ spin_lock_irqsave(&pgd_lock, flags); 枷鎖 pgd_list_del(pgd); spin_unlock_irqrestore(&pgd_lock, flags); 釋放 } 中斷枷鎖 #define spin_lock_irqsave(lock, flags)_spin_lock_irqsave(lock, flags) 分析 unsigned long __lockfunc _spin_lock_irqsave(spinlock_t *lock) { unsigned long flags; local_irq_save(flags); 將寄存器存入flags,并關(guān)中斷 preempt_disable(); 搶占鎖 _raw_spin_lock_flags(lock, flags); 枷鎖 return flags; } EXPORT_SYMBOL(_spin_lock_irqsave); /* For spinlocks etc */ #define local_irq_save(x)__asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x): /* no input */ :"memory") 將標(biāo)志寄存器的內(nèi)容放在內(nèi)存x中。請(qǐng)查看gcc匯編 static inline void _raw_spin_lock_flags (spinlock_t *lock, unsigned long flags) { #ifdef CONFIG_DEBUG_SPINLOCK if (unlikely(lock->magic != SPINLOCK_MAGIC)) { printk("eip: %p ", __builtin_return_address(0)); BUG(); } #endif __asm__ __volatile__( spin_lock_string_flags :"=m" (lock->slock) : "r" (flags) : "memory"); } #define spin_lock_string_flags " 1: " "lock ; decb %0 " ;lock總線鎖住,原子操作 "jns 4f " "2: " "testl $0x200, %1 " "jz 3f " "sti " "3: " "rep;nop " "cmpb $0, %0 " "jle 3b " "cli " "jmp 1b " "4: " 理解一下大概意思,就可以了。當(dāng)lock-1后大于等于0就可以關(guān)中斷繼續(xù)執(zhí)行了,否則nop空操作。Nop期間,cpu可以執(zhí)行其他任務(wù)的代碼。 解鎖 #define spin_unlock_irqrestore(lock, flags)_spin_unlock_irqrestore(lock, flags) void __lockfunc _spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags) { _raw_spin_unlock(lock); local_irq_restore(flags); preempt_enable(); } static inline void _raw_spin_unlock(spinlock_t *lock) { #ifdef CONFIG_DEBUG_SPINLOCK BUG_ON(lock->magic != SPINLOCK_MAGIC); BUG_ON(!spin_is_locked(lock)); #endif __asm__ __volatile__( spin_unlock_string ); } Raw赤裸的解鎖,表示最低沉的解鎖原理。 #define spin_unlock_string "xchgb %b0, %1" :"=q" (oldval), "=m" (lock->slock) :"0" (oldval) : "memory" 加1.解鎖 |