18

マルチプロセッサでは、各コアが独自の変数を持つことができます。それらは同じプロセスにあり、同じ名前を持っていますが、異なるアドレスの異なる変数だと思いました。

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

4

1 に答える 1

27

通常のグローバル変数は 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配列は、コピー間の距離で埋められます。CPU あたり 1000 バイトのデータが使用されると仮定__per_cpu_offset[n]すると、1000*n.
  4. シンボルper_cpu__xは、ロード中に CPU 0 に再配置されますper_cpu__x
  5. __get_cpu_var(x)、CPU 3 で実行している場合は、 に変換され*RELOC_HIDE(&per_cpu__x, __per_cpu_offset[3])ます。これは、CPU 0 から始まり、CPU x0 のデータと CPU 3 の間のオフセットを追加し、最終的に結果のポインターを逆参照します。
于 2013-06-09T14:48:28.060 に答える