aboutsummaryrefslogtreecommitdiff
path: root/ctr-std/src/io/stdio.rs
diff options
context:
space:
mode:
authorFenrir <[email protected]>2018-01-21 14:06:28 -0700
committerFenrirWolf <[email protected]>2018-01-21 19:16:33 -0700
commit23be3f4885688e5e0011005e2295c75168854c0a (patch)
treedd0850f9c73c489e114a761d5c0757f3dbec3a65 /ctr-std/src/io/stdio.rs
parentUpdate CI for Rust nightly-2017-12-01 + other fixes (diff)
downloadarchived-ctru-rs-23be3f4885688e5e0011005e2295c75168854c0a.tar.xz
archived-ctru-rs-23be3f4885688e5e0011005e2295c75168854c0a.zip
Recreate ctr-std from latest nightly
Diffstat (limited to 'ctr-std/src/io/stdio.rs')
-rw-r--r--ctr-std/src/io/stdio.rs90
1 files changed, 52 insertions, 38 deletions
diff --git a/ctr-std/src/io/stdio.rs b/ctr-std/src/io/stdio.rs
index e16e801..831688b 100644
--- a/ctr-std/src/io/stdio.rs
+++ b/ctr-std/src/io/stdio.rs
@@ -13,11 +13,11 @@ use io::prelude::*;
use cell::RefCell;
use fmt;
use io::lazy::Lazy;
-use io::{self, BufReader, LineWriter};
+use io::{self, Initializer, BufReader, LineWriter};
use sync::{Arc, Mutex, MutexGuard};
use sys::stdio;
use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
-use thread::LocalKeyState;
+use thread::{LocalKey, LocalKeyState};
/// Stdout used by print! and println! macros
thread_local! {
@@ -75,8 +75,10 @@ fn stderr_raw() -> io::Result<StderrRaw> { stdio::Stderr::new().map(StderrRaw) }
impl Read for StdinRaw {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.0.read(buf) }
- fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
- self.0.read_to_end(buf)
+
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::nop()
}
}
impl Write for StdoutRaw {
@@ -116,19 +118,11 @@ impl<R: io::Read> io::Read for Maybe<R> {
Maybe::Fake => Ok(0)
}
}
- fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
- match *self {
- Maybe::Real(ref mut r) => handle_ebadf(r.read_to_end(buf), 0),
- Maybe::Fake => Ok(0)
- }
- }
}
fn handle_ebadf<T>(r: io::Result<T>, default: T) -> io::Result<T> {
- use sys::stdio::EBADF_ERR;
-
match r {
- Err(ref e) if e.raw_os_error() == Some(EBADF_ERR) => Ok(default),
+ Err(ref e) if stdio::is_ebadf(e) => Ok(default),
r => r
}
}
@@ -294,6 +288,10 @@ impl Read for Stdin {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.lock().read(buf)
}
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::nop()
+ }
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
self.lock().read_to_end(buf)
}
@@ -310,8 +308,9 @@ impl<'a> Read for StdinLock<'a> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.inner.read(buf)
}
- fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
- self.inner.read_to_end(buf)
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::nop()
}
}
@@ -332,11 +331,11 @@ impl<'a> fmt::Debug for StdinLock<'a> {
///
/// Each handle shares a global buffer of data to be written to the standard
/// output stream. Access is also synchronized via a lock and explicit control
-/// over locking is available via the [`lock()`] method.
+/// over locking is available via the [`lock`] method.
///
/// Created by the [`io::stdout`] method.
///
-/// [`lock()`]: #method.lock
+/// [`lock`]: #method.lock
/// [`io::stdout`]: fn.stdout.html
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Stdout {
@@ -659,41 +658,56 @@ pub fn set_print(sink: Option<Box<Write + Send>>) -> Option<Box<Write + Send>> {
})
}
-#[unstable(feature = "print",
- reason = "implementation detail which may disappear or be replaced at any time",
- issue = "0")]
-#[doc(hidden)]
-pub fn _print(args: fmt::Arguments) {
- // As an implementation of the `println!` macro, we want to try our best to
- // not panic wherever possible and get the output somewhere. There are
- // currently two possible vectors for panics we take care of here:
- //
- // 1. If the TLS key for the local stdout has been destroyed, accessing it
- // would cause a panic. Note that we just lump in the uninitialized case
- // here for convenience, we're not trying to avoid a panic.
- // 2. If the local stdout is currently in use (e.g. we're in the middle of
- // already printing) then accessing again would cause a panic.
- //
- // If, however, the actual I/O causes an error, we do indeed panic.
- let result = match LOCAL_STDOUT.state() {
+/// Write `args` to output stream `local_s` if possible, `global_s`
+/// otherwise. `label` identifies the stream in a panic message.
+///
+/// This function is used to print error messages, so it takes extra
+/// care to avoid causing a panic when `local_stream` is unusable.
+/// For instance, if the TLS key for the local stream is uninitialized
+/// or already destroyed, or if the local stream is locked by another
+/// thread, it will just fall back to the global stream.
+///
+/// However, if the actual I/O causes an error, this function does panic.
+fn print_to<T>(args: fmt::Arguments,
+ local_s: &'static LocalKey<RefCell<Option<Box<Write+Send>>>>,
+ global_s: fn() -> T,
+ label: &str) where T: Write {
+ let result = match local_s.state() {
LocalKeyState::Uninitialized |
- LocalKeyState::Destroyed => stdout().write_fmt(args),
+ LocalKeyState::Destroyed => global_s().write_fmt(args),
LocalKeyState::Valid => {
- LOCAL_STDOUT.with(|s| {
+ local_s.with(|s| {
if let Ok(mut borrowed) = s.try_borrow_mut() {
if let Some(w) = borrowed.as_mut() {
return w.write_fmt(args);
}
}
- stdout().write_fmt(args)
+ global_s().write_fmt(args)
})
}
};
if let Err(e) = result {
- panic!("failed printing to stdout: {}", e);
+ panic!("failed printing to {}: {}", label, e);
}
}
+#[unstable(feature = "print_internals",
+ reason = "implementation detail which may disappear or be replaced at any time",
+ issue = "0")]
+#[doc(hidden)]
+pub fn _print(args: fmt::Arguments) {
+ print_to(args, &LOCAL_STDOUT, stdout, "stdout");
+}
+
+#[unstable(feature = "print_internals",
+ reason = "implementation detail which may disappear or be replaced at any time",
+ issue = "0")]
+#[doc(hidden)]
+pub fn _eprint(args: fmt::Arguments) {
+ use panicking::LOCAL_STDERR;
+ print_to(args, &LOCAL_STDERR, stderr, "stderr");
+}
+
#[cfg(test)]
mod tests {
use thread;