排他制御関連
Rev.3を表示中。最新版はこちら。
割り込み禁止
cli()で割り込み禁止状態にする。マルチプロセッサ環境においては意味がない。CONFIG_SMP定義の有無によって異なる。
CONFIG_SMP未定義時
cli命令実行するだけ
CONFIG_SMP定義時
定義がない。
2.4では全CPUで割り込みを禁止していた。
(RemoteCPUでは割り込みハンドラ実行を遅延させている)
そもそも、マルチプロセッサでは割り込み禁止だけでは排他制御はできない。spinlockによるプロセッサ間の排他も必要。
<-- このためにspin_lock_irqsave()があり、
cli()は意味がなくなったため消された。
(RemoteCPUでは割り込みハンドラ実行を遅延させている)
そもそも、マルチプロセッサでは割り込み禁止だけでは排他制御はできない。spinlockによるプロセッサ間の排他も必要。
<-- このためにspin_lock_irqsave()があり、
cli()は意味がなくなったため消された。
プロセッサ間の排他制御(スピンロック)
spin_lock()
SpinLock取得
取得できるまでSpin
取得できるまでSpin
spin_lock_irqsave()
LocalCPUについてcliで割り込み禁止にしてSpinLock取得
割り込みハンドラからもlockを取ろうとする場合は、DeadLock防止のため、こちらを使用する。
LocalCPUについて割り込み禁止しておかないと通常ContextでSpinLock取得した後、割り込みが発生して同じSpinLockを取ろうとした時、DeadLockする。他のCPUの割り込みは禁止にする必要はない。
割り込みハンドラからもlockを取ろうとする場合は、DeadLock防止のため、こちらを使用する。
LocalCPUについて割り込み禁止しておかないと通常ContextでSpinLock取得した後、割り込みが発生して同じSpinLockを取ろうとした時、DeadLockする。他のCPUの割り込みは禁止にする必要はない。
セマフォ
lock_kernel()カーネルセマフォ(kernel_sem)を取得。
down()によりセマフォが取れなければTASK_UNINTERRUPTIBLE状態でSleepする。
down()によりセマフォが取れなければTASK_UNINTERRUPTIBLE状態でSleepする。
プリエンプションの抑止
preempt_disable()current_thread_info()->preempt_countをインクリメントしてプリエンプションを抑止
プリエンプト処理は例外/割り込みからカーネルモードにもどる時(entry.S::resume_kernel)にTIF_NEED_RESCHEDが立っていたらプロセスを切り替えることでおこなっているが、preempt_countが0でなければプロセス切り替えが発生しないようにしている。
spin_lockxxx()をするとpreempt_disable()も実行され、暗黙でプリエンプションは不可とされる。
プリエンプト処理は例外/割り込みからカーネルモードにもどる時(entry.S::resume_kernel)にTIF_NEED_RESCHEDが立っていたらプロセスを切り替えることでおこなっているが、preempt_countが0でなければプロセス切り替えが発生しないようにしている。
spin_lockxxx()をするとpreempt_disable()も実行され、暗黙でプリエンプションは不可とされる。