Linux内核中percpu指针是如何实现的? [英] How are percpu pointers implemented in the Linux kernel?

查看:21
本文介绍了Linux内核中percpu指针是如何实现的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在多处理器上,每个内核都可以有自己的变量.我以为它们是不同地址的不同变量,虽然它们在同一个进程中并且具有相同的名称.

On multiprocessor, each core can have its own variables. I thought they are different variables in different addresses, although they are in same process and have the same name.

但我想知道,内核是如何实现这一点的?它是否分配了一块内存来存放所有的percpu指针,并且每次将指针重定向到某个地址时使用shift什么的?

But I am wondering, how does the kernel implement this? Does it dispense a piece of memory to deposit all the percpu pointers, and every time it redirects the pointer to certain address with shift or something?

推荐答案

普通全局变量不是每个 CPU.自动变量是在栈上的,不同的CPU使用不同的栈,自然得到不同的变量.

Normal global variables are not per CPU. Automatic variables are on the stack, and different CPUs use different stack, so naturally they get separate variables.

我猜你指的是 Linux 的每 CPU 可变基础架构.
大部分魔法都在这里(asm-generic/percpu.h):

I guess you're referring to Linux's per-CPU variable infrastructure.
Most of the magic is here (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) 只是将 ptr 向前推进给定的字节偏移量(无论指针类型如何).

The macro RELOC_HIDE(ptr, offset) simply advances ptr by the given offset in bytes (regardless of the pointer type).

它有什么作用?

  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. __get_cpu_var(x),在 CPU 3 上运行时,将转换为 *RELOC_HIDE(&per_cpu__x, __per_cpu_offset[3]).这从 CPU 0 的 x 开始,添加 CPU 0 的数据和 CPU 3 的数据之间的偏移量,并最终取消引用结果指针.
  1. When defining DEFINE_PER_CPU(int, x), an integer __per_cpu_x is created in the special .data.percpu section.
  2. When the kernel is loaded, this section is loaded multiple times - once per CPU (this part of the magic isn't in the code above).
  3. The __per_cpu_offset array is filled with the distances between the copies. Supposing 1000 bytes of per cpu data are used, __per_cpu_offset[n] would contain 1000*n.
  4. The symbol per_cpu__x will be relocated, during load, to CPU 0's per_cpu__x.
  5. __get_cpu_var(x), when running on CPU 3, will translate to *RELOC_HIDE(&per_cpu__x, __per_cpu_offset[3]). This starts with CPU 0's x, adds the offset between CPU 0's data and CPU 3's, and eventually dereferences the resulting pointer.

这篇关于Linux内核中percpu指针是如何实现的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