日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux kernel的spinlock代码导读和分析

發(fā)布時間:2025/3/21 linux 69 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux kernel的spinlock代码导读和分析 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文章目錄

      • 一、代碼閱讀分析
        • 0、spin lock調(diào)用流程圖
        • 1、再kernel中調(diào)用spi_lock()或spin_unlock函數(shù)
        • 2、調(diào)用raw_spin_lock()和raw_spin_unlock()
        • 3、調(diào)用_raw_spin_lock()和_raw_spin_unlock()
        • 4、調(diào)用__raw_spin_lock()和__raw_spin_unlock()
        • 5、調(diào)用do_raw_spin_lock()和do_raw_spin_unlock()
        • 6、調(diào)用arch_spin_lock()和arch_spin_unlock()
        • 7、在arm64中arch_spin_lock()和arch_spin_unlock()的實現(xiàn)
        • 8、在arm32中arch_spin_lock()和arch_spin_unlock()的實現(xiàn)
        • 8、相關(guān)結(jié)構(gòu)體
      • 二、spin lock的排隊原理
      • 九、spin lock的總結(jié)

一、代碼閱讀分析

0、spin lock調(diào)用流程圖

1、再kernel中調(diào)用spi_lock()或spin_unlock函數(shù)

spin_lock(&aacirun->lock) spin_unlock(&aacirun->lock)

2、調(diào)用raw_spin_lock()和raw_spin_unlock()

linux/include/linux/spinlock.hstatic __always_inline void spin_lock(spinlock_t *lock) {raw_spin_lock(&lock->rlock); }static __always_inline void spin_lock_bh(spinlock_t *lock) {raw_spin_lock_bh(&lock->rlock); } static __always_inline void spin_lock_irq(spinlock_t *lock) {raw_spin_lock_irq(&lock->rlock); }#define spin_lock_irqsave(lock, flags) \ do { \raw_spin_lock_irqsave(spinlock_check(lock), flags); \ } static __always_inline void spin_unlock(spinlock_t *lock) {raw_spin_unlock(&lock->rlock); }static __always_inline void spin_unlock_bh(spinlock_t *lock) {raw_spin_unlock_bh(&lock->rlock); }static __always_inline void spin_unlock_irq(spinlock_t *lock) {raw_spin_unlock_irq(&lock->rlock); }static __always_inline void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags) {raw_spin_unlock_irqrestore(&lock->rlock, flags); }

3、調(diào)用_raw_spin_lock()和_raw_spin_unlock()

#define raw_spin_lock(lock) _raw_spin_lock(lock)
#define raw_spin_unlock(lock) _raw_spin_unlock(lock)

4、調(diào)用__raw_spin_lock()和__raw_spin_unlock()

(linux/include/linux/spinlock_api_smp.h)#ifdef CONFIG_INLINE_SPIN_LOCK #define _raw_spin_lock(lock) __raw_spin_lock(lock) #endif(linux/kernel/locking/spinlock.c) #ifndef CONFIG_INLINE_SPIN_LOCK void __lockfunc _raw_spin_lock(raw_spinlock_t *lock) {__raw_spin_lock(lock); } EXPORT_SYMBOL(_raw_spin_lock); #endif

5、調(diào)用do_raw_spin_lock()和do_raw_spin_unlock()

(linux/include/linux/spinlock_api_smp.h) 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); }static inline void __raw_spin_unlock(raw_spinlock_t *lock) {spin_release(&lock->dep_map, 1, _RET_IP_);do_raw_spin_unlock(lock);preempt_enable(); }

在這一層中,我們看到了preempt_disable()和preempt_enable(),禁止搶占和允許搶占.

6、調(diào)用arch_spin_lock()和arch_spin_unlock()

(linux/include/linux/spinlock.h) static inline void do_raw_spin_lock(raw_spinlock_t *lock) __acquires(lock) {__acquire(lock);arch_spin_lock(&lock->raw_lock); }static inline void do_raw_spin_unlock(raw_spinlock_t *lock) __releases(lock) {arch_spin_unlock(&lock->raw_lock);__release(lock); }

7、在arm64中arch_spin_lock()和arch_spin_unlock()的實現(xiàn)

在arch_spin_unlock中為什么沒有sev指令,lock中的wfe在什么地方被喚醒呢?
等待自旋鎖的時候,使用指令ldaxrh(帶有獲取語義的獨占加載,h表示halfword,即2字節(jié))讀取服務(wù)號,獨占加載操作會設(shè)置處理器的獨占監(jiān)視器,記錄鎖的物理地址。
釋放鎖的時候,使用stlrh指令修改鎖的值,stlrh指令會清除所有監(jiān)視鎖的物理地址的處理器的獨占監(jiān)視器,清除獨占監(jiān)視器的時候會生成一個喚醒事件。

