#define unlikely(x) __builtin_expect(!!(x), 0)
#define likely(x) __builtin_expect(!!(x), 1)
上面是两个见到的最多的宏,后面的__builtin_expect是一个编译器内置函数,所谓编译器内置函数实际就是编译器加进去的一些代码片段或者一个标志提醒编译器进行优化,这里就是一个优化提醒,主要用途是当出现前者时代码很大可能是顺序执行,而后者则可能发生跳转。这样的话编译器可以通过一些代码插入手段达到优化处理器的指令预取的效果。至于这两个的宏的结果就是内部的x的值,所以可以直接当做对x的判断。而后面的 __builtin_expect(!!(x),0)会根据!!(x)和0是否相等进行判断,!!(x)形式是防止出现不相等的情况,假设x=2,经过一次求反之后变为全0,再一次求反则等于1。
# define __BUG_C0 "2:\t.long 1b, %c0\n"
#define BUG() \
do { \
asm volatile("1:\tud2\n" \
".pushsection __bug_table,\"a\"\n" \
__BUG_C0 \
"\t.word %c1, 0\n" \
"\t.org 2b+%c2\n" \
".popsection" \
: : "i" (__FILE__), "i" (__LINE__), \
"i" (sizeof(struct bug_entry))); \
unreachable(); \
} while (0)
上面指令在执行过程中会让系统死掉,当然由于整个分成两个部分,第一部分是ud2指令,这条指令发出未定义的异常,如果没有被处理则直接引起系统关闭。下面还有一段是有关调试信息的,处理过程和上次的参数检验一样。
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
上面这个宏用于从结构体中的成员变量找到结构体的首地址,利用到C语言的一个特性——成员变量是以相对位置计算的,不过现在变高级了,最终跟随下去是一个编译器实现的函数,不过功能一样。解释起来都是通过type类型结构体中的成员变量member指针ptr返回type型结构体指针。
#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
这个宏主要是为了防止处理器对x的预取、或者指令的重排序,这一点是由volatile关键字实现的。
#define typecheck(type,x) \
({ type __dummy; \
typeof(x) __dummy2; \
(void)(&__dummy == &__dummy2); \
1; \
})
#define typecheck_fn(type,function) \
({ typeof(type) __tmp = function; \
(void)__tmp; \
})
这两个宏一个用于检测类型是否相同,另一个检测一个是否是相应的函数。第一个宏的关键在这里(void)(&__dummy == &__dummy2),当__dummy和__dummy2不是同一个类型时,编译器会报错(mingw亲测),至于最后返回1也是为了防止在使用时误用做if判断。第二个宏的关键typeof(type) __tmp = function,如果function的类型不是type,则编译时会报错。最后返回__tmp则可以用于检测函数地址是否有效。
#define local_irq_enable() do { raw_local_irq_enable(); } while (0)
#define local_irq_disable() do { raw_local_irq_disable(); } while (0)
这两条指令,一条用于使能中断,一条用于禁止中断。跟踪下去实现就是调用处理器特定的标志处理指令进行清中断和开中断处理。之所以要有两层也是因为具体架构下的实现因为具体的指令差异不同而不同。
local_irq_save和local_irq_restore则首先将当前的处理器状态保存下来,然后执行关闭中断的操作。
#define mb() asm volatile ("": : :"memory")
#define rmb() mb()
#define wmb() asm volatile ("": : :"memory")
#define smp_mb() mb()
#define smp_rmb() rmb()
#define smp_wmb() wmb()
上面几句实际只是阻止其他的编译器进行优化,而按照原有的代码顺序生成机器码。
#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
关键点在于后面的int:-!!(e)。首先冒号表示设置结构体的位域,如果位域为0-31,编译是不会有问题的。而e在两次取反之后只有两个值0和1,当值等于0时再取反取负数还是等于0,而当值等于1时取负数等于-1超过了位域所能表达的范围则会报错。
#define RELOC_HIDE(ptr, off) \
({ unsigned long __ptr; \
__asm__ ("" : "=r"(__ptr) : "0"(ptr)); \
(typeof(ptr)) (__ptr + (off)); })
利用嵌入汇编将输入寄存器和输出寄存器指向同一个寄存器,然后根据输出加上偏移得到重定位之后的结果。