全部分类
移动开发与应用
WEB前端
架构与运维
程序设计
数据库
操作系统
热点技术
综合
内核中常用的bit操作
5620阅读 0评论
2016-04-17
wibnmo
分类:
LINUX
1. set_bit/clear_bit
set_bit(nr,addr)将addr的第nr位置1
clear_bit(nr,addr)
test_and_set_bit(nr,addr)将addr的第nr位置1,并返回原始addr第nr位的值
test_and_clear_bit(nr,addr)
在内核中有好几处实现,不过大同小异,我们看两种:
include/asm-generic/bitops/atomic.h
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);//这里为什么这么做,不太明白
unsigned long flags;
_atomic_spin_lock_irqsave(p, flags);
*p |= mask;
_atomic_spin_unlock_irqrestore(p, flags);
}
include/linux/bitops.h
#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
arch/arm/include/asm/types.h
#define BITS_PER_LONG 32
比如BIT_MASK(3) = (1UL << ((3) % 32)) = 0x8(1000)
另一种实现:
arch/arm/include/asm/bitops.h
static inline int
____atomic_test_and_set_bit(unsigned int bit, volatile unsigned long *p)
{
unsigned long flags;
unsigned int res;
unsigned long mask = 1UL << (bit & 31); //和上面的mask方式不同的是这里用的逻辑与
p += bit >> 5; //不太明白为什么要这么做
raw_local_irq_save(flags);
res = *p;
*p = res | mask;
raw_local_irq_restore(flags);
return (res & mask) != 0;
}
还有一种是用汇编实现的,不贴了。
关键要注意的是这种用法,比如取mask的方法:
mask = 1UL << (bit & 31)
mask = (1UL << ((nr) % BITS_PER_LONG))
从这里我们可以看出,整除和逻辑与的作用是一样的。
-------------------------------------------------------------------------------
2. BITS_TO_LONGS
它的作用就是看一个数含有几个long的长度
include/linux/bitops.h
#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
#define BITS_PER_BYTE 8
include/linux/kernel.h
#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
比方BITS_TO_LONGS(33) DIV_ROUND_UP(33, 8 * 4)
DIV_ROUND_UP(33, 8 * 4) (((33) + (32) - 1) / (32)) 即 2
也就是33含有2个long的长度
上一篇:
如何在嵌入式设备上跑自己的程序
下一篇:
抬头纹和颜色饱和度不够解析手法