libdrawとlibthread
rioが実際にマウス(/dev/mouse)を読んで(read)いるところを追っていくと,libdrawというライブラリに行き着いた.libdrawはグラフィック関係のライブラリだ.rioは,libdrawが提供するreadmouse(2)関数を呼び出してマウスのデータを取得している.
libdrawではマウスやキーボードにアクセスするために_ioprocというプロセス(スレッド?)が存在して,libdraw関数を呼び出した(アプリケーション)プロセスとメッセージパッシングでデータの授受を行なっている.メッセージパッシングに使われるsend/recvはlibthreadによって提供されている.
readmouse関数の肝は,recv関数で,その第一引数はチャネル,第二引数は受信メッセージのバッファである.このチャネル(mc->c)を介してrioと_ioprocは通信する.
33: int 34: readmouse(Mousectl *mc) 35: { 36: if(mc->image) 37: flushimage(mc->image->display, 1); 38: if(recv(mc->c, &mc->Mouse) < 0){ 39: fprint(2, "readmouse: %r\n"); 40: return -1; 41: } 42: return 0; 43: }
一方,_ioprocでは,61行目のreadでマウスからデータを読み込み(mc->mfdは/dev/mouseのファイル記述子である),Mouse構造体にパッキングして,sendしている.
libdraw/mouse.c 45: static 46: void 47: _ioproc(void *arg) 48: { 51: Mouse m; 52: Mousectl *mc; 60: for(;;){ 61: n = read(mc->mfd, buf, sizeof buf); 70: switch(buf[0]){ 74: case 'm': 75: m.xy.x = atoi(buf+1+0*12); 76: m.xy.y = atoi(buf+1+1*12); 77: m.buttons = atoi(buf+1+2*12); 78: m.msec = atoi(buf+1+3*12); 79: send(mc->c, &m);
おまけにlibdrawのマウス初期化関数も見ておこう.
libdraw/mouse.c 91: Mousectl* 92: initmouse(char *file, Image *i) 93: { 94: Mousectl *mc; 101: mc->mfd = open(file, ORDWR|OCEXEC); 120: mc->c = chancreate(sizeof(Mouse), 0); 122: proccreate(_ioproc, mc, 4096); 123: return mc; 124: }