SMP 引起的竞态
不能解决 其他原因 引起的竞态
在 CONFIG_SMP 下才有意义, 不配置 CONFIG_SMP 也能用,但是就失去了他的意义(作用,)
在某些体系结构上,per-CPU变量可使用的地址空间是受限的,要尽量保持这些变量比较小
per-cpu 并没有利用 同步原语 和 屏障,因为 per-cpu的实现 是 避开了SMP的竞态
https:
https:
应用场景及API
per-cpu 机制 解决了 三个情景下的 per-cpu 变量
1. 内核静态percpu变量
2. 模块静态percpu变量
3. 动态percpu变量
per-cpu 机制 针对 三个情景 提供了 几种初始化,几种api
A. per-cpu机制的初始化 setup_per_cpu_areas
B1. 内核静态percpu变量的定义 DEFINE_PER_CPU(type, name)
B2. 模块静态percpu变量的定义 DEFINE_PER_CPU(type, name)
B3. 动态percpu变量的定义 alloc_percpu(type)
C. percpu变量地址的获取 this_cpu_ptr(var)
D. percpu变量的获取 per_cpu(var,cpu)
per-cpu变量 内存相关
给每一个cpu分配了一块内存pcpu_area(xKB)每个cpu的xKB内存都是连续的(同group的才连续).
N个cpu对应的内存大小是 N*x
一个xKB内存分块 分为 static reserved dynamic
每个cpu对应的内存块 大小是怎么决定的
从 pcpu_base_addr 开始的 N*x大小的 空间是什么时候申请的
- per-cpu变量 相关内存的管理方法(pcpu_slot)
一个xKB内存分块 分为 static reserved dynamic
reserved dynamic 被 chunk 管理 ,而 static 没有用 chunk 管理
per-cpu 有一个内存代理商 pcpu_slot , 管理了 这些 reserved dynamic
pcpu_slot 也是像 buddy 一样(利用order)管理内存的
pcpu_slot 是 从 buddy 和 memblock 申请的内存,申请的内存通过pcpu_chunk_relocate 加入 per-cpu
其中一个内存块 pcpu_first_chunk 是 从 memblock 申请的
其他的内存 都是从buddy申请的
pcpu_slot 的消费者
per-cpu 创建per-cpu变量的时候,会用到内存,则会从 pcpu_slot 申请
只供 动态percpu变量 使用 alloc_percpu 申请
模块静态percpu变量 也会使用
per-cpu变量的存放与获取
percpu变量的存放
内核静态percpu变量 被 复制到 每个cpu的内存块的static区域,static 不可扩展(不存在空间不够的情况)
模块静态percpu变量 被 复制到 每个cpu的内存块的reserved区域,空间不够,reserved 可扩展
动态percpu变量 被 放在 每个cpu的内存块的dynamic 区域,空间不够,dynamic 可扩展
percpu变量的获取
percpu变量存放后 给出一个 值 ptr,通过this_cpu_ptr(即ptr + delta + pcpu_unit_offsets[cpu]) 获取 percpu变量的 实际地址
针对 内核静态percpu变量 : ptr 的值 位于 __per_cpu_start __per_cpu_end 之间
针对 模块静态percpu变量 : ptr 的值 为 chunk->base_addr + off - delta
针对 动态percpu变量 : ptr 的值 为 chunk->base_addr + off - delta
其他
setup_per_cpu_areas
pcpu_embed_first_chunk
pcpu_build_alloc_info
ptr = memblock_virt_alloc_nopanic(PFN_ALIGN(ai_size), 0)
areas = memblock_virt_alloc_nopanic(areas_size, 0);
ptr = alloc_fn(cpu, gi->nr_units * ai->unit_size, atom_size);/pcpu_dfl_fc_alloc
memblock_virt_alloc_from_nopanic
pcpu_setup_first_chunk
group_offsets = memblock_virt_alloc
group_sizes = memblock_virt_alloc
unit_map = memblock_virt_alloc
unit_off = memblock_virt_alloc
pcpu_slot = memblock_virt_alloc(
schunk = memblock_virt_alloc
dchunk = memblock_virt_alloc