エンジョイC051回目newproc関数が1を返す仕組み(2021-04-18)

1
ほえほえ@スプシマン @hoehoe1234

カーネルのメモリ構成を見ると次のようになっています。 ①すべてのプロセスでカーネルコードは共通 ②同上、データセグメントも共通 ③ただし、スタックのみ各プロセスが保有(場所はPPDA) となっています。

2021-04-23 17:07:02
ほえほえ@スプシマン @hoehoe1234

このメモリ構成はスレッドに似ていますね。スタックが違うということは、スタックに依存する命令が影響を受けるということです。スタックには関数の実行履歴とローカル変数が保存されていますので、カーネルは各ユーザプロセスに対応したカーネル内での実行状態を個別に保有することになります。

2021-04-23 17:09:53
ほえほえ@スプシマン @hoehoe1234

次にJSR、RSRなどのスタックの値を対象とする命令群が影響を受けます。これらの命令はスタックからジャンプ先(通常は戻りアドレス)を引き出します。ですからretu関数でPAR6を切り替えた瞬間にカーネルはそのプロセス固有の実行状態に切り替えられるということですね。

2021-04-23 17:12:35
ほえほえ@スプシマン @hoehoe1234

swtch内ではアタッチされたプロセスのユーザ仮想空間を構築しなおします。これらについてはまだ解析はできていませんが、結局ユーザプロセスはシステムコールを呼び出した次の命令から再開されることになります。

2021-04-23 17:13:49
ほえほえ@スプシマン @hoehoe1234

この仕組を理解するポイントはswtch関数です。この関数は2回retuを呼び出してカーネルスタックを切り替えています。しかし、(スタック上の)ローカル変数は使用してないので変数に影響は発生しません。もしローカル変数をつかっていればretuを実施するたびに値が変わってしまいますから。

2021-04-23 17:16:00
ほえほえ@スプシマン @hoehoe1234

swtch関数はカーネルスタックの切り替えに関係なく最初から最後まで動きます。2回目の切り替えでライジングプロセスを選択した後、swtchがretrunすることで、選択されたプロセスのカーネルスタック上の戻り値にジャンプします。

2021-04-23 17:18:48
ほえほえ@スプシマン @hoehoe1234

この戻りアドレスは、①「savuを行う関数を呼び出した関数の、savuを行う関数を呼び出した次の命令位置」です。 sleep関数を例に取ると次のようになります。 sleep  ・  ・  swtch(内部でsavuを行う)  アセンブラはJSR PC, swtch  ⇒ここが①の位置  ・  ・

2021-04-23 17:26:16
ほえほえ@スプシマン @hoehoe1234

swtchのコードは連続して実行されていますが、カーネルスタックが切り替えられているので、その状況に応じた関数に「ジャンプ」するというイメージになります。C言語だけの理解ではなかなかこの当たりは見えてきません。カーネルを読むのがむずかしい理由の一つだと思います。

2021-04-23 17:27:52
ほえほえ@スプシマン @hoehoe1234

今回の講義では、いままでの総まとめとしてカーネルがプロセスをどのように切り替えるのかを仮想記憶にさかのぼって原理と全体像の説明をしてみました。OSコードリーディングの第一の難関がこのプロセス切り替えだと思います。この部分の腹落ちが今後の学習に影響しますのでじっくりと解説しました。

2021-04-23 17:30:05
ほえほえ@スプシマン @hoehoe1234

プロセス切り替えまではコードの1行1行を精読してきましたが、次回以降は精読のラインのほかに「概要と全体像を理解」するラインの2つに分けていこうとおもいます。execなどは全体が絡んでくるからです。次回以降も頑張って解説したいと思います。 おしまい。

2021-04-23 17:31:31