首页 > 代码库 > Kernel散记——常见宏
Kernel散记——常见宏
Kernel散记——常见宏
1,likely()和unlikey()
1.1,来自哪里?@kernel.h
# define likely(x) (__builtin_expect(!!(x), 1))
# define unlikely(x) (__builtin_expect(!!(x), 0))
1.2,作用?
代码优化。详细占说是告诉编译器,优化预取指。
1.3,细节?
细节也说不清,说个大概;
#define likely(x) __builtin_expect(!!(x), 1)也就是说明x==1是“经常发生的”或是“很可能发生的”。
使用likely ,执行if后面语句的可能性大些,编译器将if{}是的内容编译到前面, 使用unlikely ,执行else后面语句的可能性大些,编译器将else{}里的内容编译到前面。这样有利于cpu预取,提高预取指令的正确率,因而可提高效率。
1.4,举个例子
ret = copy_to_user(to, fifo->data + off, l);
if (unlikely(ret))
ret = DIV_ROUND_UP(ret + len - l, esize);
else {
ret = copy_to_user(to + l, fifo->data, len - l);
if (unlikely(ret))
ret = DIV_ROUND_UP(ret + len - l, esize);
else {
ret = copy_to_user(to + l, fifo->data, len - l);
...
}
也就是说ret=0的可能性很大,else的内容被编译到if之前,优化处理器取指
另外,使用!!(x)而不使用x是把x值转化为bool值。这个也是kernel常见的。
2,在Input 子系统中,对bits有几个常用的位操作宏
@include/linux/input.h struct input_dev
unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];
先看定义:
#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
在32位系统中,long占用4个字节。
BITS_TOLONGS就是探测一下共总有多少个32bit。
比较ABS_CNT = 0x3f + 1 = 0x40
(也就是说0x40 = 64 = 32 *2
两个long<32bit>型就可以装下)
所以BITS_TO_LONGS(ABS_CNT) = 2
@input.c
test_bit(ABS_MT_TRACKING_ID, dev->absbit)
test_bit 简单地说就是返回(dev->absbit)这个地址,对应的位(ABS_MT_TRACKING)的值。
@input.c
__set_bit(EV_SYN, dev->evbit);
定义:
/**
* __set_bit - Set a bit in memory
* @nr: the bit to set
* @addr: the address to start counting from
*
* Unlike set_bit(), this function is non-atomic and may be reordered.
* If it‘s called on the same region of memory simultaneously, the effect
* may be that only one operation succeeds.
*/
static inline void __set_bit(int nr, volatile unsigned long *addr)
{
unsigned long mask = BIT_MASK(nr);
unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
*p |= mask;
}
* __set_bit - Set a bit in memory
* @nr: the bit to set
* @addr: the address to start counting from
*
* Unlike set_bit(), this function is non-atomic and may be reordered.
* If it‘s called on the same region of memory simultaneously, the effect
* may be that only one operation succeeds.
*/
static inline void __set_bit(int nr, volatile unsigned long *addr)
{
unsigned long mask = BIT_MASK(nr);
unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
*p |= mask;
}
简单地说,就是把(dev-evbit)这个内存开始的地址的第EV_SYN(0)位
综上:
理解了上述代码,则其它比特位操作API就容易懂了。
__clear_bit: 将addr所指的地址处的值第nr位清0,方法一般 addr[nr/32] & 11111011111
__change_bit: 将addr所指的地址处的值第nr位取反,方法一般 addr[nr/32] ^ 00000100000
__test_and_set_bit:将addr所指的地址处的值第nr位置1,返回该bit原始值(0或1);
__test_and_clear_bit:将addr所指的地址处的值第nr位清0,返回该bit原始值(0或1);
__test_and_change_bit:将addr所指的地址处的值第nr位取反,返回该bit原始值(0或1);
test_bit:即测试nr位是否被置位,置位返回1;
3,还是在Input系统中,关于bitmap的操作。
@input.c input_match_device()函数
if (!bitmap_subset(id->evbit, dev->evbit, EV_MAX))
bitmap_subset src1的nbits指定位数中设置1的比特位是src2中nbits指定位数中设置1的比特的子集,则返回1,否则返回0。精确到位。
关于bitmap,参考
http://blog.chinaunix.net/uid-20608849-id-3027971.html
|
Kernel散记——常见宏
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。