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レジスタの値を保存する

eflags = readeflags();

readeflags関数を呼び出して、EFLFGSレジスタの値を保存します。
次の処理でcli関数を呼び出すとEFLFGSレジスタの値が変わってしまうので、cli関数を呼び出す前にEFLFGSレジスタの値を保存しておきます。

ハードウェア割り込みを無効化する

cli();

cli関数を呼び出して、割り込みを無効化します。

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メンバの値をインクリメントします。