(linux/arch/arm64/asm/spinlock.h) static inline void arch_spin_lock(arch_spinlock_t *lock) {unsigned int tmp;arch_spinlock_t lockval, newval;asm volatile(/* Atomically increment the next ticket. */ARM64_LSE_ATOMIC_INSN(/* LL/SC */ " prfm pstl1strm, %3\n" "1: ldaxr %w0, %3\n" " add %w1, %w0, %w5\n" " stxr %w2, %w1, %3\n" " cbnz %w2, 1b\n",/* LSE atomics */ " mov %w2, %w5\n" " ldadda %w2, %w0, %3\n" " nop\n" " nop\n" " nop\n")/* Did we get the lock? */ " eor %w1, %w0, %w0, ror #16\n" " cbz %w1, 3f\n"/** No: spin on the owner. Send a local event to avoid missing an* unlock before the exclusive load.*/ " sevl\n" "2: wfe\n" " ldaxrh %w2, %4\n" " eor %w1, %w2, %w0, lsr #16\n" " cbnz %w1, 2b\n"/* We got the lock. Critical section starts here. */ "3:": "=&r" (lockval), "=&r" (newval), "=&r" (tmp), "+Q" (*lock): "Q" (lock->owner), "I" (1 << TICKET_SHIFT): "memory"); }static inline void arch_spin_unlock(arch_spinlock_t *lock) {unsigned long tmp;asm volatile(ARM64_LSE_ATOMIC_INSN(/* LL/SC */" ldrh %w1, %0\n"" add %w1, %w1, #1\n"" stlrh %w1, %0",/* LSE atomics */" mov %w1, #1\n"" nop\n"" staddlh %w1, %0"): "=Q" (lock->owner), "=&r" (tmp):: "memory"); }

8、在arm32中arch_spin_lock()和arch_spin_unlock()的實現(xiàn)

(linux/arch/arm/asm/spinlock.h) 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 = ACCESS_ONCE(lock->tickets.owner);}smp_mb(); } static inline void arch_spin_unlock(arch_spinlock_t *lock) {smp_mb();lock->tickets.owner++;dsb_sev(); }

8、相關(guān)結(jié)構(gòu)體

(1)、spinlock_t
spinlock_t 結(jié)構(gòu)體中,只有一個struct raw_spinlock rlock元素

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;

(2)、raw_spinlock
在raw_spinlock中,有arch_spinlock_t raw_lock

typedef struct raw_spinlock {arch_spinlock_t raw_lock; #ifdef CONFIG_GENERIC_LOCKBREAKunsigned int break_lock; #endif #ifdef CONFIG_DEBUG_SPINLOCKunsigned int magic, owner_cpu;void *owner; #endif #ifdef CONFIG_DEBUG_LOCK_ALLOCstruct lockdep_map dep_map; #endif } raw_spinlock_t;

(3)、arch_spinlock_t

typedef struct { #ifdef __AARCH64EB__u16 next;u16 owner; #elseu16 owner;u16 next; #endif } __aligned(4) arch_spinlock_t;

二、spin lock的排隊原理

我們將arch_spinlock_t單獨拎出來、將處理ower和next的地方也單獨拎出來,翻譯成C語言是這一個樣子的。
這種做法的目的,主要是引入排隊機制,誰先申請,誰先獲得

struct spinlock {unsigned short owner;unsigned short next; };void spin_lock(struct spinlock *lock) {unsigned short next = xadd(&lock->next, 1);while (lock->owner != next); }void spin_unlock(struct spinlock *lock) {lock->owner++; }

我們舉個例子:

init cpu0-acquire cpu4-acquire cpu6-acquire cpu1-acquire owner 1 1 1 1 1 next 0 1 2 3 4
  • 在spin_lock_init時,owenr=1, next=0;
  • 當(dāng)cpu0 acquire鎖時,next++后,next=1,在spin_lock中while循環(huán)成立,程序繼續(xù)往下跑;
  • 此時,cpu4也試圖拿鎖,next++后,next=2,程序卡在while循環(huán)中;
  • 此時,cpu6也試圖拿鎖,next++后,next=3,程序卡在while循環(huán)中;
  • 此時,cpu1也試圖拿鎖,next++后,next=4,程序卡在while循環(huán)中;
  • 等到cpu0釋放該鎖了,owner++,owner=2,此時cpu4中的while循環(huán)退出,程序繼續(xù)往下跑;

注意:在spin_lock_init時,初始化owenr=1, next=0

void __raw_spin_lock_init(raw_spinlock_t *lock, const char *name,struct lock_class_key *key) { #ifdef CONFIG_DEBUG_LOCK_ALLOC/** Make sure we are not reinitializing a held lock:*/debug_check_no_locks_freed((void *)lock, sizeof(*lock));lockdep_init_map(&lock->dep_map, name, key, 0); #endiflock->raw_lock = (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED;lock->magic = SPINLOCK_MAGIC;lock->owner = SPINLOCK_OWNER_INIT;lock->owner_cpu = -1; }#define __ARCH_SPIN_LOCK_UNLOCKED { 1 }

九、spin lock的總結(jié)

spi lock都干了那些事:
在spin_lock()時:

  • 禁止搶占;
  • 引入onwer/next排隊機制循環(huán)執(zhí)行while(1)排隊;
  • 為了降低功耗引入wfe/sev指令,未獲取該鎖的cpu進程就是低功耗狀態(tài),等到有人釋放該鎖了再去執(zhí)行while(1)排隊

總結(jié)

以上是生活随笔為你收集整理的linux kernel的spinlock代码导读和分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。