percpu指针如何在Linux内核中实现?

在多处理器上,每个核心可以有自己的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前进。

它有什么作用?

  1. 定义DEFINE_PER_CPU(int, x) ,会在特殊的.data.percpu节中创建一个整数__per_cpu_x
  2. 当内核加载时,这个部分被加载多次 – 每个CPU一次(这部分的魔法不在上面的代码中)。
  3. __per_cpu_offset数组填充了副本之间的距离。 假设使用每个cpu数据1000个字节, __per_cpu_offset[n]将包含1000*n
  4. 符号per_cpu__x将在加载期间重新定位到CPU 0的per_cpu__x
  5. 在CPU 3上运行时, __get_cpu_var(x)将转换为*RELOC_HIDE(&per_cpu__x, __per_cpu_offset[3]) 。 这从CPU 0的x ,加上CPU 0的数据和CPU 3之间的偏移,并最终取消引用结果指针。