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의 수행이 완료될 때까지 기다린다.
- smp_call_function_many()
- cpu mask 중 현재 cpu를 제외한 cpu에서 func을 수행한다.
- 참고: IPI cross call – 소프트 인터럽트 | 문c
 
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,
참고
- Bit Operations | 문c
- Bitmap Operations | 문c
- IPI cross call – 소프트 인터럽트 | 문c