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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

liunx内核中的互斥自旋锁和读写自旋锁的实现详解

發(fā)布時(shí)間:2024/4/18 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 liunx内核中的互斥自旋锁和读写自旋锁的实现详解 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

今天把這兩個(gè)鎖的內(nèi)核實(shí)現(xiàn)源碼重新捋了一遍,基于liunx2,6.0,直接粘注釋版:
核心文件,x86下實(shí)現(xiàn)的spinlock

#ifndef __ASM_SPINLOCK_H #define __ASM_SPINLOCK_H#include <asm/atomic.h> #include <asm/rwlock.h> #include <asm/page.h> #include <linux/config.h>extern int printk(const char * fmt, ...)__attribute__ ((format (printf, 1, 2)));/** Your basic SMP spinlocks, allowing only a single CPU anywhere*/typedef struct {//自旋鎖為無(wú)符號(hào)的整型變量 volatile保證變量都從內(nèi)存中獲取,不要緩存在寄存器里volatile unsigned int lock; #ifdef CONFIG_DEBUG_SPINLOCKunsigned magic; #endif } spinlock_t; //定義一個(gè)spinlock的魔數(shù),用來(lái)調(diào)試用 #define SPINLOCK_MAGIC 0xdead4ead#ifdef CONFIG_DEBUG_SPINLOCK #define SPINLOCK_MAGIC_INIT , SPINLOCK_MAGIC #else #define SPINLOCK_MAGIC_INIT /*如果沒(méi)有開(kāi)啟調(diào)試狀態(tài)將什么也沒(méi)有 */ #endif //創(chuàng)建一個(gè)值為1的自旋鎖 #define SPIN_LOCK_UNLOCKED (spinlock_t) { 1 SPINLOCK_MAGIC_INIT } //初始化自旋鎖 x是一根指針 所以解引用 #define spin_lock_init(x) do { *(x) = SPIN_LOCK_UNLOCKED; } while(0)/** Simple spin lock operations. There are two variants, one clears IRQ's* on the local processor, one does not.* 簡(jiǎn)單的自旋鎖操作。有兩種變體,一種清除本地處理器上的IRQ,另一種不清除。** We make no fairness assumptions. They have a cost.* 我們沒(méi)有做出公平的假設(shè)(非公平)。它們是有代價(jià)的*/ //判斷自旋鎖是否被鎖定 先通過(guò)取地址拿到spinlock里的lock 再轉(zhuǎn)為字符,再解引用判斷是否小于0 #define spin_is_locked(x) (*(volatile signed char *)(&(x)->lock) <= 0) //等待自旋鎖釋放,barrier()保證禁止編譯器任意排序 #define spin_unlock_wait(x) do { barrier(); } while(spin_is_locked(x)) //獲取自旋鎖內(nèi)聯(lián)匯編代碼,這里只是code部分,剩下在用的時(shí)候肯定是有輸出數(shù)和輸入數(shù)的 #define spin_lock_string \"1:" \ //1位置"lock ; decb %0" \ //對(duì)lock變量的值進(jìn)行自減,如果lock變量是0或者小于0,再減豈不是直接就小于0了嗎,所以底下js判斷是否符號(hào)位為1,也就是小于0"js 2f" \ //f是forward,往后跳,因?yàn)?:確實(shí)在后面,如果小于0,跳轉(zhuǎn)到前面的2處 js判斷的是符號(hào)位是否為1,為1當(dāng)然就小于0啦LOCK_SECTION_START("") \ //涉及到ELF的知識(shí)"2:" \"rep;nop" \ //repeat空操作"cmpb $0,%0" \ //比較lock的值是否為0,%0可以從后面的代碼看出,是輸出參數(shù),是lock變量 cmpb的b代表比一個(gè)字節(jié),l代表4字節(jié)"jle 2b" \ //b是backward,往前跳,jle代表小于或等于0,繼續(xù)2處"jmp 1b" \//jmp:無(wú)條件轉(zhuǎn)移到指定內(nèi)存地址,否則跳回到1處去進(jìn)行減一操作,這也不一定還能拿到哦,還得判斷,如果成功就拿到了鎖!!!!!LOCK_SECTION_END //".previous\n\t"/** This works. Despite all the confusion.* 這很有效。盡管如此混亂。* (except on PPro SMP or if we are using OOSTORE)* (PPro errata 66, 92)*/#if !defined(CONFIG_X86_OOSTORE) && !defined(CONFIG_X86_PPRO_FENCE)#define spin_unlock_string \ //這里和lock_string是不一樣的,直接就把輸入輸出和clobber都填好了"movb $1,%0" \ //把1設(shè)置為lock的值:"=m" (lock->lock) : : "memory" //static spinlock_t lock;這里的lock是一個(gè)spinlock_t,所以指針再指向spinlock里的lockstatic inline void _raw_spin_unlock(spinlock_t *lock) { #ifdef CONFIG_DEBUG_SPINLOCKif (lock->magic != SPINLOCK_MAGIC)BUG();if (!spin_is_locked(lock))BUG(); #endif__asm__ __volatile__(spin_unlock_string); }#else#define spin_unlock_string \"xchgb %b0, %1" \:"=q" (oldval), "=m" (lock->lock) \:"0" (oldval) : "memory"static inline void _raw_spin_unlock(spinlock_t *lock) {char oldval = 1; #ifdef CONFIG_DEBUG_SPINLOCKif (lock->magic != SPINLOCK_MAGIC)BUG();if (!spin_is_locked(lock))BUG(); #endif__asm__ __volatile__(spin_unlock_string); }#endifstatic inline int _raw_spin_trylock(spinlock_t *lock) {char oldval;__asm__ __volatile__("xchgb %b0,%1" //交換lock的值(%1)和oldval:"=q" (oldval), "=m" (lock->lock) //q:將輸入變量放入eax,ebx,ecx,edx中的一個(gè) :"0" (0) : "memory"); //0:表示用它限制的操作數(shù)與某個(gè)指定的操作數(shù)(這里就是0)匹配return oldval > 0; //大于0說(shuō)明lock變量為1,那說(shuō)明就沒(méi)有人拿到這個(gè)鎖,那么久嘗試獲得到了鎖 }static inline void _raw_spin_lock(spinlock_t *lock) { #ifdef CONFIG_DEBUG_SPINLOCK__label__ here; here:if (lock->magic != SPINLOCK_MAGIC) { printk("eip: %p\n", &&here);BUG();} #endif__asm__ __volatile__(spin_lock_string:"=m" (lock->lock)//輸出操作數(shù)列表為lock : : "memory"); }/** Read-write spinlocks, allowing multiple readers* but only one writer.** NOTE! it is quite common to have readers in interrupts* but no interrupt writers. For those circumstances we* can "mix" irq-safe locks - any writer needs to get a* irq-safe write-lock, but readers can get non-irqsafe* read-locks.*/ typedef struct {volatile unsigned int lock; #ifdef CONFIG_DEBUG_SPINLOCKunsigned magic; #endif } rwlock_t;//多個(gè)讀者共享,寫(xiě)者互斥,和互斥自旋鎖機(jī)構(gòu)一模一樣#define RWLOCK_MAGIC 0xdeaf1eed#ifdef CONFIG_DEBUG_SPINLOCK #define RWLOCK_MAGIC_INIT , RWLOCK_MAGIC #else #define RWLOCK_MAGIC_INIT /* */ #endif#define RW_LOCK_UNLOCKED (rwlock_t) { RW_LOCK_BIAS RWLOCK_MAGIC_INIT }//RW_LOCK_BIAS->0x0100 0000第七位//初始化讀寫(xiě)自旋鎖 #define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while(0)#define rwlock_is_locked(x) ((x)->lock != RW_LOCK_BIAS)//RW_LOCK_BIAS代表沒(méi)上鎖(既沒(méi)有讀鎖也沒(méi)有寫(xiě)鎖)/** On x86, we implement read-write locks as a 32-bit counter* with the high bit (sign) being the "contended" bit.* 在x86上,我們將讀寫(xiě)鎖實(shí)現(xiàn)為32位計(jì)數(shù)器,高位(符號(hào))為“爭(zhēng)用”位。** The inline assembly is non-obvious. Think about it.** Changed to use the same technique as rw semaphores. See* semaphore.h for details. -ben*/ #endif /* the spinlock helpers are in arch/i386/kernel/semaphore.c */ //helper__write_lock_failed和的實(shí)現(xiàn)去這個(gè)地方(arch/i386/kernel/semaphore.c)找,否則找不到 //獲取讀鎖或者寫(xiě)鎖失敗后的helper實(shí)現(xiàn) static inline void _raw_read_lock(rwlock_t *rw) { #ifdef CONFIG_DEBUG_SPINLOCKif (rw->magic != RWLOCK_MAGIC)BUG(); #endif__build_read_lock(rw, "__read_lock_failed");//在讀寫(xiě)鎖文件rwlock.h里有相應(yīng)實(shí)現(xiàn) }static inline void _raw_write_lock(rwlock_t *rw) { #ifdef CONFIG_DEBUG_SPINLOCKif (rw->magic != RWLOCK_MAGIC)BUG(); #endif__build_write_lock(rw, "__write_lock_failed"); }//讀鎖和寫(xiě)鎖的釋放也很簡(jiǎn)單,原子加1或者原子加0x0100 0000 #define _raw_read_unlock(rw) asm volatile("lock ; incl %0" :"=m" ((rw)->lock) : : "memory") #define _raw_write_unlock(rw) asm volatile("lock ; addl $" RW_LOCK_BIAS_STR ",%0":"=m" ((rw)->lock) : : "memory")static inline int _raw_write_trylock(rwlock_t *lock) {atomic_t *count = (atomic_t *)lock;if (atomic_sub_and_test(RW_LOCK_BIAS, count))return 1;atomic_add(RW_LOCK_BIAS, count);return 0; }#endif /* __ASM_SPINLOCK_H */

