cpu位图

SMP处理器中要用到cpu位图,用来维护系统内CPU的状态信息,具有代表性的有:

cpu_possible_map、cpu_online_map、cpu_present_map。

static DECLARE_BITMAP(cpu_possible_bits, CONFIG_NR_CPUS) __read_mostly
static DECLARE_BITMAP(cpu_online_bits, CONFIG_NR_CPUS) __read_mostly
static DECLARE_BITMAP(cpu_present_bits, CONFIG_NR_CPUS) __read_mostly

DECLARE_BITMAP宏定义如下

#define DECLARE_BITMAP(name,bits) \
    unsigned long name[BITS_TO_LONGS(bits)]

所以上面定义了三个unsigned long数组,数组大小有BITS_TO_LONGS宏确定,1~31个cpu,则为1;32~63个cpu,则为2。

目前的多核处理器还没有超过31个的,所以这个数组大小一般为1.

unsigned long cpu_possible_map[BITS_TO_LONGS(CONFIG_NR_CPUS)]
unsigned long cpu_online_map[BITS_TO_LONGS(CONFIG_NR_CPUS)]
unsigned long cpu_present_map [BITS_TO_LONGS(CONFIG_NR_CPUS)]

内核中还是用下面的一种结构体,用来表示cpu位图,于上面的结构基本等价。

typedef struct cpumask { DECLARE_BITMAP(bits, NR_CPUS); } cpumask_t;
/*
struct cpumask {

   unsigned long bits[BITS_TO_LONGS(NR_CPUS)] 

}
*/

并且定义了to_cpumask宏用于从bit_map数组转换到cpumask结构体。

const struct cpumask *const cpu_possible_mask = to_cpumask(cpu_possible_bits);
const struct cpumask *const cpu_online_mask = to_cpumask(cpu_online_bits);
const struct cpumask *const cpu_present_mask = to_cpumask(cpu_present_bits);
#define to_cpumask(bitmap)                        \
    ((struct cpumask *)(1 ? (bitmap)                \
                : (void *)sizeof(__check_is_bitmap(bitmap))))

static inline int __check_is_bitmap(const unsigned long *bitmap)
{
    return 1;
}

内核中bitmap的设置与清除

static inline void set_bit(int nr, volatile unsigned long *addr)
{
    unsigned long mask = BIT_MASK(nr);
    unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
    unsigned long flags;

    _atomic_spin_lock_irqsave(p, flags);
    *p  |= mask;
    _atomic_spin_unlock_irqrestore(p, flags);
}


static inline void clear_bit(int nr, volatile unsigned long *addr)
{
    unsigned long mask = BIT_MASK(nr);
    unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
    unsigned long flags;

    _atomic_spin_lock_irqsave(p, flags);
    *p &= ~mask;
    _atomic_spin_unlock_irqrestore(p, flags);
}

static inline void change_bit(int nr, volatile unsigned long *addr)
{
    unsigned long mask = BIT_MASK(nr);
    unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
    unsigned long flags;

    _atomic_spin_lock_irqsave(p, flags);
    *p ^= mask;
    _atomic_spin_unlock_irqrestore(p, flags);
}

static inline int test_and_set_bit(int nr, volatile unsigned long *addr)
{
    unsigned long mask = BIT_MASK(nr);
    unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
    unsigned long old;
    unsigned long flags;

    _atomic_spin_lock_irqsave(p, flags);
    old = *p;
    *p = old | mask;
    _atomic_spin_unlock_irqrestore(p, flags);

    return (old & mask) != 0;
}

static inline int test_and_clear_bit(int nr, volatile unsigned long *addr)
{
    unsigned long mask = BIT_MASK(nr);
    unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
    unsigned long old;
    unsigned long flags;

    _atomic_spin_lock_irqsave(p, flags);
    old = *p;
    *p = old & ~mask;
    _atomic_spin_unlock_irqrestore(p, flags);

    return (old & mask) != 0;
}

static inline int test_and_change_bit(int nr, volatile unsigned long *addr)
{
    unsigned long mask = BIT_MASK(nr);
    unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
    unsigned long old;
    unsigned long flags;

    _atomic_spin_lock_irqsave(p, flags);
    old = *p;
    *p = old ^ mask;
    _atomic_spin_unlock_irqrestore(p, flags);

    return (old & mask) != 0;
}

最后几个bitmap中常用的宏

#define BIT(nr)            (1UL << (nr))
#define BIT_MASK(nr)        (1UL << ((nr) % BITS_PER_LONG))
#define BIT_WORD(nr)        ((nr) / BITS_PER_LONG)
#define BITS_PER_BYTE        8
#define BITS_TO_LONGS(nr)    DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))

 把位图中所有bit设置为1

static inline void bitmap_fill(unsigned long *dst, int nbits)
{
    size_t nlongs = BITS_TO_LONGS(nbits);
    if (!small_const_nbits(nbits)) {
        int len = (nlongs - 1) * sizeof(unsigned long);
        memset(dst, 0xff,  len);
    }
    dst[nlongs - 1] = BITMAP_LAST_WORD_MASK(nbits);
}

上面用到两个宏,先判断nbis是否超过32,即表示位图的数组元素是否多余1个

#define small_const_nbits(nbits) \
    (__builtin_constant_p(nbits) && (nbits) <= BITS_PER_LONG)

最后一个32位可能没有全用到,下面的后过滤出使用到的bit

#define BITMAP_LAST_WORD_MASK(nbits)                    \
(                                    \
    ((nbits) % BITS_PER_LONG) ?                    \
        (1UL<<((nbits) % BITS_PER_LONG))-1 : ~0UL        \
)

 遍历多cpu

#define for_each_possible_cpu(cpu) for_each_cpu((cpu), cpu_possible_mask)

展开为

/**
 * for_each_cpu - iterate over every cpu in a mask
 * @cpu: the (optionally unsigned) integer iterator
 * @mask: the cpumask pointer
 *
 * After the loop, cpu is >= nr_cpu_ids.
 */
#define for_each_cpu(cpu, mask)                \
    for ((cpu) = -1;                \
        (cpu) = cpumask_next((cpu), (mask)),    \
        (cpu) < nr_cpu_ids;)

 

/**
 * cpumask_next - get the next cpu in a cpumask
 * @n: the cpu prior to the place to search (ie. return will be > @n)
 * @srcp: the cpumask pointer
 *
 * Returns >= nr_cpu_ids if no further cpus set.
 */
static inline unsigned int cpumask_next(int n, const struct cpumask *srcp)
{
    /* -1 is a legal arg here. */
    if (n != -1)
        cpumask_check(n);
    return find_next_bit(cpumask_bits(srcp), nr_cpumask_bits, n+1);
}

 

posted @ 2017-12-26 22:29  bluebluebluesky  阅读(991)  评论(0编辑  收藏  举报