ロックは保持されているので、そのCPUは割り込み無効な状態で実行されている。
swtchの呼び出し元は、すでにロックを保持してなければならないが、そのロックの管理は切り替え先のコードに渡される。
一般的な決まりごとは、ロックを獲得したスレッドにそのロックを解放する責任もあるということであり、それは正しさのためという単純明快な理由による。
これは2つのCPUが同じスタック上で実行される結果を引き起こす可能性があり、それは正しくない状況である。
実行すべきプロセスを見つけ、止まるまで実行し、それを繰り返す。
これは、このCPUが暇なとき(RUNNABLEなプロセスが見つからない)という特別な場合に重要である。
もしロックを保持したまま暇なスケジューラがループした場合、プロセスを実行中の他のどのCPUもコンテキストスイッチや、プロセス関連のシステムコールを実行できなくなり、特に暇なCPUをそのスケジューリングのループの外に脱出させるために、プロセスをRUNNABLEとしてマークすることが出来なくなる。
プロセス(例えばシェル)はI/O待ちになったりするので、RUNNABLEなプロセスが全くない状況になる可能性があるということが、暇なCPU上で定期的に割り込みを有効にする理由である。
もしプロセスがRUNNINGなら、タイマ割り込みによって呼び出されるyieldが、そのプロセスからどこかへ正しく切り替える事が出来るようにするためにセットアップされなければならない、ということがインバリアントのひとつである。
もしプロセスがRUNNABLEなら、暇なCPUのスケジューラがそれを実行出来るようにするためにセットアップされなければならない。
一度、実行中のプロセスの状態をRUNNABLEへ変更するためのコードが開始したら、そのコードはインバリアントの復元が完了するまでロックを保持しなければならない。
同様に、一度、スケジューラが実行可能なプロセスをRUNNINGに変更しはじめたら、カーネルスレッドが確実に実行されるまで(yield中のswtchの後)ロックを開放してはいけない。
ptable.lockの別の関数が分割可能かどうかについて、よく理解するためには確実に、パフォーマンスのためには多分、考える価値がある。
途中色々書いてあるところは、プロセスを表すデータ構造のインバリアントを保護するために切り替え前に何を行うかについて書かれてるんだと思います。