在linux SMP环境中,某些变量在CPU同时时,并不需要进行互斥操作,为了支持这种功能,引入了percpu变量的概念。
这些变量在每个CPU上有一个副本,它们相互没有影响,但是它们拥有相同的类型和名字。这样在编码的时候,只需要变量名称就可以访问,但是可能访问的是不同的拷贝,这由当前程序运行在哪个CPU决定的。
在实际使用中,首先都要获取当前CPU上的值,然后在操作改变量。
1.1 API
1.1.1 定义
#define DEFINE_PER_CPU(type, name)
上面的宏定义了一个percpu变量,实际上定义了一个类型为type,名称为per_cpu__##name的变量,它实际存放的位置为:
u SMP:.data.percpu section
u 单CPU:.data
1.1.2 使用
(1) get_cpu_var(var)/ put_cpu_var(var)
当需要对某个percpu变量进行操作时,首先通过get_cpu_var(var)来获取当前cpu上的该变量的地址,并且同时preempt_disable,这样防止当前的执行体(进程、softirq等等)被切换到其它的CPU上。
当变量操作完毕,调用put_cpu_var(var),打开调度preempt_enable()。
(2) __get_cpu_var(var)
如果不需要关闭调度,可以直接使用该函数获取当前cpu上的该变量地址。
1.2 实现
在main.càstart_kernel()àsetup_per_cpu_areas()函数中,将会根据cpu的数目,将.data.percpu 段中的数据,拷贝到为每个CPU分配的内存区间中。并且设置__per_cpu_offset的值,这样对每个cpu上的变量的访问,直接由该变量per_cpu_xxxxxxx的地址加上该偏移值,就可以获取在某个cpu上该变量的地址。如下图所示。