[#20227] dyna_vars problem? — Tanaka Akira <akr@...17n.org>

しばらく前から、稀に Ruby が core を吐くという問題を追いかけているので

15 messages 2003/05/19
[#20234] Re: dyna_vars problem? — matz@... (Yukihiro Matsumoto) 2003/05/19

まつもと ゆきひろです

[#20236] Re: dyna_vars problem? — Tanaka Akira <akr@...17n.org> 2003/05/19

In article <1053363181.529491.30320.nullmailer@picachu.netlab.jp>,

[ruby-dev:20269] Re: pipe reopen

From: nobu.nakada@...
Date: 2003-05-21 17:20:51 UTC
List: ruby-dev #20269
なかだです。

At Tue, 4 Feb 2003 15:10:29 +0900,
Yukihiro Matsumoto wrote:
> |> 一応こんなのを考えてみましたが、どうもlinux(というかglibc)では、
> |> fdopen()のときのモードを覚えておいてそれに合わない操作はエラー
> |> になるようで、fptr->fからは書き込みはできないようです。
> |
> |stdio objectを使い回しすべきなのは、descriptorが1..2のときでは
> |なく、stdin,stdout,stderrのときではないかという気がして来ました。
> |この二つは通常は同じことですが、STDIN.closeしてしまうと別です。
> 
> うーん、私にはこれが適切かどうか判断できないんですが、どうす
> るのが良いと思いますか? みなさま。

ちょっと書き直してテストしていたら、rb_thread_fd_close()が書き
込みに対して効いていないのに気づきました。

$ ruby -e 'f = open("|sleep 100", "r+"); Thread.start{sleep 3;f.close}; loop{f.puts("x")}'
-e:1:in `write': Interrupt      from -e:1:in `puts'
        from -e:1
        from -e:1:in `loop'
        from -e:1

まだrb_thread_schedule()でのEBADFの対処がまずいような気もします
が、こんなところで。

* IO#close,IO#reopen: 書き込み中のスレッドにも例外を上げる
* IO#reopen: 例外を上げるのは、元のdescriptorを閉じた後
* IO#reopen: stdin,stdout,stderrの場合、FILE*を使い回す


Index: eval.c
===================================================================
RCS file: /cvs/ruby/src/ruby/eval.c,v
retrieving revision 1.438
diff -u -2 -p -r1.438 eval.c
--- eval.c	21 May 2003 08:48:02 -0000	1.438
+++ eval.c	21 May 2003 10:35:19 -0000
@@ -8171,5 +8171,9 @@ rb_thread_fd_close(fd)
 
     FOREACH_THREAD(th) {
-	if ((th->wait_for & WAIT_FD) && fd == th->fd) {
+	if (((th->wait_for & WAIT_FD) && fd == th->fd) ||
+	    ((th->wait_for & WAIT_SELECT) && (fd < th->fd) &&
+	     (FD_ISSET(fd, &th->readfds) ||
+	      FD_ISSET(fd, &th->writefds) ||
+	      FD_ISSET(fd, &th->exceptfds)))) {
 	    VALUE exc = rb_exc_new2(rb_eIOError, "stream closed");
 	    rb_thread_raise(1, &exc, th);
Index: io.c
===================================================================
RCS file: /cvs/ruby/src/ruby/io.c,v
retrieving revision 1.207
diff -u -2 -p -r1.207 io.c
--- io.c	19 May 2003 06:27:06 -0000	1.207
+++ io.c	21 May 2003 03:46:46 -0000
@@ -711,5 +711,5 @@ rb_io_fread(ptr, len, f)
 		  case EWOULDBLOCK:
 #endif
-                   if (len - n >= 0) {
+		    if (len - n >= 0) {
 			clearerr(f);
 			return len - n;
@@ -1386,13 +1386,20 @@ rb_io_close(io)
 {
     OpenFile *fptr;
-    int fd;
+    int fd, fd2;
 
     fptr = RFILE(io)->fptr;
     if (!fptr) return Qnil;
-    if (!fptr->f && !fptr->f2) return Qnil;
+    if (fptr->f2) {
+	fd2 = fileno(fptr->f2);
+    }
+    else {
+	if (!fptr->f) return Qnil;
+	fd2 = -1;
+    }
 
     fd = fileno(fptr->f);
     rb_io_fptr_cleanup(fptr, Qfalse);
     rb_thread_fd_close(fd);
+    if (fd2 >= 0) rb_thread_fd_close(fd2);
 
     if (fptr->pid) {
@@ -1954,5 +1961,4 @@ pipe_del_fptr(fptr)
 }
 
-#if defined (_WIN32) || defined(DJGPP) || defined(__CYGWIN__) || defined(__human68k__) || defined(__VMS)
 static void
 pipe_atexit _((void))
@@ -1967,5 +1973,4 @@ pipe_atexit _((void))
     }
 }
-#endif
 
 static void pipe_finalize _((OpenFile *fptr,int));
@@ -2352,5 +2319,7 @@ io_reopen(io, nfile)
 	io_fflush(orig->f, orig);
     }
-    rb_thread_fd_close(fileno(fptr->f));
+    if (fptr->mode & FMODE_WRITABLE) {
+	io_fflush(GetWriteFile(fptr), fptr);
+    }
 
     /* copy OpenFile structure */
@@ -2365,5 +2334,5 @@ io_reopen(io, nfile)
     mode = rb_io_mode_string(fptr);
     fd = fileno(fptr->f);
-    if (fd < 3) {
+    if (fptr->f == stdin || fptr->f == stdout || fptr->f == stderr) {
 	clearerr(fptr->f);
 	/* need to keep stdio objects */
@@ -2377,4 +2346,5 @@ io_reopen(io, nfile)
 	fptr->f = rb_fdopen(fd, mode);
     }
+    rb_thread_fd_close(fd);
     if ((orig->mode & FMODE_READABLE) && pos >= 0) {
 	io_seek(fptr, pos, SEEK_SET);
@@ -2382,7 +2352,8 @@ io_reopen(io, nfile)
     }
 
-    if (fptr->f2) {
+    if (fptr->f2 && fd != fileno(fptr->f2)) {
 	fd = fileno(fptr->f2);
 	fclose(fptr->f2);
+	rb_thread_fd_close(fd);
 	if (orig->f2) {
 	    if (dup2(fileno(orig->f2), fd) < 0)


-- 
--- 僕の前にBugはない。
--- 僕の後ろにBugはできる。
    中田 伸悦

In This Thread