From: "NAKAMURA, Hiroshi" Date: 1999-06-22T19:42:05+09:00 Subject: [ruby-dev:7172] [PATCH] io.c: getc does not set errno? なひです. ruby-listから引っ張ってきました. > From: Yukihiro Matsumoto [mailto:matz@netlab.co.jp] > Sent: Monday, June 21, 1999 4:03 PM > Subject: [ruby-list:15055] Re: HUP シグナルを受けとってファイルの読み込 > みがうまくいかないのですが > In message "[ruby-list:14995] HUP シグナルを受けとってファイルの読み込みがうまくいかないのですが" > on 99/06/11, Keisuke Minami writes: > > |Threadを使ったプログラムの中で > |HUPシグナルを受けとってあるファイルを読み直すという > |プログラムを作ったのですがどうしてもうまく動きません。 > |HUPシグナルを受けとっても予想通りの反応をしないんです。 > > シグナルハンドラは任意のスレッドで実行されちゃうんで、killで > 自分自身を殺しちゃうことがあるからではないでしょうか? [ruby-list:15055]の紹介で三並さんの記事に気づいて, いろいろ機能を削って試してみました. 最終的にたどり着いたのが以下のようなスクリプトです. これでも,2度目のSIGHUPで,eachのところで無限ループします. ruby 1.3.4 (1999-06-11)です. p $$ def doSomething( name ) fh = File.open( name, "r" ) fh.each do |l| p l end fh.close() print "done\n" end trap("HUP") { p "receive HUP" doSomething( "conf" ) p "...finished." } $stdout.sync = true loop do sleep(1) end gdbで追いかけてみたところ,rb_io_getsの 以下のループを延々繰り返していました. 630 for (;;) { 631 READ_CHECK(f); 632 TRAP_BEG; 633 c = getc(f); 634 TRAP_END; 635 if (c == EOF) { 636 if (errno == EINTR) continue; 637 break; 638 } 639 if ((*bp++ = c) == newline) break; 640 if (bp == bpe) break; 641 } どうやら以下のようなシナリオのようです. 1. sleepする. 2. poll中にSIGHUPを受信. 3. 一度目のsignal handler処理.通常どおり行われる. 4. signal handlerから帰ってきたところで,poll中のインタラプトということで, errnoがEINTRにセットされる. 5. 再びsleepする. 6. poll中に二度目のSIGHUPを受信. 7. 二度目のsignal handler処理.上記コードに飛び込み,読む読む. 8. line: 633でgetcがEOFを返す.しかしこのマクロはerrnoをセットしない. 不幸にしてerrnoはEINTRのまま. 9. line: 636の特例に引っかかってcontinue.延々繰り返す. というわけで,弊社の小松さんにお願いしたら(^^;), io.cへのPatchを作ってコンパイルしてくれました. いやー,弊社では,小松さんを差し置いてコンパイルすることは 許されていないのです(おおうそ この変更で,上記のサンプルスクリプトは動きました. [ruby-list:14996]の,三並さんのスクリプトも,ちゃんと動くようです. $stdout.syncや「SIGHUPが子スレッドに投げられた場合」など, 若干の問題はありますが... さて,ともかく,getcがerrnoを設定しない場合もあるんですよね. ferrorの時のみEINTR,でいいでしょうか? / / / Index: io.c =================================================================== RCS file: /home/cvs/ruby/io.c,v retrieving revision 1.1.1.3.2.20 diff -u -p -r1.1.1.3.2.20 io.c --- io.c 1999/06/11 06:29:54 1.1.1.3.2.20 +++ io.c 1999/06/22 10:35:51 @@ -544,7 +544,7 @@ rb_io_gets_internal(argc, argv, io) c = getc(f); TRAP_END; if (c == EOF) { - if (errno == EINTR) continue; + if (ferror(f) && errno == EINTR) continue; break; } if ((*bp++ = c) == newline) break; @@ -633,7 +633,7 @@ rb_io_gets(io) c = getc(f); TRAP_END; if (c == EOF) { - if (errno == EINTR) continue; + if (ferror(f) && errno == EINTR) continue; break; } if ((*bp++ = c) == '\n') break;