set_bit(unsigned int bit,volatile unsigned long *p)研究

#include <stdio.h>

void set_bit(unsigned int bit,volatile unsigned int *p)
{
        unsigned int mask = 1 << (bit &31);
    
        printf(" mask = 0x%x\n",mask);
        printf(" p = %p\n",p);
        p += bit >> 5;
    
        *p |= mask;

        printf(" p = %p\n",p);
        printf("*p = 0x%x\n",*p);
}
    

int main()
{
        int a = 31;
        int b = 232;
        int *p = &b;
        set_bit(a,p);
}


作用是将数据*p的第bit位设置成1.






在include/linux/bitops.h中对比特位操作的API中: bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1).

如何来理解下面的代码呢?

// Note: nr为要设置的比特位(可以是0或者更大的值),addr为位图的起始地址
void __set_bit(int nr, volatile unsigned long *addr)
{
    unsigned long mask = 1 << (nr & 0x1f);
    unsigned long *p = ((unsigned long *)addr) + (nr >> 5);

    *p |= mask;
}

由于0x1f(16进制) = 0001 1111(二进制) = 31(十进制),
因而将上述代码翻译为下面的代码,则更为清晰一些:
void __set_bit(int nr, volatile unsigned long *addr)
{
    addr[nr >> 5] |= (1UL << (nr & 31));
}

而且nr>>5 即nr/32,那么下面的代码就更加清晰了:
    addr[nr/32] |= (1UL << (nr & (32-1)));

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

理解了上述代码,则其它比特位操作API就容易懂了。

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

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

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

   每次调度时,从活动进程队列的最高优先级链表中选择第一个进程作为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的应用
   struct input_dev {

    void *private;

    const char *name;
    const char *phys;
    const char *uniq;
    struct input_id id;

    /*
     * 根据各种输入信号的类型来建立类型为unsigned long 的数组,
     * 数组的每1bit代表一种信号类型,
     * 内核中会对其进行置位或清位操作来表示事件的发生和被处理.
     */

    unsigned long evbit[NBITS(EV_MAX)];
    unsigned long keybit[NBITS(KEY_MAX)];
    unsigned long relbit[NBITS(REL_MAX)];
    unsigned long absbit[NBITS(ABS_MAX)];
    unsigned long mscbit[NBITS(MSC_MAX)];
    unsigned long ledbit[NBITS(LED_MAX)];
    unsigned long sndbit[NBITS(SND_MAX)];
    unsigned long ffbit[NBITS(FF_MAX)];
    unsigned long swbit[NBITS(SW_MAX)];

    .........................................
};

3. Port中bitops的应用

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

你可能感兴趣的:(set_bit(unsigned int bit,volatile unsigned long *p)研究)