spinlock.c void pushcli(void)
トップページ
jupiteroak.hatenablog.com
spinlock.c
https://github.com/mit-pdos/xv6-public/blob/master/spinlock.c#L116
void pushcli(void) { int eflags; eflags = readeflags(); cli(); if(mycpu()->ncli == 0) mycpu()->intena = eflags & FL_IF; mycpu()->ncli += 1; }
pushcli関数は、クリティカルセクションのネストに対応しながら、ハードウェア割り込みを無効化(マスク)します。
処理の内容
- ハードウェア割り込みを無効化する前にEFLFGSレジスタの値を保存する
- ハードウェア割り込みを無効化する
- puchi関数呼び出しがネストしていない場合はEFLFGSレジスタのIFの値を保存する
- ハードウェア割り込みを禁止した回数を記録する
ハードウェア割り込みを無効化する前にEFLFGSレジスタの値を保存する
eflags = readeflags();
readeflags関数を呼び出して、EFLFGSレジスタの値を保存します。
次の処理でcli関数を呼び出すとEFLFGSレジスタの値が変わってしまうので、cli関数を呼び出す前にEFLFGSレジスタの値を保存しておきます。
puchi関数呼び出しがネストしていない場合はEFLFGSレジスタのIFの値を保存する
if(mycpu()->ncli == 0) mycpu()->intena = eflags & FL_IF;
mycpu関数を呼び出して、mycpu関数を現在実行しているプロセッサ(スレッド)に対応しているcpu構造体を取得します。
cpu構造体のncliメンバには、puchi関数の呼び出し回数(ネストの深さ)が記録されています。
mycpu()->ncli == 0 が真となる場合→cpu構造体のncliメンバが0の場合→puchi関数の呼び出しがネストしていない場合は、cpu構造体のintenaメンバに割り込み許可の有無を示した値 eflags & FL_IF を記録します(pushcli関数がcli命令を実行する前のハードウェア割り込み許可の有無を記録します)。
eflags & FL_IFは、EFLFGSレジスタの値をFL_IF(#define FL_IF 0x0000 0200)を使ってマスク処理し、EFLFGSレジスタのIF(bit9:インターラプトエネーブルフラグ)の値を取り出したものです。
IFの値が1の場合は、ハードウェア割り込みを有効化していることを示しています。IFの値が0の場合は、ハードウェア割り込みを無効化していることを示しています。
ハードウェア割り込みを禁止した回数を記録する
mycpu()->ncli += 1;
cpu構造体のncliメンバの値をインクリメントします。