CPU 비트맵 (API)

 

for_each_cpu()

include/linux/cpumask.h

/**
 * 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;)
  • mask가 가리키는 비트맵에서 각 비트가 1로 기록된 노드만큼 루프를 돈다.
    • nr_cpu_ids는 초기에 NR_CPUS 값이 설정되었다가 나중에 possible cpu id + 1 값으로 설정된다.

 

for_each_possible_cpu()

include/linux/cpumask.h

#define for_each_possible_cpu(cpu) for_each_cpu((cpu), cpu_possible_mask)
  • cpu_possible_mask가 가리키는 비트맵에서 각 비트가 1로 기록된 노드만큼 루프를 돈다.

 

for_each_online_cpu()

include/linux/cpumask.h

#define for_each_online_cpu(cpu)   for_each_cpu((cpu), cpu_online_mask)
  • cpu_online_mask가 가리키는 비트맵에서 각 비트가 1로 기록된 노드만큼 루프를 돈다.

 

for_each_present_cpu()

include/linux/cpumask.h

#define for_each_present_cpu(cpu)  for_each_cpu((cpu), cpu_present_mask)
  • cpu_present_mask가 가리키는 비트맵에서 각 비트가 1로 기록된 노드만큼 루프를 돈다.

 

on_each_cpu_mask()

/**
 * on_each_cpu_mask(): Run a function on processors specified by
 * cpumask, which may include the local processor.
 * @mask: The set of cpus to run on (only runs on online subset).
 * @func: The function to run. This must be fast and non-blocking.
 * @info: An arbitrary pointer to pass to the function.
 * @wait: If true, wait (atomically) until function has completed
 *        on other CPUs.
 *
 * If @wait is true, then returns once @func has returned.
 *
 * You must not call this function with disabled interrupts or from a
 * hardware interrupt handler or from a bottom half handler.  The
 * exception is that it may be used during early boot while
 * early_boot_irqs_disabled is set.
 */                     
void on_each_cpu_mask(const struct cpumask *mask, smp_call_func_t func,
                        void *info, bool wait)
{
        int cpu = get_cpu();    

        smp_call_function_many(mask, func, info, wait);
        if (cpumask_test_cpu(cpu, mask)) {
                unsigned long flags;
                local_irq_save(flags);
                func(info);
                local_irq_restore(flags);
        }               
        put_cpu();
}        
EXPORT_SYMBOL(on_each_cpu_mask);

func 함수를 다른 cpu에서 모두 수행시키고 현재 cpu에서도 수행시킨다. 인수 wait이 true인 경우 모든 cpu의 수행이 완료될 때까지 기다린다.

 

cpumask_first()

include/linux/cpumask.h

/**
 * cpumask_first - get the first cpu in a cpumask
 * @srcp: the cpumask pointer
 *
 * Returns >= nr_cpu_ids if no cpus set.
 */
static inline unsigned int cpumask_first(const struct cpumask *srcp)
{
        return find_first_bit(cpumask_bits(srcp), nr_cpumask_bits);
}

srcp가 가리키는 cpu 상태 관련 비트맵의 nr_cpumask_bits 까지에서 1로 설정된 첫 cpu id(based 0)를 알아온다.

 

cpumask_next()

include/linux/cpumask.h

/**
 * 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);
}

srcp가 가리키는 cpu 상태 관련 비트맵의 nr_cpumask_bits 까지에서 n+1 번째 비트부터 1로 설정된 cpu id(based 0)를 찾아 알아온다.

 

cpumask_next_zero()

include/linux/cpumask.h

/**
 * cpumask_next_zero - get the next unset 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 unset.
 */
static inline unsigned int cpumask_next_zero(int n, const struct cpumask *srcp)
{
        /* -1 is a legal arg here. */
        if (n != -1)
                cpumask_check(n);
        return find_next_zero_bit(cpumask_bits(srcp), nr_cpumask_bits, n+1);
}

srcp가 가리키는 cpu 상태 관련 비트맵의 nr_cpumask_bits 까지에서 n+1 번째 비트부터 0으로 설정된 cpu id(based 0)를 찾아 알아온다.

 

cpumask_next_and()

lib/cpumask.c

/**
 * cpumask_next_and - get the next cpu in *src1p & *src2p
 * @n: the cpu prior to the place to search (ie. return will be > @n)
 * @src1p: the first cpumask pointer
 * @src2p: the second cpumask pointer
 *
 * Returns >= nr_cpu_ids if no further cpus set in both.
 */ 
