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"