CPU変数
CPU変数は、DEFINE_PER_CPUマクロで、通常静的変数のセクションと異なる.data..percpuセクションに設定されます。__per_cpu_offset[]にCPU変数セクションの.data..percpuからのCPUに掛かる参照オフセットが設定され、CPU毎の変数は、CPU変数アドレス+__per_cpu_offset[CPU ID]のアドレスをCPUの変数となります。
サンプルは、カレントCPUのbabakaka1をインクリメントし、CPU IDの0/1でのCPU変数を検証するもので、カーネルマクロによるものと、そのマクロに元ずく実装によるものです。
DEFINE_PER_CPU(type, name)マクロは__attribute__((section(.data..percp))) のtype型のname変数で宣言されます。
サンプルは、カレントCPUのbabakaka1をインクリメントし、CPU IDの0/1でのCPU変数を検証するもので、カーネルマクロによるものと、そのマクロに元ずく実装によるものです。
#include <linux/kmod.h>
static DEFINE_PER_CPU(int, babakaka1) = 1;
static DEFINE_PER_CPU(int, babakaka2) = 1;
static int babakaka_init (void)
{
int *addr1, *addr2;
printk("add 1 babakaka1 on cpu%d\n", get_cpu());
percpu_add(babakaka1, 1);
printk("cpu0 babakaka1:%d babakaka2:%d\n", per_cpu(babakaka1, 0), per_cpu(babakaka2, 0));
printk("cpu1 babakaka1:%d babakaka2:%d\n", per_cpu(babakaka1, 1), per_cpu(babakaka2, 1));
printk("-------\n");
printk("cpu0 off:%lx cpu1 off:%lx\n", __per_cpu_offset[0], __per_cpu_offset[1]);
addr1 = (int *)((unsigned long)&babakaka1 + (unsigned long)__per_cpu_offset[0]);
addr2 = (int *)((unsigned long)&babakaka2 + (unsigned long)__per_cpu_offset[0]);
printk("cpu0 babakaka1:%d babakaka2:%d\n", *addr1, *addr2);
addr1 = (int *)((unsigned long)&babakaka1 + (unsigned long)__per_cpu_offset[1]);
addr2 = (int *)((unsigned long)&babakaka2 + (unsigned long)__per_cpu_offset[1]);
printk("cpu1 babakaka1:%d babakaka2:%d\n", *addr1, *addr2);
return -1;
}
module_init(babakaka_init);
カレントCPU IDは1で、従ってCPU ID=1のbabakaka1=2となりますが、CPU ID=0のbabakaka1=1です。[root@localhost lkm]# insmod cpuval.ko [root@localhost lkm]# dmesg -c : [ 1654.995045] add 1 babakaka1 on cpu1 [ 1654.995056] cpu0 babakaka1:1 babakaka2:1 [ 1654.995063] cpu1 babakaka1:2 babakaka2:1 [ 1654.995069] ------- [ 1654.995075] cpu0 off:1f397000 cpu1 off:1f3a4000 [ 1654.995081] cpu0 babakaka1:1 babakaka2:1 [ 1654.995087] cpu1 babakaka1:2 babakaka2:1
補足
実装可能なCPU数は、セクションサイズとCPU毎の必要とする変数サイズに依存し、また実装は、CPUに依存し、ここではX32での検証です。DEFINE_PER_CPU(type, name)マクロは__attribute__((section(.data..percp))) のtype型のname変数で宣言されます。
#ifndef PER_CPU_DEF_ATTRIBUTES
#define PER_CPU_DEF_ATTRIBUTES
#endif
#define DEFINE_PER_CPU(type, name) \
DEFINE_PER_CPU_SECTION(type, name, "")
#define DEFINE_PER_CPU_SECTION(type, name, sec) \
__PCPU_ATTRS(sec) PER_CPU_DEF_ATTRIBUTES \
__typeof__(type) name
#define __PCPU_ATTRS(sec) \
__percpu __attribute__((section(PER_CPU_BASE_SECTION sec)))
#define PER_CPU_BASE_SECTION ".data..percpu"






