2013-06-07 14 views
13

マルチプロセッサでは、各コアに独自の変数を設定できます。彼らは同じプロセスで同じ名前を持っていますが、彼らは異なったアドレスで異なる変数だと思いました。Linuxカーネルでpercpuポインタはどのように実装されていますか?

しかし、カーネルはこれをどのように実装しているのでしょうか?すべてのpercpuポインタをデポジットするためにメモリを分けていますか?また、ポインタをある種のアドレスにリダイレクトするたびに、

答えて

20

通常のグローバル変数は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を進めます。

どうしますか?

  1. DEFINE_PER_CPU(int, x)を定義する、整数__per_cpu_xは特別.data.percpuセクションで作成されています。
  2. カーネルがロードされると、このセクションは複数回ロードされます - CPUごとに1回(この部分は上記のコードにはありません)。
  3. __per_cpu_offsetアレイは、コピー間の距離で埋められます。 1000バイトのCPUデータが使用されているとすると、__per_cpu_offset[n]には1000*nが含まれます。
  4. シンボルper_cpu__xは、ロード時にCPU0のper_cpu__xに再配置されます。
  5. __get_cpu_var(x)は、CPU 3で動作している場合、*RELOC_HIDE(&per_cpu__x, __per_cpu_offset[3])に変換されます。これはCPU0のxで始まり、CPU0のデータとCPU3の間にオフセットを追加し、最終的に結果のポインタを逆参照します。
+0

あなたのansserに感謝します。でも、私はまだsmpに新しい質問がありますので、あなたのアイデアには嫌です。まず、私は同じプロセスが同じスタックを持つべきだと考えました、ここでPOSIXのスレッド定義 "...と自動変数は、同じプロセス内のすべてのスレッドにアクセス可能です。"自動変数はスレッドによって共有されます。異なるプロセッサは異なるスタックセグメントレジスタを有するかもしれないが、内容は同じでなければならない。第二に、percpuで得られたオフセットをロールバックするだけで他のCPUの変数にアクセスすることもできますか? – dspjm

+0

2つのスレッドが自動変数 'x'を持つ' foo'関数を呼び出すとき、スタックは2つと 'x'の2つのインスタンスがあります。それぞれが異なるアドレスを持ち、両方のスレッドがアドレスを持っていれば両方のスレッドにアクセスできます。 Linuxのper-cpu変数を使うと、 'per_cpu(var、cpu)'は任意のCPUの変数にアクセスすることができます。 – ugoren

+0

.data.percpuセクションは、percpu変数がスタックまたはヒープ上で宣言されているかどうかをどのように決定しますか? – user31986

関連する問題