如何在Linux内核中实现percpu指针?
在多处理器上,每个核心可以有自己的变量。我认为它们在不同的地址中是不同的变量,尽管它们在相同的过程中,并且具有相同的名称如何在Linux内核中实现percpu指针?,linux,linux-kernel,smp,Linux,Linux Kernel,Smp,在多处理器上,每个核心可以有自己的变量。我认为它们在不同的地址中是不同的变量,尽管它们在相同的过程中,并且具有相同的名称 但我想知道,内核是如何实现这一点的?它是否分配了一块内存来存放所有的percpu指针,并且每次它都使用shift或其他方法将指针重定向到某个地址?正常的全局变量不是每个CPU的。自动变量在堆栈上,不同的CPU使用不同的堆栈,因此它们自然会得到单独的变量 我猜您指的是Linux的每CPU可变基础架构。 这里有很多神奇之处(asm generic/percpu.h): 宏RELO
但我想知道,内核是如何实现这一点的?它是否分配了一块内存来存放所有的percpu指针,并且每次它都使用shift或其他方法将指针重定向到某个地址?正常的全局变量不是每个CPU的。自动变量在堆栈上,不同的CPU使用不同的堆栈,因此它们自然会得到单独的变量 我猜您指的是Linux的每CPU可变基础架构。
这里有很多神奇之处(
asm generic/percpu.h
):
宏RELOC\u HIDE(ptr,offset)
只需按给定的偏移量(以字节为单位)前进ptr
(不考虑指针类型)
它有什么作用
DEFINE_PER_CPU(int,x)
时,在特殊.data.perpu
部分中创建一个整数\u PER_CPU_x
\u
数组由拷贝之间的距离填充。假设使用1000字节的每cpu数据,\u每cpu\u偏移量[n]
将包含1000*n
每\u cpu\uuuuux
将重新定位到cpu 0的每\u cpu\uuuux
\uu get\u cpu\u var(x)
将转换为*RELOC\u HIDE(&per\u cpu\uux,\uu per\u cpu\u offset[3])
。这从CPU 0的x
开始,添加CPU 0的数据和CPU 3的数据之间的偏移量,并最终取消对结果指针的引用谢谢你的回答,但我还有一些问题,是smp的新手,所以,不要冒犯你的想法。首先,我认为同一个进程应该有相同的堆栈,这里是POSIX中的线程定义“…和自动变量,对同一进程中的所有线程都是可访问的。”。自动变量由线程共享。不同的处理器可能有不同的堆栈段寄存器,但内容应该相同。第二,我们是否可以说,如果需要,我们也可以访问其他cpu的变量,只需回滚percpu获得的偏移量?当两个线程调用函数
foo
,该函数有一个自动变量x
,有两个堆栈和两个x
实例。每个线程都有一个不同的地址,如果两个线程都有地址,那么它们都可以访问这两个线程。使用Linux的每cpu变量,每cpu(var,cpu)
允许您访问任何cpu的变量。data.percpu部分如何确定percpu变量是在堆栈还是堆上声明的?在加载过程中,每个cpu都有自己的GDT表。此gdt表中的每个条目都表示可以从此CPU上的线程访问的内存段。GDT表项0存储每个cpu内存的内存段。为了访问每cpu内存,linux使用gs:{variable offset}访问每cpu变量,如下所示:mov%gs:0x41(%rcx),%dlI一直在研究代码。自从这个答案被写出来后,情况似乎有了一些变化DEFINE_PER_CPU(int,x)
定义一个名为x
的符号,而不是PER_CPU(int,x)
。加载内核时,不是将x
重新定位到CPU 0的副本上,\u per\u CPU\u offset[0]
保留链接器分配给x
的地址与实际存储CPU 0副本的地址之间的差异。另外:x86内核不总是访问每个cpu的偏移量,而是将该偏移量存储为段fs
的基。然后,在段fs
中取消对指针的引用将直接指向当前CPU的副本!
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())