【转】内核代码摘记

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/p/4477812.html