Linux核心中的cmpxchg函式

2021-07-04 21:06:35 字數 1739 閱讀 6788

前幾天,為了這個函式花了好多時間,由於參考的資料有誤,一直都沒有看明白,直到google之後,總算搞明白了,因此寫出來大家分享一下。

在linux核心中,提供了比較並交換的函式cmpxchg,**在include/asm-i386/cmpxchg.h中,函式的原型是:

**: 

全選cmpxchg(void *ptr, unsigned long old, unsigned long new);

函式完成的功能是:將old和ptr指向的內容比較,如果相等,則將new寫入到ptr中,返回old,如果不相等,則返回ptr指向的內容。

在linux中的實現是這樣的。

**: 

全選#define cmpxchg(ptr,o,n)\

((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\

(unsigned long)(n),sizeof(*(ptr))))

很明顯,這個函式就是呼叫了__cmpxchg。

**: 

全選static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,

unsigned long new, int size)

return old;

}

以最為常用的4位元組交換為例,主要的操作就是彙編指令cmpxchgl %1,%2,注意一下其中的%2,也就是後面的"m"(*__xg(ptr))。

__xg是在這個檔案中定義的巨集:

struct __xchg_dummy ;

#define __xg(x) ((struct __xchg_dummy *)(x))

那麼%2經過預處理,展開就是"m"(*((struct __xchg_dummy *)(ptr))),這種做法,就可以達到在cmpxchg中的%2是乙個位址,就是ptr指向的位址。如果%2是"m"(ptr),那麼指標本身的值就出現在cmpxchg指令中。

我手頭有乙份《奔騰指令速查》,其中對cmpxchg的說明是這樣的:

**: 

全選cmpxchg r/m32,r32 0f b1 /r cmpxchg ebx,ecx ;如果eax與ebx相等,則ecx送ebx且zf置1;否則ebx送ecx,且zf清0

**: 

全選cmpxchg %ecx, %ebx;如果eax與ebx相等,則ecx送ebx且zf置1;否則ebx送ecx,且zf清0

在上述例子中,eax就是old,ebx就是ptr指向的內容,ecx就是new。所以cmpxchg指令的操作就是:如果old等於ptr指向的內容,那麼就把new寫入到ptr中,返回old(%eax沒有改變過,一直是old),這部分和cmpxchg函式的原意是符合的;

如果old不等於ptr指向的內容,那麼ptr的內容寫入new(%ecx)中,返回old(%eax沒有改變過,一直是old),這明顯不符合cmpxchg函式的意思。對此是大惑不解,後來經過google才知道,那份資料有錯。正解是:

**: 

全選cmpxchg %ecx, %ebx;如果eax與ebx相等,則ecx送ebx且zf置1;否則ebx送eax,且zf清0

也就是說,

在old和ptr指向的內容不相等的時候,將ptr的內容寫入eax中,這樣,ptr的內容就會返回給cmpxchg函式的呼叫者。這樣就和原意相符合了。

Linux核心中的list for each

在linux核心原始碼中,經常要對鍊錶進行操作,其中乙個很重要的巨集是list for each entry 意思大體如下 假設只有兩個結點,則第乙個member代表head,list for each entry的作用就是迴圈遍歷每乙個pos中的member子項。巨集list for each e...

Linux核心中的Namespace

linux核心中的namespace提供了乙個輕量級的基於系統呼叫層面的虛擬化解決方案。相比傳統的使用 vmware,qemu,xen,kvm,hurd的虛擬 圖1所示 基於namespace的輕量級虛擬具有易使用,易管理,無需硬體虛擬化支援,低 成本等優點。圖 1.namespace又稱conta...

linux核心中的 config

經過make menuconfig 生成 config 決定哪些驅動編譯到核心,哪些驅動編譯為模組 那為什麼呢?舉個例子分析一下 eg 在.config 中有 config dm9000 y grep config dm9000 r 1.c檔案中 arch arm mach s5pv210 mach...