Chinaunix首页 | 论坛 | 博客
  • 博客访问: 492063
  • 博文数量: 72
  • 博客积分: 1851
  • 博客等级: 上尉
  • 技术积分: 1464
  • 用 户 组: 普通用户
  • 注册时间: 2010-09-16 17:50
文章分类

全部博文(72)

文章存档

2013年(1)

2012年(17)

2011年(51)

2010年(3)

分类: 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 1632位中查找第一位或最后一位为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

阅读(3061) | 评论(0) | 转发(1) |
0

上一篇:gcc扩展宏技巧

下一篇:C++函数指针

给主人留下些什么吧!~~