【转】【Linux】理解bitops中的__set_bit及其应用

位操作在kernel中很普遍,以下针对__set_bit函数为例来分析其原理:

在kernel/include/asm-generic/bitops/non-atomic.h头文件下有如下

  1. /**
  2. * __set_bit - Set a bit in memory
  3. * @nr: the bit to set
  4. * @addr: the address to start counting from
  5. *
  6. * Unlike set_bit(), this function is non-atomic and may be reordered.
  7. * If it‘s called on the same region of memory simultaneously, the effect
  8. * may be that only one operation succeeds.
  9. */
  10. static inline void __set_bit(int nr, volatile unsigned long *addr)
  11. {
  12. unsigned long mask = BIT_MASK(nr);
  13. unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
  14. *p |= mask;
  15. }

在kernel/include/linux/bitops.h中有BIT_MASK,BIT_WORD

点击(此处)折叠或打开

  1. ......
  2. #include <asm/types.h>
  3. ......
  4. #define BIT(nr)            (1UL << (nr))
  5. #define BIT_MASK(nr)        (1UL << ((nr) % BITS_PER_LONG))
  6. #define BIT_WORD(nr)        ((nr) / BITS_PER_LONG)

在kernel/arch/arm/include/asm/types.h中有BITS_PER_LONG

点击(此处)折叠或打开

  1. #define BITS_PER_LONG 32

所以__set_bit函数内容等价表示如下:

点击(此处)折叠或打开

  1. static inline void __set_bit(int nr, volatile unsigned long *addr)
  2. {
  3. addr[nr/32] |= (1UL << (nr % 32));
  4. //或者addr[nr >> 5] |= (1UL << (nr & 31));
  5. }

addr是一个类型为unsigned long(32 bits)的数组,通过nr/32得到要设置的比特位nr位于该数组中的哪一个unsigned long。
然后,通过( nr%32 )得到该unsigned long整数中是哪一位(第0位、第1位、...还是第31位?)需要设置。
最后,通过 addr[nr/32] |= (1UL << (nr % 32)) 设置该unsigned long整数中相应的比特位。

addr地址所指的32bit位图如下:
                              ________________
          0       <---     |_|_|_|_|_|_|_|_|...._|
          1       <---     |____________...._|
          2       <---     |____________...._|
          .        <---     |____________...._|
          .        <---     |____________...._|
       nr/32   <---     |____________...._|

理解了上述代码,则其它比特位操作API就容易懂了。
__clear_bit: 将addr所指的地址处的值第nr位清0,方法一般 addr[nr/32] & 11111011111
__change_bit: 将addr所指的地址处的值第nr位取反,方法一般 addr[nr/32]  ^ 00000100000
__test_and_set_bit:将addr所指的地址处的值第nr位置1,返回该bit原始值(0或1);
__test_and_clear_bit:将addr所指的地址处的值第nr位清0,返回该bit原始值(0或1);
__test_and_change_bit:将addr所指的地址处的值第nr位取反,返回该bit原始值(0或1);
test_bit:即测试nr位是否被置位,置位返回1;

——————————————————————————————————————————————
比特位操作在代码中到处使用,灵活使用这些操作将能够大大提高系统的性能,以下举例说明:

1. Linux 2.6中进程调度中bitops的应用
   Linux 2.6内核重写了进程调度这部分,其时间复杂度为O(1)
   每个cpu有自己单独的运行队列runqueues,而每个运行队列中,把进程分为活动进程队列和过期进程队列。

  1. struct prio_array {
  2. unsigned int nr_active; //当前队列进程数
  3. DECLARE_BITMAP(bitmap, MAX_PRIO+1);//位图,每一位表示对应级别的进程链表是否有进程
  4. struct list_head queue[MAX_PRIO]; //进程链表,共MAX_PRIO(140)级,进程按其优先级存放在这个链表中
  5. };

每次调度时,从活动进程队列的最高优先级链表中选择第一个进程作为next。
   我们来看看它是如何选择的。
   我们先看prio_arry中的queue[MAX_PRIO], 进程按优先级放入这个队列中,queue[0]中的全部进程其优先级为0,其优先级最高,queue[1]中的全部进程其优先级为1, 优先级的值越小优先运行。
   0~MAX_RT_PRIO(100)为实时进程的优先级,MAX_RT_PRIO~MAX_PRIO(140)为普通进程的优先级。

bitmap为5个32位整数,它的前140位对应140个优先级,比如:bitmap的第5位置1,表示优先级为5的进程队列存在进程。
   idx = sched_find_first_bit(array->bitmap)就是查找bitmap中第一个为1的位,那么就可以获取当前优先级最高的进程队列。

2.  Linux中输入子系统中bitops的应用

点击(此处)折叠或打开

  1. struct input_dev {
  2. const char *name;
  3. const char *phys;
  4. const char *uniq;
  5. struct input_id id;
  6. /*
         * 根据各种输入信号的类型来建立类型为unsigned long 的数组,
         * 数组的每1bit代表一种信号类型,
         * 内核中会对其进行置位或清位操作来表示事件的发生和被处理.
         */
  7. unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)];
  8. unsigned long evbit[BITS_TO_LONGS(EV_CNT)];
  9. unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];
  10. unsigned long relbit[BITS_TO_LONGS(REL_CNT)];
  11. unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];
  12. unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];
  13. unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];
  14. unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];
  15. unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];
  16. unsigned long swbit[BITS_TO_LONGS(SW_CNT)];
  17. ...............................
  18. }