int cpumask_next_and(int n, const struct cpumask *src1p,
                     const struct cpumask *src2p)
{
        while ((n = cpumask_next(n, src1p)) < nr_cpu_ids)
                if (cpumask_test_cpu(n, src2p))
                        break;
        return n;
}
EXPORT_SYMBOL(cpumask_next_and);

src1p와 src2p가 가리키는 두 개의 cpu 상태 관련 비트맵의 n+1 번째 비트부터 두 비트맵이 동시에 1로 설정된 cpu id(based 0)를 찾아 알아온다.

 

cpumask_first_and()

include/linux/cpumask.h

/**
 * cpumask_first_and - return the first cpu from *srcp1 & *srcp2
 * @src1p: the first input
 * @src2p: the second input
 *       
 * Returns >= nr_cpu_ids if no cpus set in both.  See also cpumask_next_and().
 */
#define cpumask_first_and(src1p, src2p) cpumask_next_and(-1, (src1p), (src2p))

src1p와 src2p가 가리키는 두 개의 cpu 상태 관련 비트맵의 1 번째 비트부터 두 비트맵이 동시에 1로 설정된 cpu id(based 0)를 찾아 알아온다.

 

CPU 상태

cpumask_t 타입

include/linux/cpumask.h

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

 

cpu 비트맵 배열

다음은 unsigned long 배열 형태의 비트맵이다.

  • cpu_all_bits[]
  • cpu_possible_bits[]
  • cpu_online_bits[]
  • cpu_present_bits[]
  • cpu_active_bits[]

다음은 위 4개의 비트맵을 가리키는 const 포인터이다.

  • *cpu_possible_mask
  • *cpu_online_mask
  • *cpu_present_mask
  • *cpu_active_mask

kernel/cpu.c

const DECLARE_BITMAP(cpu_all_bits, NR_CPUS) = CPU_BITS_ALL;
EXPORT_SYMBOL(cpu_all_bits);

#ifdef CONFIG_INIT_ALL_POSSIBLE
static DECLARE_BITMAP(cpu_possible_bits, CONFIG_NR_CPUS) __read_mostly
        = CPU_BITS_ALL;
#else
static DECLARE_BITMAP(cpu_possible_bits, CONFIG_NR_CPUS) __read_mostly;
#endif
const struct cpumask *const cpu_possible_mask = to_cpumask(cpu_possible_bits);
EXPORT_SYMBOL(cpu_possible_mask);

static DECLARE_BITMAP(cpu_online_bits, CONFIG_NR_CPUS) __read_mostly;
const struct cpumask *const cpu_online_mask = to_cpumask(cpu_online_bits);
EXPORT_SYMBOL(cpu_online_mask);

static DECLARE_BITMAP(cpu_present_bits, CONFIG_NR_CPUS) __read_mostly;
const struct cpumask *const cpu_present_mask = to_cpumask(cpu_present_bits);
EXPORT_SYMBOL(cpu_present_mask);

static DECLARE_BITMAP(cpu_active_bits, CONFIG_NR_CPUS) __read_mostly;
const struct cpumask *const cpu_active_mask = to_cpumask(cpu_active_bits);
EXPORT_SYMBOL(cpu_active_mask);

 

전역 변수

nr_cpu_ids

kernel/smp.c

/* Setup number of possible processor ids */
int nr_cpu_ids __read_mostly = NR_CPUS;
EXPORT_SYMBOL(nr_cpu_ids);
  • 초기 값은 NR_CPUS로 설정됨

 

setup_max_cpus

kernel/smp.c

/* Setup configured maximum number of CPUs to activate */
unsigned int setup_max_cpus = NR_CPUS;
EXPORT_SYMBOL(setup_max_cpus);
  • 초기 값은 NR_CPUS로 설정됨

 

커널 파라메터

“nosmp”

kernel/smp.c

static int __init nosmp(char *str)
{
        setup_max_cpus = 0;
        arch_disable_smp_support();

        return 0;
}

early_param("nosmp", nosmp);

커널 파라메터 “nosmp”가 입력되면 setup_max_cpus에 0을 대입하고 arch_disable_smp_support() 함수를 통해 smp 기능이 동작하지 않도록 한다.

  • 현재 이 커널 파라메터는 x86 시스템에만 구현되어 있다.

 

arch_disable_smp_support()

kernel/smp.c

/*
 * Setup routine for controlling SMP activation
 *
 * Command-line option of "nosmp" or "maxcpus=0" will disable SMP
 * activation entirely (the MPS table probe still happens, though).
 *
 * Command-line option of "maxcpus=<NUM>", where <NUM> is an integer
 * greater than 0, limits the maximum number of CPUs activated in
 * SMP mode to <NUM>.
 */

