更好的解释请看Kernelnewbies
在内核中常会见到下面这样的代码。
bvl = bvec_alloc(gfp_mask, nr_iovecs, &idx);if (unlikely(!bvl)) {
mempool_free(bio, bio_pool);
bio = NULL;
goto out;
}
这个likely()和unlikely()其实是宏定义。原始定义在 include/linux/compiler.h中,如下:
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
__builtin_expect是GCC内建的函数。下面引用linuxform中的一篇讲GCC扩展文章
的一部分(原我找到的也是引用的文章,此处给出链接),里面解释得很清楚。
-------------------------------------------------------
* __builtin_expect(EXP, C)
内建函数 __builtin_expect 用于为编译器提供分支预测信息,其返回值是整数表达式 EXP
的值,C 的值必须是编译时常数。例如:++++ include/linux/compiler.h
13: #define likely(x) __builtin_expect((x),1)
14: #define unlikely(x) __builtin_expect((x),0)
++++ kernel/sched.c
564: if (unlikely(in_interrupt())) {
565: printk("Scheduling in interruptn");
566: BUG();
567: }
这个内建函数的语义是 EXP 的预期值是 C,编译器可以根据这个信息适当地重排
语句块的顺序,使程序在预期的情况下有更高的执行效率。上面的例子表示处于中
断上下文是很少发生的,第 565-566 行的目标码可能会放在较远的位置,以保证
经常执行的目标码更紧凑。
-------------------------------------------------------
总结,这个宏主要是优化的作用。如果英文好的话可以看文章一开始给出的
在kernelnewbies中的链接,那里有更详细的解说。
细心的人应该留意到有一点不同,likely()一开始偶给的定义为__builtin_expect(!!(x),1)。
后来的文章解说中成了__builtin_expect((x),1)。
这应该是后来的版本更改所至。就是新近版本的内核已经更改成__builtin_expect(!!(x),1).
加上个“!!”有什么好处哩。我想是因为使代码强壮与兼容的原因。因为不能保证x表达式的结果一定是1或0,有可能是非0数。加了“!!”,结果就一定是在1和0范围内了。