首页 > > > 第四章 第四节 per_cpu
我们上一章说了
实现内核同步的方法很多,如下表
技术
说明
适用范围
每CPU变量
在CPU之间复制数据结构
所有CPU
原子操作
对一个计数器原子地“读-修改-写”的指令
所有CPU
内存屏障
避免指令重新排序
本地CPU或所有CPU
自旋锁
加锁时忙等
所有CPU
信号量
加锁时阻塞等待
所有CPU
顺序锁
基于访问计数器的锁
所有CPU
本地中断的禁止
禁止单个CPU上的中断处理
本地CPU
本地软中断的禁止
禁止单个CPU上的可延迟函数处理
本地CPU
读-复制-更新(RCU)
通过指针而不是锁来访问共享数据结构
所有CPU
但是这个每CPU变量,让我看起来非常的拗口,什么是每CPU变量,我刚开始看的时候,以为别人写错了,后面又查了很多资料,确定是对的,才放心,原来是翻译的问题
优点
per_cpu的好处是访问它不需要加锁,而且这个变量存在CPU的cache里,访问速度会非常快
原英文是 per_cpu
/*
* Add a offset to a pointer but keep the pointer as is.
*
* Only S390 provides its own means of moving the pointer.
*/
#ifndef SHIFT_PERCPU_PTR
/* Weird cast keeps both GCC and sparse happy. */
#define SHIFT_PERCPU_PTR(__p, __offset) ({ \
__verify_pcpu_ptr((__p)); \
RELOC_HIDE((typeof(*(__p)) __kernel __force *)(__p), (__offset)); \
})
#endif
/*
* A percpu variable may point to a discarded regions. The following are
* established ways to produce a usable pointer from the percpu variable
* offset.
*/
#define per_cpu(var, cpu) \
(*SHIFT_PERCPU_PTR(&(var), per_cpu_offset(cpu)))
既然这么拗口,我觉得就没有必要翻译了,直接说明是per_cpu 就好了
怎么使用这个 per_cpu 呢?
在源码
drivers\cpufreq\cpufreq_userspace.c
下面有一个使用的历程
声明一个 per_cpu
static DEFINE_PER_CPU(unsigned int, cpu_is_managed);
#define DEFINE_PER_CPU(type, name) \
DEFINE_PER_CPU_SECTION(type, name, "")
使用一个per_cpu
get_cpu_var(var) 和 set_cpu_var(var)
使用另一个CPU的per_cpu变量
per_cpu(cpu_cur_freq, freq->cpu) = freq->new;
导出一个per_cpu 变量供其他模块使用
EXPORT_PER_CPU_SYMBOL(per_cpu_var);
EXPORT_PER_CPU_SYMBOL_GPL(per_cpu_var);
注意!!
在使用per_cpu的时候,记得禁止内核抢占
DECLARE_PER_CPU(int, mycounter);
● int cpu;
● preempt_disable(); //禁止抢占
● cpu = smp_processor_id();
● per_cpu(mycounter, cpu) += 1;
● preempt_enable(); //开启内核抢占
SMP系统chcae 命中
什么是smp 系统呢?就是有几个 CPU组成的芯片,就是我们通常说的几核几核的说法,大概的图像这样

per_cpu解决的是多个CPU上共享数据的问题,如果声明了一个变量A,这个变量A在每个CPU下都有自己的副本,使用的堆栈地址也不一样,但是如果改变了A的值,其他的CPU同样能获取这个改变的值。
这样的话每个CPU只要关心单个CPU的并发问题,不用考虑多CPU的互斥加锁并发问题。
声明和定义Per-CPU变量的API
描述
DECLARE_PER_CPU(type, name)
DEFINE_PER_CPU(type, name)
普通的、没有特殊要求的per cpu变量定义接口函数。没有对齐的要求
DECLARE_PER_CPU_FIRST(type, name)
DEFINE_PER_CPU_FIRST(type, name)
通过该API定义的per cpu变量位于整个per cpu相关section的最前面。
DECLARE_PER_CPU_SHARED_ALIGNED(type, name)
DEFINE_PER_CPU_SHARED_ALIGNED(type, name)
通过该API定义的per cpu变量在SMP的情况下会对齐到L1 cache line ,对于UP,不需要对齐到cachine line
DECLARE_PER_CPU_ALIGNED(type, name)
DEFINE_PER_CPU_ALIGNED(type, name)
无论SMP或者UP,都是需要对齐到L1 cache line
DECLARE_PER_CPU_PAGE_ALIGNED(type, name)
DEFINE_PER_CPU_PAGE_ALIGNED(type, name)
为定义page aligned per cpu变量而设定的API接口
DECLARE_PER_CPU_READ_MOSTLY(type, name)
DEFINE_PER_CPU_READ_MOSTLY(type, name)
通过该API定义的per cpu变量是read mostly
per_cpu 在内存中固定的section

参考资料:(公众号后台回复 per_cpu 获取)

推荐阅读:

原文作者:;如有侵权,请联系管理员删除。