当前位置: 首页 > 面试题库 >

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

丁鹏鹍
2023-03-14
问题内容

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

但是我想知道,内核如何实现呢?它是否分配了一块内存来存放所有的percpu指针,并且每次它通过shift或其他方式将指针重定向到某个地址时?


问题答案:

普通全局变量不是每个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)仅以ptr字节为单位偏移给定的偏移量(无论指针类型如何)。

它有什么作用?

  1. 定义时DEFINE_PER_CPU(int, x),将__per_cpu_x在特殊.data.percpu部分中创建一个整数。
  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的数据之间增加偏移量,最后取消对结果指针的引用。


 类似资料:
  • 问题内容: 所有, 下面的代码来自“ Unix环境中的高级编程”,它创建一个新线程,并打印主线程和新线程的进程ID和线程ID。 在书中,它表示在linux中,此代码的输出将显示两个线程具有不同的进程ID,因为pthread使用轻量级进程来模拟线程。但是,当我在Ubuntu 12.04中运行此代码时,它具有内核3.2,并打印了相同的pid。 那么,新的Linux内核是否会更改pthread的内部实现

  • 问题内容: 我试图了解链表和哈希表的Linux内核实现。实现的链接在这里。我了解链表的实现。但是我对为什么在hlist(* pprev)中使用双指针感到困惑。hlist的链接在这里。我知道hlist用于实现哈希表,因为列表的头仅需要一个指针,并且可以节省空间。为什么不能使用单个指针(就像链接列表一样 prev)来完成?请帮我。 问题答案: 原因可以在以下注释之一中找到: 如果您使用的是 prev而

  • 问题内容: 我正在尝试为x86目标构建rootfs,这已经足够简单了。但是我不知道如何配置buildroot产生的内核。第一次运行是由menuconfig提出的,但此后一直缓存.config,我看不到在哪里进行更改。 约650MB的内核模块对嵌入式目标没有好处:P 有没有一种简单的方法可以在buildroot中配置内核?诸如目标之类的东西将是完美的。 问题答案: 答案是:

  • 问题内容: 我有一个简单的字符设备驱动程序,可让您从自定义硬件设备中读取。它使用DMA将数据从设备内存复制到内核空间(然后由用户决定)。 该调用非常简单。它开始DMA写操作,然后在等待队列中等待。DMA完成后,中断处理程序将设置一个标志并唤醒等待队列。需要注意的重要一点是, 即使在设备要提供数据之前 ,我也可以随时启动DMA 。DMA引擎将坐下等待,直到有要复制的数据为止。这很好。我可以在用户空间

  • 问题内容: 该功能在内部如何工作?考虑到内核确实具有访问用户内存空间的特权,它是否使用任何缓冲区还是完成了任何内存映射? 问题答案: 的实现高度依赖于体系结构。 在x86和x86-64上,它只是直接从用户空间地址进行读取并写入内核空间地址,同时如果已配置,则暂时禁用SMAP(超级用户模式访问阻止)。它的棘手部分是将代码放置在特殊区域中,以便页面错误处理程序可以识别其中何时发生错误。发生的内存保护错

  • 问题内容: Linux内核开发人员如何在提交代码后在本地测试他们的代码?他们是否使用某种单元测试,构建自动化?测试计划? 问题答案: linux内核非常重视社区测试。 通常,任何开发人员都会在提交之前测试他们自己的代码,并且经常会使用Linus的内核开发版本,或者与他们的工作相关的项目使用其他不稳定/开发树之一。这意味着他们经常同时测试自己的变更和其他人的变更。 正式的测试计划的方式往往不多,但是