概述
set_bit、clear_bit、wait_on_bit_lock、wake_up_bit整理
项目开发过程中遇到了bug,绞尽脑汁,最终发现问题是由于死锁造成的。故将Linux内核中相关方法作出总结和整理,以供参考。
set_bit
功能:对addr指向内容的某一位进行置1操作,由参数nr决定
注意nr是需要设置的是“哪一位”的值,而不是将addr的值设置成nr。
//代码出自于Linux3.11.8archshincludeasmBitops-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: nt"
"movli.l @%1, %0 !set_bit nt"
"or %2, %0 nt" //3
"movco.l %0, @%1 nt"
"bf 1b nt"
:"=&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: nt"
"movli.l @%1, %0 ! clear_bit nt"
"and %2,%0 nt" //3
"movco.l %0, @%1 nt"
"bf 1b nt"
: "=&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_bit和clear_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: nt"
"movli.l @%2, %0 ! test_and_set_bit nt"
"mov %0,%1 nt"
"or %3,%0 nt"
"movco.l %0, @%2 nt"
"bf 1b nt" //跳转
"and %3,%1 nt"
: "=&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
}
最后
以上就是热情人生为你收集整理的set_bit、clear_bit、wait_on_bit_lock、wake_up_bit整理的全部内容,希望文章能够帮你解决set_bit、clear_bit、wait_on_bit_lock、wake_up_bit整理所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复