srvデバイス
また,日が開いてしまった.なかなか毎日更新するのは難しいなぁ.
UNIXで名前付きパイプ(またの名をFIFOスペシャルファイル)を作る場合は,専用のライブラリ関数mkfifo(3)を使う必要があるが,Plan9では,srvデバイス(#s)を使って実現できる.man srv(3)の例を次に引用する.
int fd, p[2]; char buf[32]; pipe(p); fd = create("/srv/namedpipe", OWRITE, 0666); fprint(fd, "%d", p[0]); close(fd); close(p[0]); fprint(p[1], "hello");
パイプを生成し,入力側のファイル記述子を/srv/namedpipeに書き込んでいる.これで,/srv/namedpipeへの読書きが,このパイプを介してやりとりできる.例えば,あるプロセスが/srv/namedpipeを読み出すと,"hello"と返される.
話をrioに戻して,前回書いたようなファイルツリーを作っている部分を見ていこう.今までとは違い,カーネルではなく,ユーザランドのソースコードであることに注意.
filsysinit関数がファイルシステム回りの初期化部分で,post関数は上のman srv(3)で示した例のように,srvデバイスにパイプのファイル記述子を書き込む関数である.
cmd/rio/fsys.c 90: post(char *name, char *envname, int srvfd) 91: { 92: int fd; 93: char buf[32]; 94: 95: fd = create(name, OWRITE|ORCLOSE|OCEXEC, 0600); 96: if(fd < 0) 97: error(name); 98: sprint(buf, "%d",srvfd); 99: if(write(fd, buf, strlen(buf)) != strlen(buf)) 100: error("srv write"); 101: putenv(envname, name); 102: } 122: Filsys* 123: filsysinit(Channel *cxfidalloc) 124: { 126: Filsys *fs; 130: fs = emalloc(sizeof(Filsys)); 131: if(cexecpipe(&fs->cfd, &fs->sfd) < 0) 132: goto Rescue; 169: sprint(srvpipe, "/srv/rio.%s.%d", fs->user, pid); 170: post(srvpipe, "wsys", fs->cfd);
postの最後に環境変数を設定しているが,今回はwsysが設定される.例えば,nsの結果で見たように,次のような結果になる.
term% echo $wsys /srv/rio.oraccha.23
postで使われるパイプはcexepipe関数で作られる.ここでは,pipe(2)を使わず,わざわざパイプデバイス(#|)を使って,パイプをオープンしている.その理由は明日に続く.瑣末なところで,OCEXECというオープンモードは見慣れないが,exec(2)が実行されたら,ファイルをクローズするという意味である.
108: int 109: cexecpipe(int *p0, int *p1) 110: { 111: /* pipe the hard way to get close on exec */ 112: if(bind("#|", "/mnt/temp", MREPL) < 0) 113: return -1; 114: *p0 = open("/mnt/temp/data", ORDWR); 115: *p1 = open("/mnt/temp/data1", ORDWR|OCEXEC); 116: unmount(nil, "/mnt/temp"); 117: if(*p0<0 || *p1<0) 118: return -1; 119: return 0; 120: }