[#7102] Ruby 1.3.4-990611 — Yukihiro Matsumoto <matz@...>

Ruby 1.3.4-990611 is out, check out:

20 messages 1999/06/11

[#7223] Ruby 1.3.4-990625 — Yukihiro Matsumoto <matz@...>

Ruby 1.3.4-990625 is out, check out:

14 messages 1999/06/25
[#7224] -Wl,-rpath on Linux (Re: Ruby 1.3.4-990625) — Ryo HAYASAKA <hayasaka@...21.u-aizu.ac.jp> 1999/06/25

早坂@会津大学です。

[ruby-dev:7172] [PATCH] io.c: getc does not set errno?

From: "NAKAMURA, Hiroshi" <nakahiro@...>
Date: 1999-06-22 10:42:05 UTC
List: ruby-dev #7172
なひです.

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 <keisuke@rccn.com> 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;

In This Thread

Prev Next