Lions' 本読み (90)

#台風そん なエントリ日曜日版第二弾です。14 章の xalloc 手続きについて。
若干病み上がりで微妙なカンジなんですがそのままエントリ投入しちゃえ。
手続き定義はざっくり三つに分けることができます。

  • 共有テキストセグメントのアタッチ。無い場合に備えて text 配列の最初の未使用要素も保存
  • アタッチできなかった場合の初期処理
  • アタッチできた場合、できなかった場合共通の終了処理

Linux での exec なシステムコールの先、は確認してみたいですね。多分 cpu アーキテクチャによって異なるはずなので i686 とか x86_64 とか arm とかそれぞれ見てみたいです。
それは良いとして上記大項目に沿って一つづつ実装を確認してみます。

共有テキストセグメントのアタッチ

ちなみに呼び出し元は exec 手続き限定で u.u_arg[1] にテキストサイズが読み込まれている前提となってます。_共有テキストセグメントのアタッチ_に使用されるデータ構造の定義が以下です。

4306 struct text
4307 {
4308  int       x_daddr;  /* セグメントのディスクアドレス */
4309  int       x_caddr;  /* ロードされている場合コアアドレス */
4310  int       x_size;   /* サイズ (64 バイト単位) */
4311  int       *x_iptr;  /* プロトタイプの i ノード */
4312  char      x_count;  /* 参照カウント */
4313  char      x_ccount; /* ロードされている参照数 */
4314 } text[NTEXT];

この配列を先頭から順に手繰っていきつつ

  • x_iptr 属性が NULL の場合、その要素は空き認定
  • 最初に見つかった空き要素はとっておく
  • 引数と x_iptr 属性の値が同じ (ということは同じ実行ファイル) 場合、それを参照する (共有テキストがアタッチできた)
    • x_count 属性の値増分
    • プロセス構造体の p_textp 属性に text 構造体の要素を代入
    • 共通の終了処理に jmp

ということをしている模様。
共有テキストがアタッチできた場合は共通の終了処理に飛びますが、そうでない場合は最初に見つかった空き要素をもとにして次の処理に移ります。

アタッチできなかった場合の初期処理

ここもざっくりめに処理を列挙してみます。

  • text 構造体オブジェクトの初期設定
    • x_count 属性は 1 代入
    • x_ccount 属性は 0 代入
    • x_iptr 属性は ip 代入
    • x_x_size 属性は u.u_arg[1] からサイズ計算して代入 (ローカル変数 ts にも代入)
  • スワップ領域確保して x_daddr 属性に代入
    • サイズは上記 ts を元に計算
  • expand で USIZE+ts なサイズにデータセグメントなサイズを変更
  • estabur でセグメンテーションレジスタ調整
    • データセグメントの領域サイズが ts であとは 0 という形
    • 実行ファイルのテキストセグメント読み込み用の領域
  • 用意した領域にテキストセグメントを読み込み
  • 今操作しているプロセスがスワップされない印を付けて swap 手続きを呼び出した後にスワップされない印を外す
    • x_daddr に確保した swapmap な領域に上で読み込んだ領域をスワップアウト
  • プロセス構造体の p_textp 属性に text 構造体のアドレスを代入
  • ip が指す属性の設定 (詳細略
  • expand したデータセグメントなサイズを縮小

テキストセグメントを一旦データセグメントに読みこんでおいてスワップアウトさせてます。そしてここのブロックを通過するケイスでは x_ccount 属性が 0 で設定されたママですので、次のブロックでスワップアウトして終わります。

共通の終了処理

上述の通り、x_ccount 属性が 0 (text 構造体の要素を新たに使用した場合) ならばデータセグメントをスワップアウトして savu(u.u_ssav) して swtch() で制御を抜けます。次に戻るのは swtch 手続き経由で exec の 3131 から実行が開始されます。また、x_ccount 属性が 0 ではない場合は単純に 1 加算して終わっているのが分かります。
ちなみに始めて実行されるあるプログラムがあるとすると

  • fork, exec
    • exec から呼び出される xalloc でいったんスワップアウト
  • swtch でチョイスされて exec に復帰して exec 終了
  • sched で exec により kickof されたプロセスをスワップイン
    • ここで x_ccount の値が 0 であればテキストをスワップ領域から読み込んでます

別件にて気になったこと

むむ、例えば expand の中でメモリ確保できなくてスワップアウトする場合、どうなるんだろ。別途確認してみたいと思います。