分类: LINUX
2012-01-07 14:34:45
简单的位操作定义分析如下:
这些函数根据不同的体系结构采用不同的汇编语言实现(x86为例:/include/asm-x86/bitops_64.h):
#define ADDR “+m” (*(volatile long *)addr) //需要读写该区域
LOCK_PREFIX定义如下:
#ifdef CONFIG_SMP
#define LOCK_PREFIX \
“.section .smp_locks,\”a\”\n” \ ;创建一个字段smp_locks
“ .align 8\n” ;地址(location counter) 8字节对齐
“ .quad 661f\n” /*address*/ \
“.previous\n”
“661:\n\tlock;” ;最重要的是这里,lock前缀防止并行访问
#else
#define LOCK_PREFIX “”
#endif
static inline void set_bit(int nr,volatile void *addr)
{
__asm__ __volatile__( LOCK_PREFIX
“btsl %1,%0” //btsl n ADDR(long类型数值) 将设置第n位,如果该位为1则设置CF标记
:ADDR
:”dIr” (nr):”memory”);//d:使用edx寄存器,I:立即数,r:限制nr为一寄存器值
}
static inline void __set_bit(int nr,volatile void *addr)
{
__asm__ volatile(
”btsl %1,%0”
:ADDR
:”dIr”(nr):”memory”);
}
static inline void clear_bit_unlock(unsigned long nr,volatile unsigned long *addr)
{
barrier();//防止进行调整执行顺序,变量赋值优化,该函数上面没有这里有点奇怪
clear_bit(nr,addr);
}
static inline void clear_bit(int nr,volatile void *addr)
{
__asm__ __volatile__( LOCK_PREFIX
“btrl %1,%0” //btrl n ADDR(long类型数值),将第n位清0,如果该位为1则设置CF标记
:ADDR
:”dIr” (nr));
}
static inline void __clear_bit(int nr,volatile void *addr)
{
__asm__ __volatile__(
“btrl %1,%0”
:ADDR
:”dIr” (nr));
}
static inline void change_bit(int nr,volatile void *addr)
{
__asm__ __volatile__( LOCK_PREFIX
“btcl %1,%0” //btcl nr ADDR,将ADDR中第nr位取反
:ADDR
:”dIr” (nr));
}
static inline int test_and_set_bit(int nr,volatile void *addr)
{
int oldbit;
__asm__ __volatile__(LOCK_PREFIX
“btsl %2,%1\n\tsbbl %0,%0” //btsl:设置ADDR处第nr位,如果该位为1则设置CF标记
:”=r” (oldbit),ADDR //sbbl:带进位的减,这样就获取到第nr为的值!!
:”dIr”(nr):”memory”);
return oldbit;
}
static inline int test_and_clear_bit(int nr,volatile void *addr)
{
int oldbit;
__asm__ __volatile__(LOCK_PREFIX
“btrl %2,%1\n\tsbbl %0,%0”
:”=r” (oldbit),ADDR
:”dIr” (nr):”memory”);
return oldbit;
}
static inline int test_and_change_bit(int nr,volatile void *addr)
{
int oldbit;
__asm__ __volatile__(LOCK_PREFIX
“btcl %2,%1\n\tsbbl %0,%0”
:”=r” (oldbit),ADDR
:”dIr” (nr) : “memory”)
return oldbit;
}
static inline long
__scanbit(unsigned long val,unsigned long max)
{
//bsf:bit scan forward,or bsr:bit scan reverse 在16或32位中查找第一位或最后一位为1,
//如果查找失败就会设置ZF标记
//bsf/bsr dest,source
//cmovz:ZF标记设置,就会触发mov行为
asm(“bsfq %1,%0; cmovz %2,%0”:”=&r” (val):”r”(val),”r”(max));
return val;
}
//__builtin_constant_p(size):确定size在编译期间是(返回1)否(返回0)为常量
//查找第一个设置为1的位
#define find_first_bit(addr,size) \
((__builtin_constant_p(size) && (size) <= BITS_PER_LONG? \
(__scan_bit(*(unsigned long *)addr,(size))):\
find_first_bit(addr,size)))
#define find_next_bit(addr,size,off) \
((__builtin_constant_p(size) && (size) <= BITS_PER_LONG? \
((off) + (__scanbit((*(unsigned long *)addr)>>(off),(size)-(off)))):\
find_next_bit(addr,size,off)))
//找到0位,为了使用scanbit函数,直接将参数取反
#define find_first_zero_bit(addr,size) \
((__builtin_constant_p(size) && (size) <= BITS_PER_LONG ? \
(__scanbit(~*(unsigned long *)addr,(size))) : \
find_first_zero_bit(addr,size)))
#define find_next_zero_bit(addr,size) \
((__builtin_constant_p(size) && (size) <= BITS_PER_LONG? \
((off)+(__scanbit(~(((*(unsigned long *)addr)) >> (off)),(size) – (off)))):\
find_next_zero_bit(addr,size,off)))
/*
Find string of zero bits in a bitmap, -1 when not found.
*/
extern unsigned long find _next_zero_string(unsigned long *bitmap,long start,long nbits,int len);
//设置起始位置为i,长度为len的所有位
static inline void set_bit_string(unsigned long *bitmap,unsigned long i,int len)
{
unsigned long end = i + len;
while(i < end) {
__set_bit(i,bitmap);
i++;
}
}
//清除起始位置为i,长度为len的所有位
static inline void __clear_bit_string(unsigned long *bitmap,unsigned long i,int len)
{
unsigned long end = i+len;
while(i __clear_bit(i,bitmap); i++; } } //调用与上面__scanbit一样的指令,参数的字长不一致 static inline int ffs(int x) { int r; __asm__(“bsfl %1,%0\n\t” “cmovzl %2,%0” : “=r”
(r):”rm”(x),”r”(-1)); return r+1; } //从低位查找置为1的位的位置 static inline int fls(int x) { int r; __asm__(“bsrl %1,%0\n\t” “cmovz %2,%0” : “=&r” (r) :
“rm”(x),”rm”(-1)); return r+1; } 参考资料: linux-2.6.26.4源码 professional assembly
Language LOCK_PREFIX参考这里:http://blog.chinaunix.net/space.php?uid=546544&do=blog&id=2096146