3. Port中bitops的应用

4. VLAN(1-4094)中bitops的应用

时间: 2024-08-26 10:24:54

【转】【Linux】理解bitops中的__set_bit及其应用的相关文章

linux c程序中获取shell脚本输出的实现方法

linux c程序中获取shell脚本输出的实现方法 1. 前言Unix界有一句名言:“一行shell脚本胜过万行C程序”,虽然这句话有些夸张,但不可否认的是,借助脚本确实能够极大的简化一些编程工作.比如实现一个ping程序来测试网络的连通性,实现ping函数需要写上200~300行代码,为什么不能直接调用系统的ping命令呢?通常在程序中通过 system函数来调用shell命令.但是,system函数仅返回命令是否执行成功,而我们可能需要获得shell命令在控制台上输出的结果.例如,执行外部

Linux基础--系统启动中grub功能

本文主要讲解grub原理和系统启动过程中grub的作用过程. grub是多数Linux发行版中使用的boot loader系统引导程序, 其主要作用是计算机从boot sequence中选取指定设备之后, 由grub找到系统内核kernel文件并加载内核文件的作用. grub执行过程 grub作用过程中主要分为三个阶段的作用, 如下图所示: stage1: 启动grub程序, 位于MBR的前446Byte中; stage1.5: 识别内核所在分区的文件系统类型, 位于内核文件所在分区的boot

我对linux理解之driver_register

------------------------------------------ 本文系本站原创,欢迎转载! 转载请注明出处:amingriyue.blog.chinaunix.net ------------------------------------------/** * driver_register - register driver with bus * @drv: driver to register * * We pass off most of the work to t

Hasen的linux设备驱动开发学习之旅--linux设备驱动中的并发与竞态

/** * Author:hasen * 参考 :<linux设备驱动开发详解> * 简介:android小菜鸟的linux * 设备驱动开发学习之旅 * 主题:linux设备驱动中的并发与竞态 * Date:2014-11-04 */ 1.并发与竞态 并发(concurrency)指的是多个执行单元同时.并行被执行,而并发的执行单元对共享资源(软件上的全 局变量,静态变量等)的访问则很容易导致竞态(race conditions). 主要的竞态发生在以下几种情况: (1)对称多处理(SMP)

python3----如何简单地理解Python中的if __name__ == &#39;__main__&#39;

1. 摘要 通俗的理解__name__ == '__main__':假如你叫小明.py,在朋友眼中,你是小明(__name__ == '小明'):在你自己眼中,你是你自己(__name__ == '__main__'). if __name__ == '__main__'的意思是:当.py文件被直接运行时,if __name__ == '__main__'之下的代码块将被运行:当.py文件以模块形式被导入时,if __name__ == '__main__'之下的代码块不被运行. 2. 程序入口

[转] linux下shell中使用上下键翻出历史命名时出现^[[A^[[A^[[A^[[B^[[B的问题解决,Linux使用退格键时出现^H解决方法

[From] https://www.zmrbk.com/post-2030.html https://blog.csdn.net/suifengshiyu/article/details/40952771 我的理解是,如果出现如题所描述的问题,这是因为使用了不同的shell程序和对应的stty设置对应关系所综合作用的结果. 这是/bin/sh里面stty -a命令输出的信息: $ stty -a speed 38400 baud; rows 43; columns 209; line = 0;

一篇文章助你理解Python3中字符串编码问题

前几天给大家介绍了unicode编码和utf-8编码的理论知识,以及Python2中字符串编码问题,没来得及上车的小伙伴们可以戳这篇文章:浅谈unicode编码和utf-8编码的关系和一篇文章助你理解Python2中字符串编码问题.下面在Python3环境中进行代码演示,分别Windows和Linux操作系统下进行演示,以加深对字符串编码的理解. 在Python2的Python文件的文件头往往会声明字符的编码格式,通过会使用代码"#-*- coding -*-"作为编码声明,如下图所示

深入理解CSS中的层叠上下文和层叠顺序(转)

by zhangxinxu from http://www.zhangxinxu.com 本文地址:http://www.zhangxinxu.com/wordpress/?p=5115 零.世间的道理都是想通的 在这个世界上,凡事都有个先后顺序,凡物都有个论资排辈.比方说食堂排队打饭,对吧,讲求先到先得,总不可能一拥而上.再比如说话语权,老婆的话永远是对的,领导的话永远是对的. 在CSS届,也是如此.只是,一般情况下,大家歌舞升平,看不出什么差异,即所谓的众生平等.但是,当发生冲突发生纠葛的时

深入理解CSS中的margin

1.css margin可以改变容器的尺寸 元素尺寸 可视尺寸--标准盒子模型中盒子的宽度是不包括margin值的,clientWidth 占据尺寸--包括margin的宽度 outWidth不在标准之中,jquery中有相对应的方法 margin与可视尺寸 1.1使用那个与没有设定width/height的普通block水平元素 2.2只适用于水平方向尺寸 <body style="background-color:#1a2b3c"> <div style=&quo