e$B2~?4$7$Fe(B duplex e$B$Je(B IO.popen e$B$Ge(B socketpair
e$B$r;H$&$N$O$d$a$h$&e(B
e$B$H;W$&$N$G$9$,!"$I$&$G$7$g$&$+!#e(B
e$B$H$$$&$N$O!"5/F0$7$?%W%m%0%i%$,I8=
=PNO$r%/%m!<%:$7$?$3$H$re(B
e$B?F$,8!CN$G$-$J$$$+$i$G$9!#e(B
% cat close-stdout.c
#include <unistd.h>
int main(int argc, char **argv)
{
close(1);
sleep(2);
return 0;
}
% gcc -o close-stdout close-stdout.c
e$B$H$$$&$h$&$J!“I8==PNO$rB(:B$K%/%m!<%:$7!"$=$N8e$Ge(B 2e$BIC?2$k!"e(B e$B$H$$$&%W%m%0%i%
$,$”$C$?$H$7$^$9!#e(B
e$B$3$l$Oe(B 1.8 e$B$G$O<!$N$h$&$KB(:B$K=*$o$j$^$9!#e(B
% time ruby-1.8 -ve ‘p IO.popen("./close-stdout", “r+”).read’
ruby 1.8.6 (2007-11-09 patchlevel 5000) [i686-linux]
“”
ruby-1.8 -ve ‘p IO.popen("./close-stdout", “r+”).read’ 0.00s user 0.00s
system 71% cpu 0.006 total
e$B$7$+$7e(B 1.9 e$B$G$Oe(B 2e$BIC$+$+$j$^$9!#e(B
% time ./ruby -ve ‘p IO.popen("./close-stdout", “r+”).read’
ruby 1.9.0 (2007-11-10 patchlevel 0) [i686-linux]
“”
./ruby -ve ‘p IO.popen("./close-stdout", “r+”).read’ 0.01s user 0.00s
system 0% cpu 2.020 total
e$B$3$l$Oe(B socketpair e$B$Ge(B EOF e$B$rEA$($k$?$a$K$Oe(B half close
e$B$7$J$$e(B
e$B$H$$$1$J$/$F!"$=$N$?$a$K$Oe(B shutdown e$B$9$kI,MW$,$"$k$1$l$I5/F0e(B
e$B$5$l$?B&$N%W%m%0%i%`$O$=$s$J$3$H$OCN$C$?$3$H$G$OL5$$!"$H$$$&e(B
e$B$N$,LdBj$G$9!#e(B
e$B$3$l$Oe(B socketpair e$B$r;H$&8B$j$O2r7h$G$-$J$$$N$G!"e(B1.8
e$B$N$h$&$Ke(B
e$B%Q%$%W$re(B 2e$BK;H$C$F!“IaDL$Ke(B close
e$B$9$l$P?F$,$=$l$r8!CN$G$-$ke(B
e$B$N$,E,@Z$G$”$k$H$$$&7kO@$K;j$j$^$7$?!#e(B
e$B$J$*!“e(BIO e$B$R$H$D$Ke(B 2e$B$D$Ne(B fd e$B$,F~$C$F$$$Fe(B fcntl
e$BEy$Ne(B fd e$B$NA:ne(B e$B$K;Y>c$rMh$9$H$$$&LdBj$O!"=q$-9~$_B&$Ne(B fd e$B$K$bFHN)$7$?e(B IO e$B%*e(B e$B%V%8%'%/%H$r:n$j!"$=$l$re(B @write_io e$B$H$$$&%$%s%9%?%s%9JQ?t$Ge(B e$B;2>H2DG=$K$9$k$3$H$K$h$j!"A
:nIT2DG=$G$O$J$$$h$&$K$7$F$”$j$^e(B
e$B$9!#e(B
Index: include/ruby/intern.h
— include/ruby/intern.h (e$B%j%S%8%g%se(B 13873)
+++ include/ruby/intern.h (e$B:n6H%3%T!<e(B)
@@ -353,6 +353,7 @@
VALUE rb_io_print(int, VALUE*, VALUE);
VALUE rb_io_puts(int, VALUE*, VALUE);
VALUE rb_io_fdopen(int, int, const char*);
+VALUE rb_io_get_write_io(VALUE);
VALUE rb_file_open(const char*, const char*);
VALUE rb_gets(void);
void rb_write_error(const char*);
Index: include/ruby/io.h
— include/ruby/io.h (e$B%j%S%8%g%se(B 13873)
+++ include/ruby/io.h (e$B:n6H%3%T!<e(B)
@@ -45,6 +45,7 @@
int rbuf_off;
int rbuf_len;
int rbuf_capa;
- int has_write_io;
rb_encoding *enc;
} rb_io_t;
@@ -88,8 +89,12 @@
fp->rbuf_off = 0;
fp->rbuf_len = 0;
fp->rbuf_capa = 0;\
- fp->has_write_io = 0;
} while (0)
+#define GetReadIO(io) (io)
+#define GetWriteIO(io) rb_io_get_write_io(io)
+
FILE *rb_io_stdio_file(rb_io_t *fptr);
FILE rb_fopen(const char, const char*);
Index: io.c
— io.c (e$B%j%S%8%g%se(B 13873)
+++ io.c (e$B:n6H%3%T!<e(B)
@@ -246,6 +246,21 @@
return rb_check_convert_type(io, T_FILE, “IO”, “to_io”);
}
+VALUE
+rb_io_get_write_io(VALUE io)
+{
- VALUE write_io;
- if (RFILE(io)->fptr->has_write_io) {
-
write_io = rb_ivar_get(io, rb_intern("@write_io"));
-
if (RTEST(write_io)) {
-
write_io = rb_io_get_io(write_io);
-
if (!RFILE(write_io)->fptr->has_write_io)
-
return write_io;
-
}
- }
- return io;
+}
/*
- call-seq:
-
IO.try_convert(obj) -> io or nil
@@ -676,6 +691,7 @@
VALUE tmp;
rb_secure(4);
-
io = GetWriteIO(io);
str = rb_obj_as_string(str);
tmp = rb_io_check_io(io);
if (NIL_P(tmp)) {
@@ -748,6 +764,7 @@
return rb_funcall(io, id_flush, 0);
} -
io = GetWriteIO(io);
GetOpenFile(io, fptr);if (fptr->mode & FMODE_WRITABLE) {
@@ -982,6 +999,7 @@
{
rb_io_t *fptr; -
io = GetWriteIO(io);
GetOpenFile(io, fptr);
return (fptr->mode & FMODE_SYNC) ? Qtrue : Qfalse;
}
@@ -1006,6 +1024,7 @@
{
rb_io_t *fptr; -
io = GetWriteIO(io);
GetOpenFile(io, fptr);
if (RTEST(mode)) {
fptr->mode |= FMODE_SYNC;
@@ -1034,6 +1053,7 @@
#ifdef HAVE_FSYNC
rb_io_t *fptr; -
io = GetWriteIO(io);
GetOpenFile(io, fptr);io_fflush(fptr);
@@ -1464,6 +1484,7 @@
if (TYPE(str) != T_STRING)
str = rb_obj_as_string(str); -
io = GetWriteIO(io);
GetOpenFile(io, fptr);
rb_io_check_writable(fptr);
@@ -2348,7 +2369,17 @@
{
rb_io_t *fptr;
int fd;
-
VALUE write_io;
-
rb_io_t *write_fptr;
-
write_io = GetWriteIO(io);
-
if (io != write_io) {
-
write_fptr = RFILE(write_io)->fptr;
-
if (write_fptr && 0 <= write_fptr->fd) {
-
rb_io_fptr_cleanup(write_fptr, Qtrue);
-
}
-
}
-
fptr = RFILE(io)->fptr;
if (!fptr) return Qnil;
if (fptr->fd < 0) return Qnil;
@@ -2425,7 +2456,17 @@
rb_io_closed(VALUE io)
{
rb_io_t *fptr; -
VALUE write_io;
-
rb_io_t *write_fptr;
-
write_io = GetWriteIO(io);
-
if (io != write_io) {
-
write_fptr = RFILE(write_io)->fptr;
-
if (write_fptr && 0 <= write_fptr->fd) {
-
return Qfalse;
-
}
-
}
-
fptr = RFILE(io)->fptr;
rb_io_check_initialized(fptr);
return 0 <= fptr->fd ? Qfalse : Qtrue;
@@ -2453,6 +2494,7 @@
rb_io_close_read(VALUE io)
{
rb_io_t *fptr; -
VALUE write_io;
if (rb_safe_level() >= 4 && !OBJ_TAINTED(io)) {
rb_raise(rb_eSecurityError, “Insecure: can’t close”);
@@ -2469,6 +2511,13 @@
return rb_io_close(io);
return Qnil;
} -
write_io = GetWriteIO(io);
-
if (io != write_io) {
-
fptr_finalize(fptr, Qfalse);
-
return Qnil;
-
}
-
if (fptr->mode & FMODE_WRITABLE) {
rb_raise(rb_eIOError, “closing non-duplex IO for reading”);
}
@@ -2498,6 +2547,8 @@
rb_io_close_write(VALUE io)
{
rb_io_t *fptr; -
VALUE write_io;
-
rb_io_t *write_fptr;
if (rb_safe_level() >= 4 && !OBJ_TAINTED(io)) {
rb_raise(rb_eSecurityError, “Insecure: can’t close”);
@@ -2515,6 +2566,13 @@
return Qnil;
} -
write_io = GetWriteIO(io);
-
if (io != write_io) {
-
write_fptr = RFILE(write_io)->fptr;
-
fptr_finalize(write_fptr, Qfalse);
-
return Qnil;
-
}
-
if (fptr->mode & FMODE_READABLE) {
rb_raise(rb_eIOError, “closing non-duplex IO for writing”);
}
@@ -2582,6 +2640,7 @@
if (TYPE(str) != T_STRING)
str = rb_obj_as_string(str); -
io = GetWriteIO(io);
GetOpenFile(io, fptr);
rb_io_check_writable(fptr);
@@ -2666,15 +2725,6 @@
return str;
}
-/*
-
- call-seq:
-
-
ios.binmode => ios
-
-
-
- Puts ios into binary mode. This is useful only in
-
- MS-DOS/Windows environments. Once a stream is in binary mode, it
-
- cannot be reset to nonbinary mode.
- */
VALUE
rb_io_binmode(VALUE io)
{
@@ -2693,6 +2743,30 @@
return io;
}
+/*
-
- call-seq:
-
-
ios.binmode => ios
-
-
-
- Puts ios into binary mode. This is useful only in
-
- MS-DOS/Windows environments. Once a stream is in binary mode, it
-
- cannot be reset to nonbinary mode.
- */
+static VALUE
+rb_io_binmode_m(VALUE io)
+{
+#if defined(_WIN32) || defined(DJGPP) || defined(CYGWIN) ||
defined(human68k) || defined(EMX)
- VALUE write_io;
- rb_io_binmode(io);
- write_io = GetWriteIO(io);
- if (write_io != io)
-
rb_io_binmode(write_io);
+#endif
- return io;
+}
static const char*
rb_io_flags_mode(int flags)
{
@@ -3078,17 +3152,23 @@
struct rb_exec_arg exec;
int modef;
int pair[2];
- int write_pair[2];
};
static void
popen_redirect(struct popen_arg *p)
{
if ((p->modef & FMODE_READABLE) && (p->modef & FMODE_WRITABLE)) {
-
close(p->write_pair[1]);
-
if (p->write_pair[0] != 0) {
-
dup2(p->write_pair[0], 0);
-
close(p->write_pair[0]);
-
} close(p->pair[0]);
-
dup2(p->pair[1], 0);
-
dup2(p->pair[1], 1);
-
if (2 <= p->pair[1])
-
if (p->pair[1] != 1) {
-
dup2(p->pair[1], 1); close(p->pair[1]);
-
}}
else if (p->modef & FMODE_READABLE) {
close(p->pair[0]);
@@ -3132,6 +3212,8 @@
int pid = 0;
rb_io_t *fptr;
VALUE port; - rb_io_t *write_fptr;
- VALUE write_port;
#if defined(HAVE_FORK)
int status;
struct popen_arg arg;
@@ -3141,17 +3223,24 @@
#endif
FILE *fp = 0;
int fd = -1; - int write_fd = -1;
#if defined(HAVE_FORK)
arg.modef = modef;
arg.pair[0] = arg.pair[1] = -1;
- arg.write_pair[0] = arg.write_pair[1] = -1;
switch (modef & (FMODE_READABLE|FMODE_WRITABLE)) {
-#if defined(HAVE_SOCKETPAIR)
case FMODE_READABLE|FMODE_WRITABLE:
-
if (socketpair(AF_UNIX, SOCK_STREAM, 0, arg.pair) < 0)
-
if (pipe(arg.write_pair) < 0) rb_sys_fail(cmd);
-
if (pipe(arg.pair) < 0) {
-
int e = errno;
-
close(arg.write_pair[0]);
-
close(arg.write_pair[1]);
-
errno = e;
-
rb_sys_fail(cmd);
-
break;}
-#endif
case FMODE_READABLE:
if (pipe(arg.pair) < 0)
rb_sys_fail(cmd);
@@ -3187,12 +3276,18 @@
int e = errno;
close(arg.pair[0]);
close(arg.pair[1]); -
if ((modef & (FMODE_READABLE|FMODE_WRITABLE)) ==
(FMODE_READABLE|FMODE_WRITABLE)) {
-
close(arg.write_pair[0]);
-
close(arg.write_pair[1]);
-
}
errno = e;
rb_sys_fail(cmd);
}
if ((modef & FMODE_READABLE) && (modef & FMODE_WRITABLE)) {
close(arg.pair[1]);
fd = arg.pair[0]; -
close(arg.write_pair[0]);
-
write_fd = arg.write_pair[1];
}
else if (modef & FMODE_READABLE) {
close(arg.pair[1]);
@@ -3245,6 +3340,16 @@
fptr->mode = modef | FMODE_SYNC|FMODE_DUPLEX;
fptr->pid = pid; -
if (0 <= write_fd) {
-
write_port = io_alloc(rb_cIO);
-
MakeOpenFile(write_port, write_fptr);
-
write_fptr->fd = write_fd;
-
write_fptr->mode = (modef & ~FMODE_READABLE)|
FMODE_SYNC|FMODE_DUPLEX;
-
fptr->mode &= ~FMODE_WRITABLE;
-
rb_ivar_set(port, rb_intern("@write_io"), write_port);
-
fptr->has_write_io = 1;
- }
#if defined (CYGWIN) || !defined(HAVE_FORK)
fptr->finalize = pipe_finalize;
pipe_add_fptr(fptr);
@@ -3770,6 +3875,7 @@
{
rb_io_t *fptr, *orig;
int fd;
-
VALUE write_io;
io = rb_io_get_io(io);
if (dest == io) return dest;
@@ -3792,6 +3898,13 @@
rb_io_binmode(dest);
} -
write_io = GetWriteIO(io);
-
if (io != write_io) {
-
write_io = rb_obj_dup(write_io);
-
rb_ivar_set(dest, rb_intern("@write_io"), write_io);
-
fptr->has_write_io = 1;
-
}
-
return dest;
}
@@ -4732,7 +4845,8 @@
if (!NIL_P(write)) {
Check_Type(write, T_ARRAY);
for (i=0; i<RARRAY_LEN(write); i++) {
-
GetOpenFile(rb_io_get_io(RARRAY_PTR(write)[i]), fptr);
-
VALUE write_io =
GetWriteIO(rb_io_get_io(RARRAY_PTR(write)[i]));
-
}GetOpenFile(write_io, fptr); rb_fd_set(fptr->fd, &fds[1]); if (max < fptr->fd) max = fptr->fd;
@@ -4744,9 +4858,16 @@
if (!NIL_P(except)) {
Check_Type(except, T_ARRAY);
for (i=0; i<RARRAY_LEN(except); i++) {
-
GetOpenFile(rb_io_get_io(RARRAY_PTR(except)[i]), fptr);
-
VALUE io = rb_io_get_io(RARRAY_PTR(except)[i]);
-
VALUE write_io = GetWriteIO(io);
-
GetOpenFile(io, fptr); rb_fd_set(fptr->fd, &fds[2]); if (max < fptr->fd) max = fptr->fd;
-
if (io != write_io) {
-
GetOpenFile(write_io, fptr);
-
rb_fd_set(fptr->fd, &fds[2]);
-
if (max < fptr->fd) max = fptr->fd;
-
}}
ep = rb_fd_ptr(&fds[2]);
}
@@ -4771,10 +4892,11 @@
if (rp) {
list = RARRAY_PTR(res)[0];
for (i=0; i< RARRAY_LEN(read); i++) {
- GetOpenFile(rb_io_get_io(RARRAY_PTR(read)[i]), fptr);
-
VALUE io = rb_io_get_io(rb_ary_entry(read, i));
- GetOpenFile(io, fptr);
if (rb_fd_isset(fptr->fd, &fds[0]) ||
rb_fd_isset(fptr->fd, &fds[3])) {
-
rb_ary_push(list, rb_ary_entry(read, i));
-
}rb_ary_push(list, io);
}
}
@@ -4782,9 +4904,11 @@
if (wp) {
list = RARRAY_PTR(res)[1];
for (i=0; i< RARRAY_LEN(write); i++) {
- GetOpenFile(rb_io_get_io(RARRAY_PTR(write)[i]), fptr);
-
VALUE io = rb_io_get_io(rb_ary_entry(write, i));
-
VALUE write_io = GetWriteIO(io);
- GetOpenFile(write_io, fptr);
if (rb_fd_isset(fptr->fd, &fds[1])) {
-
rb_ary_push(list, rb_ary_entry(write, i));
-
}rb_ary_push(list, io);
}
}
@@ -4792,10 +4916,18 @@
if (ep) {
list = RARRAY_PTR(res)[2];
for (i=0; i< RARRAY_LEN(except); i++) {
- GetOpenFile(rb_io_get_io(RARRAY_PTR(except)[i]), fptr);
-
VALUE io = rb_io_get_io(rb_ary_entry(write, i));
-
VALUE write_io = GetWriteIO(io);
- GetOpenFile(io, fptr);
if (rb_fd_isset(fptr->fd, &fds[2])) {
-
rb_ary_push(list, rb_ary_entry(except, i));
-
rb_ary_push(list, io);
}
-
else if (io != write_io) {
-
GetOpenFile(write_io, fptr);
-
if (rb_fd_isset(fptr->fd, &fds[2])) {
-
rb_ary_push(list, io);
-
}
-
} }
}
}
@@ -5906,7 +6038,7 @@rb_define_method(rb_cIO, “isatty”, rb_io_isatty, 0);
rb_define_method(rb_cIO, “tty?”, rb_io_isatty, 0);
- rb_define_method(rb_cIO, “binmode”, rb_io_binmode, 0);
-
rb_define_method(rb_cIO, “binmode”, rb_io_binmode_m, 0);
rb_define_method(rb_cIO, “sysseek”, rb_io_sysseek, -1);rb_define_method(rb_cIO, “ioctl”, rb_io_ioctl, -1);
e$B$J$!"e(BWindows e$B$K$D$$$F$O$$$A$$&e(B binmode
e$B$@$1$O=hCV$7$?$D$be(B
e$B$j$G$9$,!"$&$^$/$$$C$F$$$J$$$+$b$7$l$^$;$s!#e(B