在多处理器上,每个核心可以有自己的variables。 我以为它们是不同地址的不同variables,尽pipe它们处于相同的过程中并且具有相同的名称。
但是我想知道,内核是如何实现这个的? 它是否分配一块内存来存放所有percpu指针,并且每当它将指针redirect到某个地址时,都会发生移位或什么?
正常的全局变量不是每个CPU。 自动变量位于堆栈上,不同的CPU使用不同的堆栈,所以自然会得到不同的变量。
我想你是指Linux的每个CPU可变基础设施。
大部分的魔法在这里( asm-generic/percpu.h
):
extern unsigned long __per_cpu_offset[NR_CPUS]; #define per_cpu_offset(x) (__per_cpu_offset[x]) /* Separate out the type, so (int[3], foo) works. */ #define DEFINE_PER_CPU(type, name) \ __attribute__((__section__(".data.percpu"))) __typeof__(type) per_cpu__##name /* var is in discarded region: offset to particular copy we want */ #define per_cpu(var, cpu) (*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset[cpu])) #define __get_cpu_var(var) per_cpu(var, smp_processor_id())
宏RELOC_HIDE(ptr, offset)
简单地按照给定的字节偏移量(不管指针类型如何RELOC_HIDE(ptr, offset)
将ptr
前进。
它有什么作用?
DEFINE_PER_CPU(int, x)
,会在特殊的.data.percpu
节中创建一个整数__per_cpu_x
。 __per_cpu_offset
数组填充了副本之间的距离。 假设使用每个cpu数据1000个字节, __per_cpu_offset[n]
将包含1000*n
。 per_cpu__x
将在加载期间重新定位到CPU 0的per_cpu__x
。 __get_cpu_var(x)
将转换为*RELOC_HIDE(&per_cpu__x, __per_cpu_offset[3])
。 这从CPU 0的x
,加上CPU 0的数据和CPU 3之间的偏移,并最终取消引用结果指针。