Bug #2575
closeda test fail for IO#readpartial is broken on *BSD
Description
=begin
IO#readpartialのテストに失敗します。確認はNetBSD 5.0_STABLE, current (5.99.22)とFreeBSD 7.2-STABLE、いずれもi386環境で行いました。
test/ruby/test_io.rb の test_readpartial_pos() に、
open("foo", "w") {|f| f << "abc" }
open("foo") {|f|
f.seek(0)
assert_equal("ab", f.readpartial(2))
assert_equal(2, f.pos)
}
といったテストがあります。ここで、f.posの結果がゼロとなってテストに失敗します。直前のf.seek(0)を削除するとテストに成功するようになりますが、この有無で結果が変わってはなりません。
io.cのio_getpartial()では、
- read_buffered_data()でFILE構造体に読み込み済みのデータを読んでみる。
- 読み込み済みのデータがなければ、
2.1 read(2)でデータをFILE構造体に読み込む。
2.2 後でfflush(3)を呼び出してFILE構造体の内容の整合性が取れ(ることを
期待してい)る。
といったことをしています。2.1の処理は、
merge revision(s) 21913:
* io.c (io_getpartial): fflush after read for updating pos in FILE.
not portable, I guess. [ruby-core:21561]
とコミットされています。ここで推測されているように実際に移植性はありません。そもそも、fflush(3)で構造体の内容が適切になされると期待することに無理がある気もします。
*BSDのFILE構造体(DragonFlyは不明)には、
o ファイル中のオフセットを示す構造体メンバ _offset があります。
o 構造体メンバ_flagsのフラッグ値には、_offsetの値が実際に有効かどうかを
示す __SOFF という値があります。
そして、この問題は以下のように説明できます。
(1) f.seek(0)を呼び出すとfseeko(3)が呼び出されて、_offsetに値と__SOFFが
フラッグが設定されます。このときの _offset が後のf.tellの戻り値となっ
ています。
(2) f.seek(0)を呼び出さないと、f.tellの呼び出された時点で_offsetに値と
__SOFFが設定されるため、期待した値が返ることになります。
解決策としては、fflush(3)の呼び出しに代えて__SOFFをアンセットしてからftello(3)を呼び出すといったことが考えられます。取り敢えずのパッチで、問題が解決することを確認しました。
=end
Files
Updated by taca (Takahiro Kambe) almost 15 years ago
=begin
In message 4b46a911c23d1_8c3bbe17ec398dd@redmine.ruby-lang.org
on Fri, 8 Jan 2010 12:40:04 +0900,
Takahiro Kambe redmine@ruby-lang.org wrote:
解決策としては、fflush(3)の呼び出しに代えて__SOFFをアンセットしてから
ftello(3)を呼び出すといったことが考えられます。取り敢えずのパッチで、
問題が解決することを確認しました。
この問題は解決しますが、解決しているのはオフセットだけで、
read_buffered_data()辺りにはfread(3)呼び出してるコードも
存在します。
副作用もあるでしょうし、最終的にはRuby 1.9でstdio捨てると
いう話に結び付くのでしょう。
--
神戸 隆博(かんべ たかひろ) at 仕事場
=end
Updated by taca (Takahiro Kambe) almost 15 years ago
=begin
[ruby-dev:40051] に添付のパッチで現象が解決することを確認しました。
根本的な原因は、Bug #1872で、timerスレッド関係か何かの関係で顕在化したと考えられます。
=end
Updated by taca (Takahiro Kambe) almost 15 years ago
=begin
In message 4b4c141dbb220_8bcf020a0844891@redmine.ruby-lang.org
on Tue, 12 Jan 2010 15:18:06 +0900,
Takahiro Kambe redmine@ruby-lang.org wrote:
[ruby-dev:40051] に添付のパッチで現象が解決することを確認しました。
と、書きましたが、
根本的な原因は、Bug #1872で、timerスレッド関係か何かの関係で顕在化し
たと考えられます。
単純なバッククォートやsystem()の実行での問題は解消しましたが、やはり、
test_local_barrier(TC_Thread):
で刺さるときがあるようです。
--
神戸 隆博(かんべ たかひろ) at 仕事場
P.S.
刺さったプロセスを kill -KILL で終了させて、make test-all を終わらせた
あとに、親なしとなったrubyのプロセスが10個くらい残り、parkedな状態
(pthread_joinか何か)となってます。NetBSD current (5.99.22)自体も怪しい
ところはあるので、取り敢えず 5.99.23 にしてから再確認する予定です。
=end
Updated by taca (Takahiro Kambe) almost 15 years ago
=begin
申し訳ありませんが、redmineに登録された、
[ruby-dev:40055]によるコメント#2
[ruby-dev:40056]によるコメント#3)
については、IO#readpartialの問題とは無関係でした。
=end
Updated by hukl (John Bader) over 14 years ago
=begin
I have issues with that on FreeBSD. I ran unicorn and it delivered only partial responses. The maintainer fixed this with:
diff --git a/io.c b/io.c
index 375cbc8..d4d28e5 100644
--- a/io.c
+++ b/io.c
@@ -122,6 +122,9 @@ extern void Init_File _((void));
endif¶
#endif
+#define preserving_errno(stmts) \
- do {int saved_errno = errno; stmts; errno = saved_errno;} while (0)
VALUE rb_cIO;
VALUE rb_eEOFError;
VALUE rb_eIOError;
@@ -490,7 +493,7 @@ io_fwrite(str, fptr)
r = write(fileno(f), RSTRING(str)->ptr+offset, l);
TRAP_END;
#if BSD_STDIO
- fseeko(f, lseek(fileno(f), (off_t)0, SEEK_CUR), SEEK_SET);
- preserving_errno(fseeko(f, lseek(fileno(f), (off_t)0, SEEK_CUR), SEEK_SET));
#endif
if (r == n) return len;
if (0 <= r) {
This resolved the issue for me. I applied the patch to the FreeBSD ruby18 port and reinstalled.
=end
Updated by taca (Takahiro Kambe) over 14 years ago
=begin
Hi John.
Dose your patch solve the partial read problem on FreeBSD without io.c.diff,
or your patch provide additional fix?
Anyway, I rewrite slightly your patch and merged my updated fix to attached file.
=end
Updated by jeremyevans0 (Jeremy Evans) about 5 years ago
- Description updated (diff)
- Status changed from Open to Closed