void __weak arch_disable_smp_support(void) { }
  • 각 아키텍처에서 정의된 함수를 사용하며 없는 경우 weak 함수로 정의된 빈 함수가 동작한다.

 

“nr_cpus”

kernel/smp.c

/* this is hard limit */
static int __init nrcpus(char *str)
{
        int nr_cpus;

        get_option(&str, &nr_cpus);
        if (nr_cpus > 0 && nr_cpus < nr_cpu_ids)
                nr_cpu_ids = nr_cpus;

        return 0;
}

early_param("nr_cpus", nrcpus);

커널 파라메터 “nr_cpus”로 입력 받은 cpu 수를 nr_cpu_ids에 대입한다.  대입 가능 범위는 1~nr_cpus 만큼이다.

  • 예) “nr_cpus=2”

 

get_option()

lib/cmdline.c

/**
 *      get_option - Parse integer from an option string 
 *      @str: option string
 *      @pint: (output) integer value parsed from @str
 *
 *      Read an int from an option string; if available accept a subsequent
 *      comma as well.
 *
 *      Return values:
 *      0 - no int in string
 *      1 - int found, no subsequent comma
 *      2 - int found including a subsequent comma
 *      3 - hyphen found to denote a range
 */

int get_option(char **str, int *pint)
{
        char *cur = *str;

        if (!cur || !(*cur))
                return 0;
        *pint = simple_strtol(cur, str, 0);
        if (cur == *str)
                return 0;
        if (**str == ',') {
                (*str)++; 
                return 2;
        }
        if (**str == '-')
                return 3;
        
        return 1;
}
EXPORT_SYMBOL(get_option);

str 문자열을 정수로 변환하여 pint에 저장하고 리턴 되는 값은 다음과 같다.

  • 정수 변환이 되지 않는 경우 0
  • 정수 변환 후, 옵션 문자열이 없는 경우 1
  • 정수 변환 후, 옵션 문자열이 ‘,’인 경우 2
  • 정수 변환 후, 옵션 문자열이 ‘-‘인 경우 3

 

  • if (!cur || !(*cur)) return 0;
    • cur가 null이거나 cur 문자열이 “”인 경우 0을 리턴한다.
  • *pint = simple_strtol(cur, str, 0);
    • cur를 파싱하고 숫자로 변환하여 pint에 저장한다. 변환된 문자열의 다음 문자를 가리키는 주소를 출력 인수 str에 저장한다.
  • if (cur == *str) return 0;
    • 문자열을 숫자로 변환되지 않는 경우 0을 리턴한다.
  • if (**str == ‘,’) { (*str)++; return 2; }
    • 변환 후 다음 문자가 ‘,’인 경우 str을 증가시키고 2를 리턴한다.
  • if (**str == ‘-‘) return 3;
    • 변환 후 다음 문자가 ‘-‘인 경우 str을 증가시키고 3을 리턴한다.
  • 변환 후 문자가 ‘,’ 또는 ‘-‘가 아닌 경우 1을 리턴한다.

 

“maxcpus”

kernel/smp.c

static int __init maxcpus(char *str)
{
        get_option(&str, &setup_max_cpus);
        if (setup_max_cpus == 0)
                arch_disable_smp_support();

        return 0;
}

early_param("maxcpus", maxcpus);

커널 파라메터 “maxcpus”로 입력 받은 값을 setup_max_cpus에 대입한다.

  • 만일 0이 입력되면 smp 기능이 동작하지 않게 한다.
    • 현재 0 값의 허용은 x86 시스템에만 구현되어 있다.
  • 예) “maxcpus=2”

 


싱글 비트 설정된 cpumask

get_cpu_mask()

include/linux/cpumask.h

static inline const struct cpumask *get_cpu_mask(unsigned int cpu)
{
        const unsigned long *p = cpu_bit_bitmap[1 + cpu % BITS_PER_LONG];
        p -= cpu / BITS_PER_LONG;
        return to_cpumask(p);
}