rwlock.h核心文件,x86實(shí)現(xiàn):

/* include/asm-x86_64/rwlock.h** Helpers used by both rw spinlocks and rw semaphores.** Based in part on code from semaphore.h and* spinlock.h Copyright 1996 Linus Torvalds.** Copyright 1999 Red Hat, Inc.* Copyright 2001,2002 SuSE labs ** Written by Benjamin LaHaise.** This program is free software; you can redistribute it and/or* modify it under the terms of the GNU General Public License* as published by the Free Software Foundation; either version* 2 of the License, or (at your option) any later version.*/ #ifndef _ASM_X86_64_RWLOCK_H #define _ASM_X86_64_RWLOCK_H#include <linux/stringify.h>#define RW_LOCK_BIAS 0x01000000 #define RW_LOCK_BIAS_STR "0x01000000"#define __build_read_lock_ptr(rw, helper) \asm volatile(LOCK "subl $1,(%0)" \ //獲取讀鎖就是嘗試在lock上減1,因?yàn)镽W_LOCK_BIAS是非常大的一個(gè)數(shù)// 只有有寫(xiě)鎖的時(shí)候會(huì)直接減去0x01000000變?yōu)?,其他時(shí)候是不可能小于0的,所以沒(méi)有寫(xiě)鎖的情況下,去搶占這個(gè)讀鎖是沒(méi)有問(wèn)題的"js 2f" \ //判斷符號(hào)位是否為1,也即是否為負(fù)數(shù),如果是負(fù)數(shù),那么說(shuō)明已經(jīng)有寫(xiě)鎖啦,那你只能去2位置了"1:" \LOCK_SECTION_START("") \"2: call " helper "" \ //調(diào)用helper方法,helper即為_(kāi)_read_lock_failed,下面把這段實(shí)現(xiàn)摘抄出來(lái)了,我沒(méi)有獲取到鎖,只好調(diào)用這個(gè)方法"jmp 1b" \LOCK_SECTION_END \::"a" (rw) : "memory") //a:將輸入變量放入eax//這段代碼是從i386的semaphore下摘出來(lái)的asm("__read_lock_failed:"LOCK "incl (%eax)"//原子性增加eax寄存器中的值(也就是lock變量的值)"1: rep; nop" //進(jìn)行空操作,耗掉一點(diǎn)點(diǎn)時(shí)間"cmpl $1,(%eax)"// cmp影響符號(hào)位,lock變量和1相減如果是負(fù)數(shù),符號(hào)位為1"js 1b" //如果是負(fù)數(shù)那么就去1重新比較,直到可以獲得讀鎖LOCK "decl (%eax)"//說(shuō)明eax也就是lock大于等于1,進(jìn)行相減再次判斷是否為負(fù)數(shù),因?yàn)榭赡軆蓚€(gè)線程同時(shí)走這一步,嚴(yán)謹(jǐn)!!!!!"js __read_lock_failed"//負(fù)數(shù)說(shuō)明又沒(méi)搶到,繼續(xù)循環(huán)吧"ret"//搶到了,返回);#define __build_read_lock_const(rw, helper) \asm volatile(LOCK "subl $1,%0\n\t" \"js 2f\n" \"1:\n" \LOCK_SECTION_START("") \"2:\tpushq %%rax\n\t" \"leaq %0,%%rax\n\t" \"call " helper "\n\t" \"popq %%rax\n\t" \"jmp 1b\n" \LOCK_SECTION_END \:"=m" (*((volatile int *)rw))::"memory")#define __build_read_lock(rw, helper) do { \if (__builtin_constant_p(rw)) \__build_read_lock_const(rw, helper); \else \__build_read_lock_ptr(rw, helper); \//走這里} while (0)#define __build_write_lock_ptr(rw, helper) \asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",(%0)" \ //核心,寫(xiě)鎖只能有一個(gè),上來(lái)直接把那個(gè)大數(shù)減完了"jnz 2f" \ //看是否為0,不為0說(shuō)明絕對(duì)有讀鎖在占著,直接失敗去2處forward"1:" \LOCK_SECTION_START("") \"2: call " helper "" \同讀鎖邏輯,截取helper如下"jmp 1b" \LOCK_SECTION_END \::"a" (rw) : "memory")//這段代碼是從i386的semaphore下摘出來(lái)的asm("__write_lock_failed:"LOCK "addl $" RW_LOCK_BIAS_STR ",(%eax)" //大同小異,先加后減"1: rep; nop\n\t""cmpl $" RW_LOCK_BIAS_STR ",(%eax)""jne 1b"LOCK "subl $" RW_LOCK_BIAS_STR ",(%eax)""jnz __write_lock_failed""ret");#define __build_write_lock_const(rw, helper) \asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",(%0)\n\t" \"jnz 2f\n" \"1:\n" \LOCK_SECTION_START("") \"2:\tpushq %%rax\n\t" \"leaq %0,%%rax\n\t" \"call " helper "\n\t" \"popq %%rax\n\t" \"jmp 1b\n" \LOCK_SECTION_END \:"=m" (*((volatile long *)rw))::"memory")#define __build_write_lock(rw, helper) do { \if (__builtin_constant_p(rw)) \__build_write_lock_const(rw, helper); \else \__build_write_lock_ptr(rw, helper); \ //上讀鎖走這里} while (0)#endif

看注釋可以很容易理解。

總結(jié)

以上是生活随笔為你收集整理的liunx内核中的互斥自旋锁和读写自旋锁的实现详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

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