open(2)
名前空間の取っ掛かりとして,open(2)システムコールから読んでみようと思う.UNIXでもお馴染みのopen(2)である.
int open(char *file, int omode)
アーキテクチャ依存の例外処理部ははぶき,sysopen関数から見ていく.システムコールを処理する関数は「"sys" + システムコール名」という命名規約になっている.if(waserror()) {...}とpoperror()は,カーネル内エラー処理で書いた通りで,エラー処理の定石パターンだ.肝になるのは,namec()でチャネルを取得し,newfd()でファイル記述子を取得している部分である.
port/sysfile.c 265: long 266: sysopen(ulong *arg) 267: { 268: int fd; 269: Chan *c = 0; 270: 271: openmode(arg[1]); /* error check only */ 272: if(waserror()){ 273: if(c) 274: cclose(c); 275: nexterror(); 276: } 277: validaddr(arg[0], 1, 0); 278: c = namec((char*)arg[0], Aopen, arg[1], 0); 279: fd = newfd(c); 280: if(fd < 0) 281: error(Enofd); 282: poperror(); 283: return fd; 284: } 285:
open(2)の戻り値がファイル記述子なので,アプリから見たファイルに対するインタフェースは,UNIXと大差なさそうである.カーネル内の違いとしては,UNIXの場合,ファイル記述子はオープンしたファイル構造体の配列に対するインデックスになるが,Plan9の場合,チャネル構造体(struct Chan)の配列になる.この情報を保持する構造体はFgrp(file groupの略)と呼ばれ,プロセス構造体からリンクされている.rfork(2)でRFFDGフラグを指定しなければ,親子プロセス間でFgrp(つまり,オープンファイルテーブル)が共有される.まだ,チャネルはどんなものなのかよくわかっていないけど,今のところVFSをもっと汎用化したようなイメージで捉えている.
port/portdat.h 462: struct Fgrp 463: { 464: Ref; 465: Chan **fd; 466: int nfd; /* number allocated */ 467: int maxfd; /* highest fd in use */ 468: int exceed; /* debugging */ 469: }; 600: struct Proc 630: Fgrp *fgrp; /* File descriptor group */
さて,名前空間がプロセスごとに存在するのであれば,namec関数で,名前からチャネルを取得するときに,何か仕掛けがあるはずだ.