@cpu에 해당하는 싱글비트 설정된 cpumask 비트맵을 반환한다.

  • NR_CPUS가 어떤 값이든 요청 cpu에 대해 싱글 비트가 설정된 cpumask를 만들어내기위해 컴파일 타임에 특수한 형태의 static 배열 cpu_bit_bimap[][]을 만든다.
  • 예) NR_CPUS=192일 때,각 cpu에 대해 반환되는 cpumask는
    • get_cpu_mask(0) = 0x0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000
    • get_cpu_mask(1) = 0x0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0001
    • get_cpu_mask(4) = 0x0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0008
    • get_cpu_mask(65) = 0x0000_0000_0000_0000_0000_0000_0000_0001_0000_0000_0000_0000
    • get_cpu_mask(99) = 0x0000_0000_0000_0000_0000_0001_0000_0000_0000_0000_0000_0000
    • get_cpu_mask(129) = 0x0000_0000_0000_0001_0000_0000_0000_0000_0000_0000_0000_0000
    • get_cpu_mask(192) = 0x8000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000

 

cpu_bit_bitmap 배열

kernel/cpu.c

/*
 * Special-case data structure for "single bit set only" constant CPU masks.
 *
 * We pre-generate all the 64 (or 32) possible bit positions, with enough
 * padding to the left and the right, and return the constant pointer
 * appropriately offset.
 */
const unsigned long cpu_bit_bitmap[BITS_PER_LONG+1][BITS_TO_LONGS(NR_CPUS)] = {

        MASK_DECLARE_8(0),      MASK_DECLARE_8(8),
        MASK_DECLARE_8(16),     MASK_DECLARE_8(24),
#if BITS_PER_LONG > 32
        MASK_DECLARE_8(32),     MASK_DECLARE_8(40),
        MASK_DECLARE_8(48),     MASK_DECLARE_8(56),
#endif
};
EXPORT_SYMBOL_GPL(cpu_bit_bitmap);

get_cpu_mask() 함수에서 사용하기 위한 특수한 형태의 싱글 비트 설정된 cpumask를 컴파일 타임에 준비한다.

