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関数で,名前からチャネルを取得するときに,何か仕掛けがあるはずだ.