Lions' 本読み (48)
まごろくさんからフォロー頂いた部分を確認。
まず malloc から
まごろくさん tweet が以下。
mallocは今のmalloc(3)とは違って、OS層の領域を管理します。メモリとDISK上のswap域を共通のロジックで管理してます。これにswapmapを渡すとswap領域の獲得。coremapを渡すとメモリ領域の獲得を行う事ができます。
https://twitter.com/magoroku15/status/211103131990376448 より引用
297p あたりに解説あり。ここも宿題ということにしといて別途確認の方向。
xalloc 手続き
ざっくりベースで確認を。まず unix/text.h で定義されてる構造体が以下。
4300 /* 4301 * text 構造体 4302 * スワップデバイス上の純粋な 4303 * 手続きごとに 1 つづつ割り当てられる。 4304 * text.c が操作する。 4305 */ 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];
xalloc 手続きではこの構造体の配列をナメて一番アタマの x_iptr 属性が NULL な要素を取り出し候補にしておきつつ、引数の i-node なポインタと x_iptr 属性の値が同じ要素があるかどうかを確認してます。
同値な要素があれば共用可能な text セグメントがロードされておる、という判断をしている模様。
4441 for(xp = &text[0]; xp < &text[NTEXT]; xp++) 4442 if(xp->x_iptr == NULL) { 4443 if(rp == NULL) 4444 rp = xp; 4445 } else 4446 if(xp->x_iptr == ip) { 4447 xp->x_count++; 4448 u.u_procp->p_textp = xp; 4449 goto out;
x_ccount という属性はコアにいるのかどうかを判断する属性な模様。out なラベル以降の処理の記述が以下になってて
4474 out: 4475 if(xp->x_ccount == 0) { 4476 savu(u.u_rsav); 4477 savu(u.u_ssav); 4478 xswap(u.u_procp, 1, 0); 4479 u.u_procp->p_flag =| SSWAP; 4480 swtch(); 4481 /* リターンしない */ 4482 } 4483 xp->x_ccount++;
値が 0 ならスワップアウトしとります。また、共用できる text セグメントが無かった場合、この属性の値は 0 で初期化されてて、見つからなかった場合は必ず一回スワップアウトする、という事、で良いのかな。
核心部分
とりあえず順に確認。
4452 xp->x_count = 1; 4453 xp->x_ccount = 0; 4454 xp->x_iptr = ip; 4455 ts = ((u.u_arg[1]+63)>>6) & 01777; 4456 xp->x_size;
このあたりは text 構造体な配列要素の初期化ですね。
- 参照カウント 1 にして
- コアにはロードされておらず
- 引数で渡された i-node オブジェクトを x_iptr 属性に格納
- テキストセグメントのサイズを x_size 属性に格納
で、スワップ領域確保してるのか。
4457 if((xp->x_daddr = malloc(swapmap, (ts+7)/8)) == NULL) 4458 panic("out of swap space");
で、
が以下二行で
4459 expand(USIZE+ts); 4460 estabur(0, ts, 0, 0);
次にユーザーアドレス空間の 0 番地にテキストセグメントなデータを読み込んでいます。
4461 u.u_count = u.u_arg[1]; 4462 u.u_offset[1] = 020; 4463 u.u_base = 0; 4464 readi(ip);
readi 手続きは 6221 以降で定義されててコメントの一部を以下に
6216 * u_base 転送先のコアアドレス 6217 * u_offset ファイル中のバイトオフセット 6218 * u_count 読み出すべきバイト数 6219 * u_segflg カーネル/ユーザーへの読み出し
これってデータセグメントにテキストセグメントを読み出した、という記述になってますが、swap を簡単に済ませるための便宜的措置と見てよいのかな。
んで、プロセス構造体を取り出してロックして
4465 rp = u.u_procp; 4466 rp->p_flag =| SLOCK;
swap 手続き呼び出してます。
4467 swap(xp->x_daddr, rp->p_addr+USIZE, ts, 0);
これ、順番に
- 確保したスワップ領域のアドレス
- ユーザ構造体のアドレスに USIZE を加えた値 (データセグメントのアドレス ?)
- ここがユーザーアドレス空間の 0 番地になるはず
- テキストセグメントのサイズ
- 最後の引数が現時点で意味不明
という事なのか。で、後は諸々の後始末をして
4468 rp->p_flag =& ~SLOAD; 4469 rp->p_textp = xp; 4470 rp = ip; 4471 rp->i_flag =| ITEXT; 4472 rp->i_count++; 4473 expand(USIZE);
終わり、なんですがなんつーか凄いな。ポインタ型が何でも指せちゃうので何でもあり的記述になってて笑う。4469 まではプロセス構造体の後始末で、4470 から 4472 までは引数で渡ってきた i-node なオブジェクトの後始末なのか。
で、最後にスワップアウトされた領域を解放して out: 以降の処理、になるのか。
あら?
swap 手続きはスワップインが云々という記述がありますね。あ、でも 374p な記述は以下なのか。
4467: (プロセス固有データを除いた) データセグメントをテキストセグメントのために確保されたディスクスワップ領域にスワップアウトする。
Lions' Commentary on UNIX より引用
xalloc のコメントも以下に引用してみます。
4418 /* 共有テキストセグメントをアタッチする。 4419 * 共有テキストがなければ、リターンする。 4420 * あれば、それをつかまえる。 4421 * もしそれが現在使われていなければ、i ノード (ip) から 4422 * 読み込んで、スワップ空間に作る必要がある 4423 * 使われていても、現在コアにないなら、 4424 * それを戻すために swap を呼び出さなければならない。
ついでに xswap も見てみる
と思ったらここでも swap 呼び出してますね。どうも swap に渡す四番目の引数が読み書きなフラグになっている模様。sched とかでは 1 を渡してスワップイン、みたい。
ということで勉強会がそろそろ始まるので続きは別途。