*本篇來看看多次在內核中出現的spin_lock——自旋鎖,到底是個什麼東西。。。→_→*
內核中的spin_lock()
- spin_lock()源代碼
static inline void spin_lock(spinlock_t *lock)//自旋鎖的類型定義見下方 { #if SPINLOCK_DEBUG __label__ here; here: if (lock->magic != SPINLOCK_MAGIC) { printk("eip: %p\n", &&here); BUG(); } #endif __asm__ __volatile__( spin_lock_string//進入宏函數spin_lock_string,傳參數lock->lock :"=m" (lock->lock) : : "memory"); }
- 自旋鎖的類型定義
typedef struct { volatile unsigned int lock;//不考慮調試時,自旋鎖就是一個無符號整形,volatile保證編譯器不進行過度優化 #if SPINLOCK_DEBUG unsigned magic; #endif } spinlock_t;
- spin_lock_string宏函數
#define spin_lock_string \ "\n1:\t" \ "lock ; decb %0\n\t" \ //decb指令涉及讀-改-寫操作,所以lock總線保證該條指令的原子性,%0就是傳入的參數lock->lock,decb指令將lock->lock減1,結果非負表示加鎖成功,直接返回 "js 2f\n" \ ".section .text.lock,\"ax\"\n" \ "2:\t" \ //結果爲負,循環測試lock->lock的值 "cmpb $0,%0\n\t" \ //將lock->lock的值與0比較 "rep;nop\n\t" \ "jle 2b\n\t" \ //當lock->lock小於等於0時,繼續循環測試 "jmp 1b\n" \ //當lock->lock大於0時,跳轉到標號1,獲取自旋鎖 ".previous"
從代碼中得知,如果lock->lock小於等於0,那麼就一直循環測試其值,直到lock->lock大於0。這就相當於讓CPU一直空轉,做無用功,因此自旋鎖應用的地方不能加鎖時間太長,否則就會浪費資源。
內核中的spin_unlock()
- spin_unlock()源代碼
static inline void spin_unlock(spinlock_t *lock) { #if SPINLOCK_DEBUG if (lock->magic != SPINLOCK_MAGIC) BUG(); if (!spin_is_locked(lock)) BUG(); #endif __asm__ __volatile__( spin_unlock_string//調用spin_unlock_string宏函數,傳參數lock->lock :"=m" (lock->lock) : : "memory"); }
- spin_unlock_string宏函數
#define spin_unlock_string \ "movb $1,%0" //%0就是傳入的參數lock->lock,movb指令將lock->lock置爲1,movb指令本身就是原子操作,所以不需要lock總線
內核中的自旋鎖具體應用的類型
- 加鎖操作
#define spin_lock_irqsave(lock, flags) do { local_irq_save(flags); spin_lock(lock); } while (0) #define spin_lock_irq(lock) do { local_irq_disable(); spin_lock(lock); } while (0) #define spin_lock_bh(lock) do { local_bh_disable(); spin_lock(lock); } while (0)
- 去鎖操作
#define spin_unlock_irqrestore(lock, flags) do { spin_unlock(lock); local_irq_restore(flags); } while (0) #define spin_unlock_irq(lock) do { spin_unlock(lock); local_irq_enable(); } while (0) #define spin_unlock_bh(lock) do { spin_unlock(lock); local_bh_enable(); } while (0)
- 不同操作之間的異同
同:加鎖和去鎖操作中都是分爲兩部分,即先執行local_操作——關閉或開啓本處理器上的中斷響應,再執行_lock操作——防止來自其他處理器的干擾。
異:主要區別就在於如何關閉本處理器上的中斷響應
/* For spinlocks etc */ #define local_irq_save(x) __asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x): /* no input */ :"memory") //通過cli指令關閉中斷,且將本處理器的狀態標識寄存器通過push和pop操作,保存到參數x中,以便去鎖時恢復。狀態標誌寄存器中的IF標誌位反映當前中斷的開關狀態 #define local_irq_restore(x) __restore_flags(x) //去鎖時恢復標識寄存器 #define local_irq_disable() __cli() //直接將標識寄存器的IF標誌位清0 #define local_irq_enable() __sti()
*碼完喫飯。。。下午繼續最後的read_lock和write_lock。。。→_→*