From 2cb83fdd7ea4e76d4b1c830a97480521cc405625 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 28 Feb 2014 12:55:30 -0800 Subject: [PATCH] std: Switch stdout/stderr to buffered by default Similarly to #12422 which made stdin buffered by default, this commit makes the output streams also buffered by default. Now that buffered writers will flush their contents when they are dropped, I don't believe that there's no reason why the output shouldn't be buffered by default, which is what you want in 90% of cases. As with stdin, there are new stdout_raw() and stderr_raw() functions to get unbuffered streams to stdout/stderr. --- src/librustc/lib.rs | 3 +-- src/libstd/fmt/mod.rs | 4 +-- src/libstd/io/stdio.rs | 34 ++++++++++++++++++++++---- src/libstd/logging.rs | 4 +-- src/libsyntax/diagnostic.rs | 4 +-- src/libtest/lib.rs | 4 +-- src/test/bench/shootout-fasta-redux.rs | 4 +-- src/test/bench/shootout-fasta.rs | 2 +- src/test/bench/shootout-mandelbrot.rs | 3 +-- 9 files changed, 41 insertions(+), 21 deletions(-) diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index c5b4147f090c8..2e3b9be5f9b86 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -297,8 +297,7 @@ pub fn run_compiler(args: &[~str]) { match input { d::FileInput(ref ifile) => { let mut stdout = io::stdout(); - d::list_metadata(sess, &(*ifile), - &mut stdout as &mut io::Writer).unwrap(); + d::list_metadata(sess, &(*ifile), &mut stdout).unwrap(); } d::StrInput(_) => { d::early_error("can not list metadata for stdin"); diff --git a/src/libstd/fmt/mod.rs b/src/libstd/fmt/mod.rs index bdc1aa75c9419..67e2fc00b8b49 100644 --- a/src/libstd/fmt/mod.rs +++ b/src/libstd/fmt/mod.rs @@ -654,8 +654,8 @@ uniform_fn_call_workaround! { /// use std::fmt; /// use std::io; /// -/// let w = &mut io::stdout() as &mut io::Writer; -/// format_args!(|args| { fmt::write(w, args); }, "Hello, {}!", "world"); +/// let mut w = io::stdout(); +/// format_args!(|args| { fmt::write(&mut w, args); }, "Hello, {}!", "world"); /// ``` pub fn write(output: &mut io::Writer, args: &Arguments) -> Result { unsafe { write_unsafe(output, args.fmt, args.args) } diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index b125fd69c5aec..241f3d23c6b74 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -90,6 +90,12 @@ fn src(fd: libc::c_int, readable: bool, f: |StdSource| -> T) -> T { /// buffered access is not desired, the `stdin_raw` function is provided to /// provided unbuffered access to stdin. /// +/// Care should be taken when creating multiple handles to the stdin of a +/// process. Beause this is a buffered reader by default, it's possible for +/// pending input to be unconsumed in one reader and unavailable to other +/// readers. It is recommended that only one handle at a time is created for the +/// stdin of a process. +/// /// See `stdout()` for more notes about this function. pub fn stdin() -> BufferedReader { BufferedReader::new(stdin_raw()) @@ -104,20 +110,38 @@ pub fn stdin_raw() -> StdReader { src(libc::STDIN_FILENO, true, |src| StdReader { inner: src }) } -/// Creates a new non-blocking handle to the stdout of the current process. +/// Creates a line-buffered handle to the stdout of the current process. /// /// Note that this is a fairly expensive operation in that at least one memory /// allocation is performed. Additionally, this must be called from a runtime /// task context because the stream returned will be a non-blocking object using /// the local scheduler to perform the I/O. -pub fn stdout() -> StdWriter { +/// +/// Care should be taken when creating multiple handles to an output stream for +/// a single process. While usage is still safe, the output may be surprising if +/// no synchronization is performed to ensure a sane output. +pub fn stdout() -> LineBufferedWriter { + LineBufferedWriter::new(stdout_raw()) +} + +/// Creates an unbuffered handle to the stdout of the current process +/// +/// See notes in `stdout()` for more information. +pub fn stdout_raw() -> StdWriter { src(libc::STDOUT_FILENO, false, |src| StdWriter { inner: src }) } -/// Creates a new non-blocking handle to the stderr of the current process. +/// Creates a line-buffered handle to the stderr of the current process. /// /// See `stdout()` for notes about this function. -pub fn stderr() -> StdWriter { +pub fn stderr() -> LineBufferedWriter { + LineBufferedWriter::new(stderr_raw()) +} + +/// Creates an unbuffered handle to the stderr of the current process +/// +/// See notes in `stdout()` for more information. +pub fn stderr_raw() -> StdWriter { src(libc::STDERR_FILENO, false, |src| StdWriter { inner: src }) } @@ -182,7 +206,7 @@ fn with_task_stdout(f: |&mut Writer| -> IoResult<()> ) { Local::put(task); if my_stdout.is_none() { - my_stdout = Some(~LineBufferedWriter::new(stdout()) as ~Writer); + my_stdout = Some(~stdout() as ~Writer); } let ret = f(*my_stdout.get_mut_ref()); diff --git a/src/libstd/logging.rs b/src/libstd/logging.rs index 39a62a80cfcf9..2271a7c23808f 100644 --- a/src/libstd/logging.rs +++ b/src/libstd/logging.rs @@ -166,9 +166,7 @@ pub fn log(level: u32, args: &fmt::Arguments) { }; if logger.is_none() { - logger = Some(~DefaultLogger { - handle: LineBufferedWriter::new(io::stderr()), - } as ~Logger); + logger = Some(~DefaultLogger { handle: io::stderr(), } as ~Logger); } logger.get_mut_ref().log(level, args); diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs index affeb86f782a3..cb7034a375dd0 100644 --- a/src/libsyntax/diagnostic.rs +++ b/src/libsyntax/diagnostic.rs @@ -227,8 +227,8 @@ enum Destination { impl EmitterWriter { pub fn stderr() -> EmitterWriter { let stderr = io::stderr(); - if stderr.isatty() { - let dst = match term::Terminal::new(stderr) { + if stderr.get_ref().isatty() { + let dst = match term::Terminal::new(stderr.unwrap()) { Ok(t) => Terminal(t), Err(..) => Raw(~io::stderr()), }; diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 3162fe02a0fac..0e062003053c0 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -415,8 +415,8 @@ impl ConsoleTestState { Some(ref path) => Some(try!(File::create(path))), None => None }; - let out = match term::Terminal::new(io::stdout()) { - Err(_) => Raw(io::stdout()), + let out = match term::Terminal::new(io::stdio::stdout_raw()) { + Err(_) => Raw(io::stdio::stdout_raw()), Ok(t) => Pretty(t) }; Ok(ConsoleTestState { diff --git a/src/test/bench/shootout-fasta-redux.rs b/src/test/bench/shootout-fasta-redux.rs index f38acf0457d3c..532bc714d3165 100644 --- a/src/test/bench/shootout-fasta-redux.rs +++ b/src/test/bench/shootout-fasta-redux.rs @@ -9,7 +9,7 @@ // except according to those terms. use std::cmp::min; -use std::io::{stdout, BufferedWriter, IoResult}; +use std::io::{stdout, IoResult}; use std::os; use std::vec::bytes::copy_memory; use std::vec; @@ -183,7 +183,7 @@ fn main() { 5 }; - let mut out = BufferedWriter::new(stdout()); + let mut out = stdout(); out.write_line(">ONE Homo sapiens alu").unwrap(); { diff --git a/src/test/bench/shootout-fasta.rs b/src/test/bench/shootout-fasta.rs index f0c3517a0b88e..ae0bd069c906d 100644 --- a/src/test/bench/shootout-fasta.rs +++ b/src/test/bench/shootout-fasta.rs @@ -117,6 +117,6 @@ fn main() { let mut file = BufferedWriter::new(File::create(&Path::new("./shootout-fasta.data"))); run(&mut file); } else { - run(&mut BufferedWriter::new(io::stdout())); + run(&mut io::stdout()); } } diff --git a/src/test/bench/shootout-mandelbrot.rs b/src/test/bench/shootout-mandelbrot.rs index 6f4a4c43b0395..2bff20d52f88f 100644 --- a/src/test/bench/shootout-mandelbrot.rs +++ b/src/test/bench/shootout-mandelbrot.rs @@ -9,7 +9,6 @@ // except according to those terms. use std::io; -use std::io::BufferedWriter; struct DummyWriter; impl Writer for DummyWriter { @@ -27,7 +26,7 @@ fn main() { (1000, ~DummyWriter as ~Writer) } else { (from_str(args[1]).unwrap(), - ~BufferedWriter::new(std::io::stdout()) as ~Writer) + ~std::io::stdout() as ~Writer) }; let h = w; let mut byte_acc = 0u8;