set_bit、clear_bit、wait_on_bit_lock、wake_up_bit整理

set_bit、clear_bit、wait_on_bit_lock、wake_up_bit整理

项目开发过程中遇到了bug,绞尽脑汁,最终发现问题是由于死锁造成的。故将Linux内核中相关方法作出总结和整理,以供参考。

 

set_bit

功能:对addr指向内容的某一位进行置1操作,由参数nr决定

注意nr是需要设置的是“哪一位”的值,而不是将addr的值设置成nr。

 

//代码出自于Linux3.11.8\arch\sh\include\asm\Bitops-llsc.h

static inline void set_bit(int nr, volatile void*addr)

{

   int   mask;

   volatileunsigned int *a = addr;

   unsignedlong tmp;

 

   a += nr>> 5;         //1

   mask = 1<< (nr & 0x1f);    //2

 

   __asm____volatile__ (

      "1:                   \n\t"

      "movli.l @%1, %0  !set_bit   \n\t"

      "or      %2, %0         \n\t"           //3

      "movco.l %0, @%1            \n\t"

      "bf      1b          \n\t"

      :"=&z" (tmp)

      :"r" (a), "r" (mask)    //4

      :"t", "memory"

   );

}

 

1)将nr的高27位取出,作为十进制数加到addr所指向的内容

(为了处理nr大于31的情况)

2) 取出nr的低5位,转换为十进制数,并对1进行左移操作

3) 表示将要执行的是or(或)操作

4) 将addr指向的内容与mask进行or操作,即将addr中的第nr位置1,得到最终结果

 

For example:

假设nr = 3 , *addr = 7,则set_bit(nr , addr)将执行以下操作:

1) a = 7; a +=0;

2) mask  = 1 << 3(00011) = 8 (1000)

3) a = a |mask = 0111 | 1000 = 1111 (f)

4) 最终结果为将addr指向的内容设置为f

 

 

clear_bit

功能:对addr指向内容的某一位进行置1操作,由参数nr决定。与set_bit执行的是相反的操作。

注:clear_bit_unlock()为clear_bit()的封装函数,操作大致相同,详见内核源码

 

static inlinevoid clear_bit(int nr, volatile void *addr)

{

    int mask;

    volatile unsigned int *a = addr;

    unsigned long tmp;

 

    a += nr >> 5;            //1

    mask = 1 << (nr & 0x1f);        //2

 

    __asm__ __volatile__ (

       "1:                  \n\t"

       "movli.l   @%1, %0    ! clear_bit       \n\t"

       "and       %2,%0            \n\t"             //3

       "movco.l   %0, @%1              \n\t"

       "bf    1b            \n\t"

       : "=&z" (tmp)

       : "r" (a), "r"(~mask)          //4

       : "t", "memory"

    );

}

 

1) 2) 与set_bit执行的操作是一样的

3) 表示将要执行的是and(与)操作

4) 将addr指向的内容与mask的反码(~mask)进行and操作,得到最终结果

 

For example:

假设nr = 3 , *addr = f,则clear_bit(nr , addr)将执行以下操作:

1) a = f; a +=0;

2) mask  = 1 << 3(00011) = 8 (1000)

3) ~mask = 7(0111)

3) a = a &mask = 1111 & 0111 = 0111 (7)

4) 最终结果为将addr指向的内容设置为7

 

结果表明,set_bitclear_bit两个操作是可逆的。

 

 

 

 

 

wait_on_bit_lock

功能:同上。对addr指向内容的某一位进行置1操作,由参数nr决定。

 

wait_on_bit_lock()where one is waiting for the bit to clear with the intention of setting it, andwhen done, clearing it.

 

在对某一位置1操作之前,需要等待该位被清0,之后才置1。若此时该位仍未被清0,则陷入等待。

 

static inlineint wait_on_bit_lock(void *word, int bit,

              int (*action)(void *), unsignedmode)

{

    if (!test_and_set_bit(bit, word))

       return 0;            //1

    return out_of_line_wait_on_bit_lock(word,bit, action, mode);

}

 

1) 若test_and_set_bit返回值为0,即对应的比特位上一次被设置的值为0,则函数return 0;否则陷入等待

 

//此函数返回相应比特位上一次被设置的值

static inlineint test_and_set_bit(intnr, volatile void *addr)

{

    int mask,retval;

    volatile unsigned int *a = addr;

    unsigned long tmp;

 

    a += nr >> 5;

    mask = 1 << (nr & 0x1f);

 

    __asm__ __volatile__ (

       "1:                  \n\t"

       "movli.l   @%2, %0    ! test_and_set_bit   \n\t"

       "mov       %0,%1            \n\t"

       "or    %3,%0            \n\t"

       "movco.l   %0, @%2              \n\t"

       "bf    1b            \n\t"             //跳转

       "and       %3,%1            \n\t"

       : "=&z" (tmp),"=&r" (retval)

       : "r" (a), "r" (mask)

       : "t", "memory"

    );

    return retval != 0;

}

wake_up_bit

功能:wake up a waiter on a bit

 

For instance,if one were to have waiters on a bitflag, one would call wake_up_bit() afterclearing the bit.

 

调用wake_up_bit方法后,上述wait_on_bit_lock方法将被唤醒,继续执行

 

 

综上所述,以上四个方法可以实现一个类似于加锁的功能,

For example:以RDMA为例

 

发送数据:

set_bit()     //先加锁

ibv_post_send()      //提交request

wait_bit_on_lock()       //等待解锁

. . . .

 

 

CQhandler

if(ibv_poll_cq()> 0){

clear_bit_unlock()       //解锁

wake_up_bit()        //唤醒wait_bit_on_lock

}

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值