我是靠谱客的博主 魁梧狗,最近开发中收集的这篇文章主要介绍学了手内核的位运算(1):test_and_set_bit,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

我一直都对位运算感兴趣,但凡最小的bit都能干一件大事,比如最多见的“存放一种状态”。
果然瘦子都比胖子灵活,就连计算机也没有例外,位运算巧妙的用着计算机的与门、或门、非门和异或等简单操作,就将空间开销拉到了最低。

碰巧正研究着kernel的网络协议栈,看到了中间也参杂着不少的位运算函数,所以仗着捣鼓TCP的机会,学习下内核的一些位运算机制。一是学到点自己感兴趣的东西,二是以后再遇到,自然可以相视一笑。

此外,内核的位运算实现大多都是原子操作,这让这些位运算函数被广泛用于内核的各个地方。

写到这,回想下,自己熟悉的原子操作只是操作系统“锁”和“信号量”的PV原子操作,惊!!!

test_and_set_bit函数在内核中很常见,最近一次看见是在 “TCP-TSQ机制” 中,socket被用户持有,还没有被释放,tcp_tsq_handler函数将暂停当前的数据流程,等待控制流程的结束,当前socket会被打上TCP_TSQ_DERFERRED延迟标识,用的正是test_and_set_bit

test_and_set_bit最多的用途就是“存放一种状态”。

位运算test_and_set_bit的本质

test_and_set_bit函数的机制是设置addr指针所指向对象的第nr位,并返回原先nr位上的值。

/**
 * test_and_set_bit - Set a bit and return its old value
 * @nr: Bit to set
 * @addr: Address to count from
 */
static inline int test_and_set_bit(int nr, unsigned long *addr) 
{
	// BIT掩码
	unsigned long mask = BIT_MASK(nr);
	// 原addr地址
	unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
	unsigned long old;
	old = *p;
	// 原地址和掩码的或——1/0置1,1/1置0
	*p = old | mask;
	// 原地址和掩码的与——1/1置1,1/0置0,即返回原值
	//语句亦可用return old & mask;
	return (old & mask) != 0;
}

test_and_set_bit地址bit位掩码就搞定,光看代码还犯嘀咕,我下面再来张图。
test_and_set_bit

应该很清楚了,没有太多复杂的调度,一切都那么直观,而内核也一直是这么做的。

至于BIT_MASK(nr)BIT_WORD(nr)我特意去内核源码找了下,翻出来给大家看看。

/* 宏运算
* BIT_PER_LONG是long类型的位长度
* 那么BIT_MASK很清楚是nr位的置1
* BIT_WORD是位和BIT_PER_LONG的余数,往往BIT_WORD(nr)是0
*/
#define BIT_MASK(nr)		(UL(1) << ((nr) % BITS_PER_LONG))
#define BIT_WORD(nr)		((nr) / BITS_PER_LONG)

好了,就先到这里,“肥西”有点小情绪了,我得花点时间去照顾我的猫了。

最后

以上就是魁梧狗为你收集整理的学了手内核的位运算(1):test_and_set_bit的全部内容,希望文章能够帮你解决学了手内核的位运算(1):test_and_set_bit所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(87)

评论列表共有 0 条评论

立即
投稿
返回
顶部