• 【转】内核代码摘记


    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

  • 相关阅读:
    BZOJ 2299 向量
    BZOJ 1237 配对
    BZOJ 2226 LCMSum
    BZOJ 1876 SuperGCD
    查漏补缺:C++STL简述(容器部分)
    查漏补缺:Linux进程与线程的区别
    码海拾遗:常用的其中排序算法
    码海拾遗:简述C++(一)
    码海拾遗:简单的链表类
    码海拾遗:位运算实现加减乘除
  • 原文地址:https://www.cnblogs.com/mull/p/4477812.html
Copyright © 2020-2023  润新知