CPU変数


Rev.2を表示中。最新版はこちら

シングルプロセスシステムでは、割り込みを禁止すれば、リソースの競合を回避できますが、SMPではそうはいきません。SMPではそれぞれのCPUが独自に、しかも平行して、プロセスを実行しています。ユーザモードの延長線上にあるカーネルパスについてもです。しかしリソースは共有しています。従って、そのCPUで割り込みを禁止しても、他のCPUがそのCPUで実行しているクリティカル区間を、実行する事があるからです。

その回避としてスピンロックと言う物が登場しました。スピンロックは一種のフラグ(メモリ)です。このメモリをアトミックに参照すれば、このフラグの更新での競合を回避することができます。アトミックのアクセスとは、そのメモリ参照を、メモリ回路で保証するからです。(たぶん)

しかし、スピンロックを取得する場合、取得するまでビジーウエイトでループすることになってしまいます(セマフォと違ってスピンロックは、スタティックな変数等を参照する時に利用されます。)。これはパフォーマンス的によくありません。そこで登場したのがCPU変数というものです。

CPU変数は、そのCPU下で動作しているシステム下でしか、参照できない(させない)と言う変数です。すなわち、CPU変数に関してシングルプロセスのシステムとなるわけで、その競合を回避するには、割り込みを禁止さえすれば言い訳です。従ってCPU変数でのアクセスは高速で、例えばページフレーム管理などは、このCPU変数として管理しています。トータルシステムとしてのページフレームの管理は、全CPU変数を参照することで可能でもあるわけです。

x86については、CPUその物にIDのような物を設定する事はできないようです。ではどのようにしてCPUをユニークに認識しているかと言うことですが、gsないしfsセグメントを各CPUにユニークに持たせ(CPUその物にIDを持たせると言うのでなく、そのCPUで動作している環境下に、IDを持たせると言った感じでしょうか。)、そのセグメントを参照することで、CPU毎に独自の変数を定義していているようです。(たぶん)

get_cpu_varは、CPU変数を取得するマクロです。引数のvarは取得するCPU変数です。このマクロは __this_cpu_ptrへと展開されるようです。(このあたりはアーキテクチャー依存です。) __this_cpu_ptrの詳細は今ひとつ分かりません。以下アバウトです。

__percpu_arg(1)は拡張インラインアセンブラの%1となり、this_cpu_offとなります。this_cpu_offもCPU変数のようで、CPU変数が始まるオフセットで、それと引数のvarのオフセットを足しこんで、tcp_ptr__に設定するというものです。
get_cpu_var(var)

#define __this_cpu_ptr(ptr)                             \
({                                                      \
       unsigned long tcp_ptr__;                        \
       __verify_pcpu_ptr(ptr);                         \
       asm volatile("add " __percpu_arg(1) ", %0"      \
                    : "=r" (tcp_ptr__)                 \
                    : "m" (this_cpu_off), "0" (ptr));  \
       (typeof(*(ptr)) __kernel __force *)tcp_ptr__;   \
})
ここで、 __percpu_arg(x)ですが、__percpu_prefixマクロを介して、__percpu_segでオーバプレフィックスするように展開しています。
#define __percpu_arg(x)         __percpu_prefix "%P" #x
#define __percpu_prefix         "%%"__stringify(__percpu_seg)":"
__percpu_segはCONFIG_X86_64でgsとし、そうでなければfsとしています。たぶんこのセグメントは、CPU毎のシステム起動時に、それぞれユニークな値を設定することでCPU毎にユニークな変数を定義しているのではと思います・・・。
#ifdef CONFIG_X86_64
#define __percpu_seg            gs
#define __percpu_mov_op         movq
#else
#define __percpu_seg            fs
#define __percpu_mov_op         movl
# endif


最終更新 2012/03/23 16:21:03 - north
(2012/03/23 16:19:37 作成)


検索

アクセス数
3586069
最近のコメント
コアダンプファイル - sakaia
list_head構造体 - yocto_no_yomikata
勧告ロックと強制ロック - wataash
LKMからのファイル出力 - 重松 宏昌
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
Adsense
広告情報が設定されていません。