From: Tanaka Akira Date: 2004-11-27T02:58:10+09:00 Subject: [ruby-dev:24965] sync and stdio buffering ちょっとした思いつきなのですが、 Index: io.c =================================================================== RCS file: /src/ruby/io.c,v retrieving revision 1.330 diff -u -p -r1.330 io.c --- io.c 26 Nov 2004 06:27:45 -0000 1.330 +++ io.c 26 Nov 2004 17:33:27 -0000 @@ -2728,6 +2728,7 @@ rb_io_synchronized(fptr) OpenFile *fptr; { fptr->mode |= FMODE_SYNC; + setvbuf(GetWriteFile(fptr), NULL, _IONBF, 0); } void というかんじで、sync なときには stdio の buffering を行わないようにす るのはどうでしょうか。 その狙いは % ruby -rfcntl -e ' r, w = IO.pipe pid = fork { w.close sleep 1 puts r.read } r.close w.fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK) w.write "x" * 4098 w.write "y" w.close Process.wait pid'|od -c 0000000 x x x x x x x x x x x x x x x x * 0010000 y \n 0010002 という、nonblocking write におけるデータの蒸発を (sync なときに限り) 避けるというものです。 パッチを当てない状況では上記のように 4098個の x を書き込んだにも関わら ず 4096個しか出て来ませんが、パッチを当てると % ./ruby -rfcntl -e ' r, w = IO.pipe pid = fork { w.close sleep 1 puts r.read } r.close w.fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK) w.write "x" * 4098 w.write "y" w.close Process.wait pid'|od -c 0000000 x x x x x x x x x x x x x x x x * 0010000 x x y \n 0010004 というように、書き込んだ 4098個すべてが出て来ます。 このようにデータの蒸発が避けられる理由は、stdio レベルのバッファリング がなくなるために、EAGAIN が fflush でなく fwrite で起き、rb_io_fwrite がちゃんと EAGAIN でループするようになるというものです。 ただし、このパッチには (少なくとも) つぎの問題があります。 * setvbuf は fopen (や fdopen) 直後にしか呼び出してはいけないのに pipe_open 中から orig_stdout と orig_stderr に対して呼び出してしまう * IO#sync= で false にしてもバッファリングしなくなってしまう というわけで、上記のパッチそのものはあまりうまくないような感じもします が、こういうアイデアはどんなものでしょうか? -- [田中 哲][たなか あきら][Tanaka Akira]