通常のグローバル変数はCPUごとではありません。自動変数はスタック上にあり、異なるCPUは異なるスタックを使用するため、自然に別々の変数が得られます。
LinuxのCPU単位の可変インフラストラクチャを指していると思います。
魔法のほとんどは、ここで(asm-generic/percpu.h
)である:
extern unsigned long __per_cpu_offset[NR_CPUS];
#define per_cpu_offset(x) (__per_cpu_offset[x])
/* Separate out the type, so (int[3], foo) works. */
#define DEFINE_PER_CPU(type, name) \
__attribute__((__section__(".data.percpu"))) __typeof__(type) per_cpu__##name
/* var is in discarded region: offset to particular copy we want */
#define per_cpu(var, cpu) (*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset[cpu]))
#define __get_cpu_var(var) per_cpu(var, smp_processor_id())
マクロRELOC_HIDE(ptr, offset)
は、単に与えられた(かかわらず、ポインタ型の)バイトオフセットによってptr
を進めます。
どうしますか?
DEFINE_PER_CPU(int, x)
を定義する、整数__per_cpu_x
は特別.data.percpu
セクションで作成されています。
- カーネルがロードされると、このセクションは複数回ロードされます - CPUごとに1回(この部分は上記のコードにはありません)。
__per_cpu_offset
アレイは、コピー間の距離で埋められます。 1000バイトのCPUデータが使用されているとすると、__per_cpu_offset[n]
には1000*n
が含まれます。
- シンボル
per_cpu__x
は、ロード時にCPU0のper_cpu__x
に再配置されます。
__get_cpu_var(x)
は、CPU 3で動作している場合、*RELOC_HIDE(&per_cpu__x, __per_cpu_offset[3])
に変換されます。これはCPU0のx
で始まり、CPU0のデータとCPU3の間にオフセットを追加し、最終的に結果のポインタを逆参照します。
あなたのansserに感謝します。でも、私はまだsmpに新しい質問がありますので、あなたのアイデアには嫌です。まず、私は同じプロセスが同じスタックを持つべきだと考えました、ここでPOSIXのスレッド定義 "...と自動変数は、同じプロセス内のすべてのスレッドにアクセス可能です。"自動変数はスレッドによって共有されます。異なるプロセッサは異なるスタックセグメントレジスタを有するかもしれないが、内容は同じでなければならない。第二に、percpuで得られたオフセットをロールバックするだけで他のCPUの変数にアクセスすることもできますか? – dspjm
2つのスレッドが自動変数 'x'を持つ' foo'関数を呼び出すとき、スタックは2つと 'x'の2つのインスタンスがあります。それぞれが異なるアドレスを持ち、両方のスレッドがアドレスを持っていれば両方のスレッドにアクセスできます。 Linuxのper-cpu変数を使うと、 'per_cpu(var、cpu)'は任意のCPUの変数にアクセスすることができます。 – ugoren
.data.percpuセクションは、percpu変数がスタックまたはヒープ上で宣言されているかどうかをどのように決定しますか? – user31986