マルチプロセッサでは、各コアが独自の変数を持つことができます。それらは同じプロセスにあり、同じ名前を持っていますが、異なるアドレスの異なる変数だと思いました。
しかし、カーネルはこれをどのように実装しているのでしょうか? すべてのpercpuポインターをデポジットするためにメモリの一部を分配し、シフトなどでポインターを特定のアドレスにリダイレクトするたびに?
マルチプロセッサでは、各コアが独自の変数を持つことができます。それらは同じプロセスにあり、同じ名前を持っていますが、異なるアドレスの異なる変数だと思いました。
しかし、カーネルはこれをどのように実装しているのでしょうか? すべてのpercpuポインターをデポジットするためにメモリの一部を分配し、シフトなどでポインターを特定のアドレスにリダイレクトするたびに?
通常のグローバル変数は 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
__per_cpu_offset
配列は、コピー間の距離で埋められます。CPU あたり 1000 バイトのデータが使用されると仮定__per_cpu_offset[n]
すると、1000*n
.per_cpu__x
は、ロード中に CPU 0 に再配置されますper_cpu__x
。__get_cpu_var(x)
、CPU 3 で実行している場合は、 に変換され*RELOC_HIDE(&per_cpu__x, __per_cpu_offset[3])
ます。これは、CPU 0 から始まり、CPU x
0 のデータと CPU 3 の間のオフセットを追加し、最終的に結果のポインターを逆参照します。