Skip to content

Commit cd4ebab

Browse files
committed
Don't dup the stdio file handles
It turns out that libuv no longer closes these handles when the corresponding TTY instance is closed, so there's no reason for us to dup these file handles. Yay!
1 parent b28714a commit cd4ebab

File tree

1 file changed

+27
-38
lines changed

1 file changed

+27
-38
lines changed

src/libstd/rt/io/stdio.rs

Lines changed: 27 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -31,57 +31,35 @@ use libc;
3131
use option::{Option, Some, None};
3232
use result::{Ok, Err};
3333
use rt::io::buffered::LineBufferedWriter;
34-
use rt::rtio::{IoFactory, RtioTTY, RtioFileStream, with_local_io,
35-
CloseAsynchronously};
36-
use super::{Reader, Writer, io_error, IoError, OtherIoError};
34+
use rt::rtio::{IoFactory, RtioTTY, RtioFileStream, with_local_io, DontClose};
35+
use super::{Reader, Writer, io_error, IoError, OtherIoError,
36+
standard_error, EndOfFile};
3737

38-
// And so begins the tale of acquiring a uv handle to a stdio stream on all
39-
// platforms in all situations. Our story begins by splitting the world into two
40-
// categories, windows and unix. Then one day the creators of unix said let
41-
// there be redirection! And henceforth there was redirection away from the
42-
// console for standard I/O streams.
38+
// A stdio source is frequently connected to a terminal (tty), but it's also
39+
// commonly redirected elsewhere. Right now libuv has questionable support for
40+
// using a stdio source as a tty handle when it's actually piped elsewhere, so
41+
// we have this enum for delegating what the underlying handle is being used as.
4342
//
44-
// After this day, the world split into four factions:
43+
// For now this is fine, as the only real reason for having a tty distinction is
44+
// to provide some nice extra features (like terminal dimensions), and piped
45+
// streams don't have that anyway.
4546
//
46-
// 1. Unix with stdout on a terminal.
47-
// 2. Unix with stdout redirected.
48-
// 3. Windows with stdout on a terminal.
49-
// 4. Windows with stdout redirected.
50-
//
51-
// Many years passed, and then one day the nation of libuv decided to unify this
52-
// world. After months of toiling, uv created three ideas: TTY, Pipe, File.
53-
// These three ideas propagated throughout the lands and the four great factions
54-
// decided to settle among them.
55-
//
56-
// The groups of 1, 2, and 3 all worked very hard towards the idea of TTY. Upon
57-
// doing so, they even enhanced themselves further then their Pipe/File
58-
// brethren, becoming the dominant powers.
59-
//
60-
// The group of 4, however, decided to work independently. They abandoned the
61-
// common TTY belief throughout, and even abandoned the fledgling Pipe belief.
62-
// The members of the 4th faction decided to only align themselves with File.
63-
//
64-
// tl;dr; TTY works on everything but when windows stdout is redirected, in that
65-
// case pipe also doesn't work, but magically file does!
47+
// The good news is that if stdio is on a terminal, tty always works. If stdio
48+
// is not on a terminal, then a file stream always works. Yay!
6649
enum StdSource {
6750
TTY(~RtioTTY),
6851
File(~RtioFileStream),
6952
}
7053

71-
#[fixed_stack_segment] #[inline(never)]
7254
fn src<T>(fd: libc::c_int, readable: bool, f: &fn(StdSource) -> T) -> T {
55+
// it's understood that the file descriptor passed to these functions will
56+
// *not* be closed when these I/O objects go out of scope. Otherwise, only
57+
// sadness would ensue.
7358
do with_local_io |io| {
74-
let fd = unsafe { libc::dup(fd) };
7559
match io.tty_open(fd, readable) {
7660
Ok(tty) => Some(f(TTY(tty))),
7761
Err(_) => {
78-
// It's not really that desirable if these handles are closed
79-
// synchronously, and because they're squirreled away in a task
80-
// structure the destructors will be run when the task is
81-
// attempted to get destroyed. This means that if we run a
82-
// synchronous destructor we'll attempt to do some scheduling
83-
// operations which will just result in sadness.
84-
Some(f(File(io.fs_from_raw_fd(fd, CloseAsynchronously))))
62+
Some(f(File(io.fs_from_raw_fd(fd, DontClose))))
8563
}
8664
}
8765
}.unwrap()
@@ -203,6 +181,17 @@ impl Reader for StdReader {
203181
File(ref mut file) => file.read(buf).map(|i| i as uint),
204182
};
205183
match ret {
184+
// It appears that libuv will return 0-length reads for a stdio file
185+
// handle when the file is positioned at EOF. When we open normal
186+
// files, this doesn't happen, so it probably has to do with the
187+
// handle being more of a pipe rather than something else.
188+
// Regardless, translate 0-length reads of a stdio handle to an EOF
189+
// notice rather than returning 0. Returning 0 will simply
190+
// infinitely return 0 until the end of time (not good).
191+
Ok(0) => {
192+
io_error::cond.raise(standard_error(EndOfFile));
193+
None
194+
}
206195
Ok(amt) => Some(amt as uint),
207196
Err(e) => {
208197
io_error::cond.raise(e);

0 commit comments

Comments
 (0)