namec〜名前からチャネルを取得する
今まで何度か出てきたが,追求を避けてきたnamec関数を見ていこう.と言ってもnamecは350行ほどの大きな関数なので,まずはenvデバイスを例にカーネルデバイスの場合からはじめよう.
カーネルデバイスのファイル名は#から始まる.envデバイスの場合は#eだ.そして,devtab経由でattach関数を呼び出し,チャネルを取得している.attach関数はbindmount関数にも出現していた.attachすることでファイルツリーが連結され,プロセスからアクセスできるようになる.
port/chan.c 1288: Chan* 1289: namec(char *aname, int amode, int omode, ulong perm) 1290: { 1308: name = aname; 1316: switch(name[0]){ 1322: case '#': 1350: t = devno(r, 1); 1353: c = devtab[t]->attach(up->genbuf+n); 1354: break; 1632: return c; 1633: }
envデバイスのattach関数であるenvattachは,汎用attach関数であるdevattachを呼んでいる.
port/devenv.c 63: static Chan* 64: envattach(char *spec) 65: { 66: Chan *c; 75: 76: c = devattach('e', spec); 78: return c; 79: }
devattachでは,チャネルを生成し,qidとpathを設定している.qidはファイルサーバ(今回はenvデバイス)におけるファイルの識別子で,pathはパス名である.
port/dev.c 125: Chan* 126: devattach(int tc, char *spec) 127: { 128: Chan *c; 129: char *buf; 130: 131: c = newchan(); 132: mkqid(&c->qid, 0, 0, QTDIR); 133: c->type = devno(tc, 0); 134: if(spec == nil) 135: spec = ""; 136: buf = smalloc(4+strlen(spec)+1); 137: sprint(buf, "#%C%s", tc, spec); 138: c->path = newpath(buf); 139: free(buf); 140: return c; 141: }
基本的なopen-close-read-writeは、このnamecとdevtab[]の組み合わせで実行される.次のイディオムは頻出するので覚えておくとよい.
c = namec(name, ...); devtab[c->type]->read(c, ...);