void set_bit(int nr, volatile unsigned long *addr) void clear_bit(int nr, volatile unsigned long *addr) void change_bit(int nr, volatile unsigned long *addr) int test_and_set_bit(int nr, volatile unsigned long *addr) int test_and_clear_bit(int nr, volatile unsigned long *addr)
上面的这些方法都是原子操作的。
void set_bit(int nr, volatile unsigned long *addr)
将存放在addr内存地址的unsigned long类型的数据的nr位设成1。这儿改变的是addr地址的数据的相应位,而这个数据的类型为unsigend long。参数nr是可以大于unsigend long的bit的位数(一般为0~31)。假设传入的nr为33,那么修改的就是addr+1地址的数据的第1位(从第0位开始计算)。
void clear_bit(int nr, volatile unsigned long *addr)
将相应位设成0。
void change_bit(int nr, volatile unsigned long *addr)
将相应位置反。
int test_and_set_bit(int nr, volatile unsigned long *addr)
将相应位设成1,并返回未设置之前的值。如果之前的值为0,返回0,如果之前的值为1,返回真(非0,可能是1,也可能是-1,跟平台有关)。
int test_and_clear_bit(int nr, volatile unsigned long *addr)
将相应位设成0,并返回未设置之前的值。
Linux还提供了一些非原子操作的方法:
void __set_bit(int nr, volatile unsigned long *addr) void __clear_bit(int nr, volatile unsigned long *addr) void __change_bit(int nr, volatile unsigned long *addr) int __test_and_set_bit(int nr, volatile unsigned long *addr) int __test_and_clear_bit(int nr, volatile unsigned long *addr) int __test_and_change_bit(int nr,volatile unsigned long *addr) int test_bit(int nr, const volatile unsigned long *addr)
int test_bit(int nr, const volatile unsigned long *addr)
检测相应位的值,如果相应位为0,则返回假;如果相应位为1,则返回真。
除了上面一些操作外,经常还会遇到一些与位相关的宏:
include/linux/bitops.h#define BIT(nr)(1UL << (nr)) #define BIT_MASK(nr)(1UL << ((nr) % BITS_PER_LONG)) #define BIT_WORD(nr)((nr) / BITS_PER_LONG) #define BITS_PER_BYTE8 #define BITS_PER_LONG (sizeof(long) * BITS_PER_BYTE) #define BITS_TO_LONGS(nr)DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
BIT(nr)与BIT_MASK(nr)的效果一样,都是将nr位置1。不同的是当nr大于等于long型所占用的位数时,BIT(nr)返回0。例如,一个long占32位,那么BIT(32)=0,BIT_MASK(32)=1。
BIT_WORD(nr)
BITS_TO_LONGS(nr)
上面两个宏都表示:一个数占用nr位,那么这个数就需要BITS_TO_LONGS(nr)个long型数据来表示。比如,long型数据占用32位。BITS_TO_LONGS(0)=0,BITS_TO_LONGS(1~32)=1。
DIV_ROUND_UP(n,d)
返回n/d的最小整数。
还有下面几个:
fls(unsigned count);
当count为0时,fls(0)返回0。
当count>0时,fls(count)返回将count转换成二进制后,从高位到低位第一个为1的位数(从0开始计算)+1。
比如,fls(1)=1,fls(2) = 2 ,fls(3)=2 ,fls(4)=3, fls(5)=3。
get_count_order(unsigned count);
返回log2count。如果log2count不是整数,那么返回大的整数。
如:当count为1时,返回0,当count为2时,返回1,当count为3~4时,返回2,当count为5~8时,返回3。
判断一个数count是否为2的指数的方法:
count&(count-1)
如果count是2的指数,那么上面与运算结果为0,否则不为0。内核中使用下面方法。
bool is_power_of_2(unsigned long n) { return (n != 0 && ((n & (n - 1)) == 0)); }lib/find_next_bit.c
unsigned long find_first_zero_bit(const unsigned long *addr, unsigned long size)
在以addr开始的内存区中查找第一个值为0的位,查找范围为size大小。
addr为内存区的起始地址,size为要查找的最大长度。
返回第一个位为0的位号。如果没找到,则返回值大于size。
在内存当中从addr为起始地址,以size为最大的搜索范围寻找第一个是0的bit位,并且返回该bit位的bit位号(从0开始计算)。该方法用于取得一个long型数据的最低0位。
如:unsigned long data = 0x5f,则find_first_zero_bit(&data,sizeof(data)) = 5。