一、看内核源码时,有很多在访问per_cpu变量时,会有很多for_each_online_cpu ,下面介绍一下区别
假设一太机器上有8个CPU:
1.1 for_each_possible_cpu
机器上最多有多少个CPU,包括本机的CPU,以及可以热插拔的CPU。
1. 假设最多可以插CPU为10,本机CPU个数为8个,则最多可以再添加2个可插拔CPU。
1.2 for_each_present_cpu
当前有多少个CPU。
1. 本机CPU个数为8个,都是online的,则cpu_present_map为8;
2. 再插入1个可插拔CPU,则cpu_present_map为9。
1.3 for_each_online_cpu
在当前的CPU中,有多少个可用的CPU。
1. 本机CPU个数为8个,都是online的,则for_each_online_cpu 为8;
2. 将其中一个设置为offline,则for_each_online_cpu变为7
内核源码:include/linux/cpumask.h
#define for_each_possible_cpu(cpu) for_each_cpu((cpu), cpu_possible_mask)
#define for_each_online_cpu(cpu) for_each_cpu((cpu), cpu_online_mask)
#define for_each_present_cpu(cpu) for_each_cpu((cpu), cpu_present_mask)
for_each_cpu
/**
* 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;)
二、介绍per_cpu() 接口
for_each_possible_cpu(cpu) {
for_each_cpu_worker_pool(pool, cpu) {
pool->node = cpu_to_node(cpu);
}
}
for_each_cpu_worker_pool(pool, cpu)
#define for_each_cpu_worker_pool(pool, cpu) \
for ((pool) = &per_cpu(cpu_worker_pools, cpu)[0]; \
(pool) < &per_cpu(cpu_worker_pools, cpu)[NR_STD_WORKER_POOLS]; \
(pool)++)
per_cpu()
#define per_cpu(var, cpu) (*per_cpu_ptr(&(var), cpu))
per_cpu_ptr
#define per_cpu_ptr(ptr, cpu) \
({ \
__verify_pcpu_ptr(ptr); \
SHIFT_PERCPU_PTR((ptr), per_cpu_offset((cpu))); \
})
cpu_worker_pools 是定义的每cpu上工作者池组的变量名。
/* the per-cpu worker pools */
static DEFINE_PER_CPU_SHARED_ALIGNED(struct worker_pool [NR_STD_WORKER_POOLS], cpu_worker_pools);
从上面的代码看出, per_cpu(cpu_worker_pools, cpu),per_cpu 是获取指定的cpu per_cpu副本cpu_worker_pools变量的地址;(pool) = &per_cpu(cpu_worker_pools, cpu)[0],工作者池数组的第一个地址,再把地址付给pool 变量。
在解释深一层, cpu_worker_pools 这称之为源变量,DEFINE_PER_CPU_SHARED_ALIGNED 之后,为每个CPU声明一个源变量副本。在之后,通过per_cpu 获取每cpu 的变量副本,进行操作。