From: nobu.nakada@... Date: 2003-05-22T02:20:51+09:00 Subject: [ruby-dev:20269] Re: pipe reopen なかだです。 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はできる。 中田 伸悦