【转】内核代码摘记
atomic_inc_not_zero(),atomic_add_unless(), atomic_cmpxchg()
atomic_表示原子操作,不被任何其他操作打擾,一次完成。
------------------------------------------------------------------------------------------------------------
#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
?//atomic_add_unless(v,a,u)表示如果v的值不等于u就加a,返回1。如果v的值等于u就返回0。
//也就是說,v的值要滿足不等于u的條件才加a,否則v的值不變。返回值呢就是加了就返回1,沒加就返回0。
static inline int atomic_add_unless(atomic_t *v, int a, int u)
{
?int c, old;
?c = atomic_read(v);
?for (;;) {
??if (unlikely(c == (u)))
???break;
??old = atomic_cmpxchg((v), c, c + (a)); //如果v的值等于c就加a,old=c。如果v的值不等于c,old=v的值;
??if (likely(old == c))
???break;
??c = old;
?}
?return c != (u);
}
//?__raw_cmpxchg(ptr, old, new)表示,如果*ptr等于old, *ptr=new, 返回old;如果*ptr不等于old,*ptr不變,返回*ptr。
//也就是說,ptr的值要滿足等于old的條件才改變,不滿足條件不改變。返回值始終是原來*ptr的值。
#define __raw_cmpxchg(ptr, old, new, size, lock)???\
({?????????\
?__typeof__(*(ptr)) __ret;?????\
?__typeof__(*(ptr)) __old = (old);????\
?__typeof__(*(ptr)) __new = (new);????\
?switch (size) {???????\
??case 4:????????\
??asm volatile(lock "cmpxchgl %1,%2"???\
??????? : "=a"(__ret)????\
??????? : "r"(__new), "m"(*__xg(ptr)), "0"(__old)?\
??????? : "memory");????\
??break;???????\
??}????????\
?__ret;????????\
})
//cmpxchgl? %src,%dest
//Compares the accumulator (8-32 bits) with "dest". If equal the"dest" is loaded with "src", otherwise the accumulator is loaded with "dest".
------------------------------------------------------------------------------------------------------------
smp_processor_id()
涉及到per_cpu變量定義和訪問
------------------------------------------------------------------------------------------------------------
DECLARE_PER_CPU(int, cpu_number);
# define smp_processor_id() raw_smp_processor_id()
#define raw_smp_processor_id() (percpu_read(cpu_number))
#define percpu_read(var)?percpu_from_op("mov", per_cpu__##var,?\
??????????? "m" (per_cpu__##var))
#define percpu_from_op(op, var, constraint)??\
({???????\
?typeof(var) pfo_ret__;????\
?switch (sizeof(var)) {????\
?case 4:??????\
??asm(op "l "__percpu_arg(1)",%0"??\
????? : "=r" (pfo_ret__)???\
????? : constraint);???\
??break;?????\
??}??????\
?pfo_ret__;?????\
})
其中
?#define __stringify_1(x...)?#x?
?#define __stringify(x...)?__stringify_1(x)
?#define __percpu_seg??fs
?#define __percpu_arg(x)??"%%"__stringify(__percpu_seg)":%P" #x
?//printf("__percpu_arg(x)=%s\n",__percpu_arg(1)); //輸出?("__percpu_arg(x)=%%fs:%P1
?//printf("__stringify(__percpu_seg)=%s\n",__stringify(__percpu_seg));?//輸出?__stringify(__percpu_seg)=fs
// 最后smp_processor_id()匯編部分展開為
??asm("movl %%fs:%P1,%0"??//fs: cpu_number表示fs段中cpu_number偏移處
????? : "=r" (pfo_ret__)??//pfo_ret__是輸出部%0,q,表示寄存器eax、ebx、ecx或edx中的一個
????? : "m"(per_cpu__cpu_number));
//“加載全局/中斷描述符表”中把__KERNEL_PERCPU段選擇子賦給了fs了嗎,fs: cpu_number就獲得了當前存放在__KERNEL_PERCPU段中cpu_number偏移的內存中
------------------------------------------------------------------------------------------------------------
這里主要是宏的運用
?#define __stringify_1(x...)?#x?
?#define __stringify(x...)?__stringify_1(x)??//如果這里直接定義#define __stringify(x...)?#x不行,__percpu_seg沒法替換成fs
?#define __percpu_seg??fs
注意__percpu_seg在?__stringify(x...)?里被解析成__stringify_1(fs),再被解析成"fs"。
參考??激活第一個CPU
asmlinkage_protect(n, ret, args...)
防止編譯器在調用函數前后改變caller()的寄存器值
------------------------------------------------------------------------------------------------------------
#define asmlinkage_protect(n, ret, args...) \
?? ?__asmlinkage_protect##n(ret, ##args)
#define __asmlinkage_protect_n(ret, args...) \
?? ?__asm__ __volatile__ ("" : "=r" (ret) : "0" (ret), ##args)
#define __asmlinkage_protect3(ret, arg1, arg2, arg3) \
?? ?__asmlinkage_protect_n(ret, "g" (arg1), "g" (arg2), "g" (arg3))
------------------------------------------------------------------------------------------------------------
例子:
------------------------------------------------------------------------------------------------------------
externintcallee(inta,intb);staticintc;
intcall(inta,intb){? ? ? ?intret=callee(c, b);? ? ? ? __asm__("":"=r"(ret):"0"(ret),"g"(a),"g"(b)); //這句沒有任何實質操作,卻影響編譯器行為,強迫把ret,a,b放入棧中。
? ? ? ?returnret;
}
//gcc -fomit-frame-pointer -fno-inline -O2 -S tail_call.c
//看它對應的匯編代碼
------------------------------------------------------------------------------------------------------------
例子:系統調用sys_open()
------------------------------------------------------------------------------------------------------------
SYSCALL_DEFINE4(openat, int, dfd, const char __user *, filename, int, flags, int, mode)
{
?? ?long ret;
?? ?if (force_o_largefile())
?? ??? ?flags |= O_LARGEFILE;
?? ?ret = do_sys_open(dfd, filename, flags, mode);
?? ?/* avoid REGPARM breakage on x86: */
?? ?asmlinkage_protect(4, ret, dfd, filename, flags, mode);
?? ?return ret;
}
//其中asmlinkage_protect展開為__asm__ __volatile__ ("" : "=r" (ret) : "0" (ret), "g" (filename), "g" (flags), "g" (mode));
------------------------------------------------------------------------------------------------------------
參考尾部調用優化
宏#和##的區別
一般,宏中用#組合字符串,用##組合變量名。
例子:
------------------------------------------------------------------------------------------------------------
#include <stdio.h>
#define str(n) "str"#n
#define dat(n) dat##n
#define max(x,y) (x)>(y)?(x):(y)
void main()
{
?int a = 1;
?int b = 2;
?int dat(1) = 3;
?int c = max(a,b);?
?printf("str(n)=%s,dat(n)=%d",str(8),dat(1)); //輸出 str(n)=str8,dat(n)=3
?}
------------------------------------------------------------------------------------------------------------
container_of(ptr, type, member)
ptr是結構類型type的成員名member,container_of(ptr, type, member) 得到地址ptr所在結構體的地址。
------------------------------------------------------------------------------------------------------------
#define container_of(ptr, type, member) ({???\
?const typeof( ((type *)0)->member ) *__mptr = (ptr);?\?
?(type *)( (char *)__mptr - offsetof(type,member) );})
------------------------------------------------------------------------------------------------------------
定義一個指針變量__mptr,它的類型是typeof( ((type *)0)->member ) *。
typeof( ((type *)0)->member ),通過結構類型一個成員名稱可以得到該成員的數據類型。
offsetof(type,member) ,結構類型和一個成員名稱的offsetof,得到該成員離結構頭的距離。?
smp_mb(),mb(),barrier()
#define barrier() __asm__ __volatile__("": : :"memory")
內存屏障,memory強制gcc編譯器假設RAM所有內存單元均被匯編指令修改,這樣cpu中的registers和cache中已緩存的內存單元中的數據將作廢。cpu將不得不在需要的時候重新讀取內存中的數據。這就阻止了cpu又將registers,cache中的數據用于去優化指令。
參考 內存屏障(memory barrier)
hi~,北風北的豬最后編輯于2011.03.08
轉載于:https://www.cnblogs.com/mull/archive/2013/06/03/4477812.html
總結
- 上一篇: getting joins
- 下一篇: Linux学习参考书