Chinaunix首页 | 论坛 | 博客
  • 博客访问: 415682
  • 博文数量: 60
  • 博客积分: 442
  • 博客等级: 下士
  • 技术积分: 910
  • 用 户 组: 普通用户
  • 注册时间: 2010-03-27 14:53
文章分类

全部博文(60)

文章存档

2021年(1)

2018年(1)

2017年(14)

2016年(31)

2015年(1)

2013年(3)

2012年(9)

我的朋友

分类: LINUX

2016-04-17 15:45:58

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的长度



阅读(5485) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~