zoukankan      html  css  js  c++  java
  • 【转】【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的应用

  • 相关阅读:
    总结:使用pll来进行“异步复位,同步释放”
    总结“异步复位,同步释放”
    用quartusII再带的modelsim进行后仿真(时序仿真)的操作步骤
    Notepad++新建文件默认保存格式修改问题
    英语翻译正确的思维
    浅谈web网站架构演变过程
    MVC-API(二)
    C#面向对象编程的基础
    C# 堆栈讲解
    AutoCAD 2013 之R14版本下载地址整理汇总
  • 原文地址:https://www.cnblogs.com/ftsummerer/p/4079491.html
Copyright © 2011-2022 走看看