예) NR_CPUS=192인 경우 long 값이 64비트를 처리할 수 있으므로, 192개의 cpu를 처리하려면 3개의 배열을 사용해야 한다.

  • cpu_bit_bitmap[64+1][3] ={
    • {0x0, 0x0, 0x0},
    • {0x1, 0x0, 0x0},
    • {0x4, 0x0, 0x0},
    • {0x8, 0x0, 0x0},
    • {0x10, 0x0, 0x0},
    • {0x20, 0x0, 0x0},
    • {0x40, 0x0, 0x0},
    • {0x80, 0x0, 0x0},
    • {0x100, 0x0, 0x0},
    • {0x200, 0x0, 0x0},
    • {0x400, 0x0, 0x0},
    • {0x800, 0x0, 0x0},
    • {0x1000, 0x0, 0x0},
    • {0x2000, 0x0, 0x0},
    • {0x4000, 0x0, 0x0},
    • {0x8000, 0x0, 0x0},
    • {0x8000_0000_0000_0000, 0x0, 0x0}

 

unsigned logn cpu_bit_bitmap[NR_CPUS+1];과 같은 형태로 선언하고 배열내의 각 cpumask 값을 런타임에 준비할 수도 있지만, NR_CPUS 값이 클 때 메모리가 많이 낭비되며, 런타임에 별도의 초기화를 수행해야 하는 단점이 있다. 따라서 이 루틴을 설계한 개발자는 특수한 형태의 배열을 컴파일 타임에 준비해두고 이를 교묘하게 활용하여 get_cpu_mask() 함수를 통해 요청한 cpu에 대한 싱글 비트가 설정된 값을 담은 cpumask를 반환할 수 있게 설계하였다.

 

NR_CPUS=192일 때 little 엔디안 cpu을 사용하는 시스템에서 cpu_bit_bitmap을 덤프하면 다음과 같다.

  • cpu=5일 때 오렌지색에 해당하는 cpumask를 반환한다.
    • =0x10
  • cpu=73일 때 파란색에 해당하는 cpumask를 반환한다.(unsigned long 단위를 cpu/64만큼 뒤로 이동한 포인터를 반환한다.)
    • =0x1_00_0000_0000_0000_0000
  • cpu=192일 때 초록색에 해당하는 cpumask를 반환한다.
    • =0x80_0000_0000_0000_0000_0000_0000_0000_0000
0x00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 : cpu_bit_bitmap[0]
0x01 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 : cpu_bit_bitmap[1]
0x02 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 : cpu_bit_bitmap[2]
0x04 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 : cpu_bit_bitmap[3]
0x08 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 : cpu_bit_bitmap[4]
0x10 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 : cpu_bit_bitmap[5]
0x20 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 : cpu_bit_bitmap[6]
0x40 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 : cpu_bit_bitmap[7]  
0x80 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 : cpu_bit_bitmap[8]  
0x00 01 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 : cpu_bit_bitmap[9]  
0x00 02 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 : cpu_bit_bitmap[10]  
0x00 04 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 : cpu_bit_bitmap[11]  
0x00 08 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 : cpu_bit_bitmap[12]  
0x00 10 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 : cpu_bit_bitmap[13]  
0x00 20 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 : cpu_bit_bitmap[14]  
0x00 40 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 : cpu_bit_bitmap[15]  
0x00 80 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 : cpu_bit_bitmap[16]
(...생략...)
0x00 00 00 00 00 00 00 40 - 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 : cpu_bit_bitmap[63]
0x00 00 00 00 00 00 00 80 - 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 : cpu_bit_bitmap[64]

 

NR_CPUS=192일 때 big 엔디안 cpu를 사용하는 시스템에서 cpu_bit_bitmap을 덤프하면 다음과 같다.

  • cpu=5일 때 오렌지색에 해당하는 cpumask를 반환한다.
    • =0x10
  • cpu=73일 때 파란색에 해당하는 cpumask를 반환한다.
    • =0x1_00_0000_0000_0000_0000
  • cpu=192일 때 초록색에 해당하는 cpumask를 반환한다.
    • =0x80_0000_0000_0000_0000_0000_0000_0000_0000
0x00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 : cpu_bit_bitmap[0]
0x00 00 00 00 00 00 00 01 - 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 : cpu_bit_bitmap[1] 
0x00 00 00 00 00 00 00 02 - 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 : cpu_bit_bitmap[2] 
0x00 00 00 00 00 00 00 04 - 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 : cpu_bit_bitmap[3] 
0x00 00 00 00 00 00 00 08 - 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 : cpu_bit_bitmap[4] 
0x00 00 00 00 00 00 00 10 - 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 : cpu_bit_bitmap[5] 
0x00 00 00 00 00 00 00 20 - 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 : cpu_bit_bitmap[6] 
0x00 00 00 00 00 00 00 40 - 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 : cpu_bit_bitmap[7] 
0x00 00 00 00 00 00 00 80 - 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 : cpu_bit_bitmap[8] 
0x00 00 00 00 00 00 01 00 - 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 : cpu_bit_bitmap[9] 
0x00 00 00 00 00 00 02 00 - 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 : cpu_bit_bitmap[10] 
0x00 00 00 00 00 00 04 00 - 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 : cpu_bit_bitmap[11] 
0x00 00 00 00 00 00 08 00 - 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 : cpu_bit_bitmap[12] 
0x00 00 00 00 00 00 10 00 - 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 : cpu_bit_bitmap[13] 
0x00 00 00 00 00 00 20 00 - 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 : cpu_bit_bitmap[14] 
0x00 00 00 00 00 00 40 00 - 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 : cpu_bit_bitmap[15] 
0x00 00 00 00 00 00 80 00 - 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 : cpu_bit_bitmap[16] 
(...생략...)
0x40 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 : cpu_bit_bitmap[63]
0x80 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 : cpu_bit_bitmap[64]

 

MASK_DECLARE_x 매크로

kernel/cpu.c

/*
 * cpu_bit_bitmap[] is a special, "compressed" data structure that
 * represents all NR_CPUS bits binary values of 1<<nr.
 *
 * It is used by cpumask_of() to get a constant address to a CPU
 * mask value that has a single bit set only.
 */

/* cpu_bit_bitmap[0] is empty - so we can back into it */
#define MASK_DECLARE_1(x)       [x+1][0] = (1UL << (x))
#define MASK_DECLARE_2(x)       MASK_DECLARE_1(x), MASK_DECLARE_1(x+1)
#define MASK_DECLARE_4(x)       MASK_DECLARE_2(x), MASK_DECLARE_2(x+2)
#define MASK_DECLARE_8(x)       MASK_DECLARE_4(x), MASK_DECLARE_4(x+4)

MASK_DECLARE_8(x)은 다음과 같이 변화한다.

  • [x+1][0] = 1UL << x,
  • [x+1+1][0] = 1UL << x+1,
  • [x+2+1][0] = 1UL << x+2,
  • [x+3+1][0] = 1UL << x+3,
  • [x+4+1][0] = 1UL << x+4,
  • [x+5+1][0] = 1UL << x+5,
  • [x+6+1][0] = 1UL << x+6,
  • [x+7+1][0] = 1UL << x+7,

 

참고

댓글 남기기