2005年12月3日 (土曜日)

14:57:59 # Life CPU アーキテクチャ名の混乱. amd64(Debianでの呼称, AMDのマーケティングはOpteronが出始めたころにAMD64という呼称に変更してくれ,とあらゆるところに依頼を出した.Debianはそれに従った.), K8(順当にいった場合のコード名), x86-64(Linux カーネル, gcc での呼称,まだシミュレータしか無いころは最初はこういう名前だった), x64(Windowsでの最近はじまった呼称), ia32e(リリース前のIntelの呼称), EM64T(Intelの呼称). この名前は実はすべて同じCPUアーキテクチャをさします. Dave Jonesが愚痴っていました.

19:50:34 # Life cowdancerで,cow-shellを毎回起動されるたびにfindがうごいているのがなんとなく気に入らない. dnotifyとかで監視してファイルの更新があったら更新するようにして, デーモンがファイル一覧の情報をもっていて, その情報をUNIXドメインソケット経由で提供する,というインタフェースが使えないだろうか,と考えてみる. 現在はあらゆるケースで find/xargs/stat を活用していて, fork/execしまくりなので,それを何とかしたい. ただ,そこがボトルネックになっているという事実は全くないので, 実用的にはそんなことをしなくても問題ない.どっちかというと,機能があるからやってみました的なハック価値. 現状.ilist というファイルにi-nodeの一覧を保持しているが,そのファイルをUNIX Domain socketにしてしまって,デーモンがその先に存在するようにしたらどうなるだろうか. dnotifyとunix domain socketについて下調べをしてみる.

dnotifyについて.カーネルソースのfs/dnotify.cにある. Documentation/dnotify.txtにドキュメントがある. cowdancer的には,DN_CREATE DN_DELETE DN_RENAMEが気になる. こいつらを監視すればよさそう. dnotifyのサンプルを動かしてみるといろいろと分かる. ディレクトリを一つ監視するために,ディレクトリをopenで開き,fdに対してfnctlで監視を指定する. 何かイベントが起きた場合には,カーネルが,指定した任意のシグナルを送信してくれ, ディレクトリを開いたときのファイルデスクリプタ番号を送信してくれる. どのディレクトリに変更が発生したのか,というのは,ファイルデスクリプタの番号で確認できる仕組みになっている. サブディレクトリについては,監視できないので, それぞれのディレクトリに関して監視を設定する必要がある. つまり,ディレクトリツリーを監視するには,ディレクトリの数だけファイルデスクリプタを開く必要がある. 例として, Debian の base.tgz を展開した結果を監視する場合,689のファイルデスクリプタが必要になる. dnotify.cを読んでいると,一つのファイルに対して操作が発生した場合に関しても, そのparent inodeを発見するためだけにspinlockをしている. さらに,その親にまで遡及させるにはそれなりに長い処理が必要になるので, なんとなくいやだ. ということを調べていたら,inotifyというのがあるのを思い出した. inotifyのドキュメントはDocumentation/filesystems/inotify.txtにある. dnotifyの反省をいかした内容になっている. ファイルの変更イベントの送信がシグナルではなく,ファイルからのreadだけで実現できているという点がポイント. しかし,dentryのparentを見て,そのinodeが監視対象か,という確認しかしていないので, 全ディレクトリを監視するためには,監視対象に全ディレクトリを指定してあげないといけないというのは同じ.ただ,それぞれのディレクトリに対してファイルデスクリプタをopenにする必要はない. これを実行するには,find相当の処理が必要. 結局,cowdancerの観点から見ると,dnotifyもinotifyも50歩100歩ということが判明した.

Socketについて. UNIX Domain Socketというのを作成すると,指定したファイル名ができ,それ経由でソケット通信ができるようになる. 指定するのは,PF_LOCAL, PF_SOCKETPF_FILE(全て同じらしい). sockaddr_inの代わりにsockaddr_unという構造体があり,それで実際にファイル名を指定する. その構造体中に謎の固定長のsun_path[108]という配列がある.これは,ファイル名の文字列らしい. 108文字という制限はなぜ存在するのだろう,というコメントがglibc.infoにはあって,確かに謎だ. glibc:socket/sys/un.hにも確かにそう定義されていて, 実際にその制限は存在しているようだ. なんとなくglibcのソースを読んでいたら, なんとなく凄いコードを見付けた.glibc:sysdeps/mach/hurd/bind.c. lispか,と思うようなコード. 一連のコードを{}で囲めば,最後のステートメントの値が{}の結果として評価され,それをそのまま関数の値として利用している,のか?マクロなので,違うのかもしれない.

  err = HURD_DPORT_USE (fd,
			({
			  if (err)
			    err = __socket_create_address (port,
							   addr->sun_family,
							   (char *) addr, len,
							   &aport);
			  if (! err)
			    {
			      err = __socket_bind (port, aport);
			      __mach_port_deallocate (__mach_task_self (),
						      aport);
			    }
			  err;
			}));
	

まるでlispみたいなコードが書ける. うーむ.盲点だった.だからといってこれがよいコードなわけははないだろう. まず,何がしたいのかよくわからない. もうちょっと読みやすいサンプルを作ってみた. しかし,これがどの場面で便利になのか,という点については疑問. いろいろと調べていると,Linux カーネルの get_user 関数も 同様の構造でマクロを定義していることを発見.悪夢のようだ.


main()
{
  const char *a;
  printf ("Hello C %s \n", 
	  ({
	    if (1)
	      {
		a="This is possible";
	      }
	    else
	      {
		a="Weird test"; 
	      }
	    a;
	  })
	  );
}
	
Junichi Uekawa

$Id: dancer-diary.el,v 1.89 2005/05/12 11:19:14 dancer Exp $