Ronald Kinard
8 years ago
committed by
GitHub
12 changed files with 1303 additions and 109 deletions
@ -0,0 +1,68 @@ |
|||||||
|
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
use cell::Cell; |
||||||
|
use ptr; |
||||||
|
use sync::Arc; |
||||||
|
use sys_common; |
||||||
|
use sys_common::mutex::Mutex; |
||||||
|
|
||||||
|
pub struct Lazy<T> { |
||||||
|
lock: Mutex, |
||||||
|
ptr: Cell<*mut Arc<T>>, |
||||||
|
init: fn() -> Arc<T>, |
||||||
|
} |
||||||
|
|
||||||
|
unsafe impl<T> Sync for Lazy<T> {} |
||||||
|
|
||||||
|
impl<T: Send + Sync + 'static> Lazy<T> { |
||||||
|
pub const fn new(init: fn() -> Arc<T>) -> Lazy<T> { |
||||||
|
Lazy { |
||||||
|
lock: Mutex::new(), |
||||||
|
ptr: Cell::new(ptr::null_mut()), |
||||||
|
init: init |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn get(&'static self) -> Option<Arc<T>> { |
||||||
|
unsafe { |
||||||
|
self.lock.lock(); |
||||||
|
let ptr = self.ptr.get(); |
||||||
|
let ret = if ptr.is_null() { |
||||||
|
Some(self.init()) |
||||||
|
} else if ptr as usize == 1 { |
||||||
|
None |
||||||
|
} else { |
||||||
|
Some((*ptr).clone()) |
||||||
|
}; |
||||||
|
self.lock.unlock(); |
||||||
|
return ret |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
unsafe fn init(&'static self) -> Arc<T> { |
||||||
|
// If we successfully register an at exit handler, then we cache the
|
||||||
|
// `Arc` allocation in our own internal box (it will get deallocated by
|
||||||
|
// the at exit handler). Otherwise we just return the freshly allocated
|
||||||
|
// `Arc`.
|
||||||
|
let registered = sys_common::at_exit(move || { |
||||||
|
self.lock.lock(); |
||||||
|
let ptr = self.ptr.get(); |
||||||
|
self.ptr.set(1 as *mut _); |
||||||
|
self.lock.unlock(); |
||||||
|
drop(Box::from_raw(ptr)) |
||||||
|
}); |
||||||
|
let ret = (self.init)(); |
||||||
|
if registered.is_ok() { |
||||||
|
self.ptr.set(Box::into_raw(Box::new(ret.clone()))); |
||||||
|
} |
||||||
|
ret |
||||||
|
} |
||||||
|
} |
@ -1,33 +0,0 @@ |
|||||||
use fmt; |
|
||||||
use io::{self, Write}; |
|
||||||
|
|
||||||
// NOTE: We're just gonna use the spin mutex until we figure out how to properly
|
|
||||||
// implement mutexes with ctrulib functions
|
|
||||||
use spin::Mutex; |
|
||||||
use libc; |
|
||||||
|
|
||||||
pub static STDOUT: Mutex<StdoutRaw> = Mutex::new(StdoutRaw(())); |
|
||||||
|
|
||||||
pub struct StdoutRaw(()); |
|
||||||
|
|
||||||
#[stable(feature = "3ds", since = "1.0.0")] |
|
||||||
impl Write for StdoutRaw { |
|
||||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { |
|
||||||
unsafe { |
|
||||||
// devkitPro's version of write(2) fails if zero bytes are written,
|
|
||||||
// so let's just exit if the buffer size is zero
|
|
||||||
if buf.is_empty() { |
|
||||||
return Ok(buf.len()) |
|
||||||
} |
|
||||||
libc::write(libc::STDOUT_FILENO, buf.as_ptr() as *const _, buf.len()); |
|
||||||
Ok(buf.len()) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
fn flush(&mut self) -> io::Result<()> { Ok(()) } |
|
||||||
} |
|
||||||
|
|
||||||
#[doc(hidden)] |
|
||||||
pub fn _print(args: fmt::Arguments) { |
|
||||||
STDOUT.lock().write_fmt(args).unwrap(); |
|
||||||
} |
|
@ -0,0 +1,722 @@ |
|||||||
|
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
use io::prelude::*; |
||||||
|
|
||||||
|
use cell::RefCell; |
||||||
|
use fmt; |
||||||
|
use io::lazy::Lazy; |
||||||
|
use io::{self, BufReader, LineWriter}; |
||||||
|
use sync::{Arc, Mutex, MutexGuard}; |
||||||
|
use sys::stdio; |
||||||
|
use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; |
||||||
|
use thread::LocalKeyState; |
||||||
|
|
||||||
|
/// Stdout used by print! and println! macros
|
||||||
|
thread_local! { |
||||||
|
static LOCAL_STDOUT: RefCell<Option<Box<Write + Send>>> = { |
||||||
|
RefCell::new(None) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// A handle to a raw instance of the standard input stream of this process.
|
||||||
|
///
|
||||||
|
/// This handle is not synchronized or buffered in any fashion. Constructed via
|
||||||
|
/// the `std::io::stdio::stdin_raw` function.
|
||||||
|
struct StdinRaw(stdio::Stdin); |
||||||
|
|
||||||
|
/// A handle to a raw instance of the standard output stream of this process.
|
||||||
|
///
|
||||||
|
/// This handle is not synchronized or buffered in any fashion. Constructed via
|
||||||
|
/// the `std::io::stdio::stdout_raw` function.
|
||||||
|
struct StdoutRaw(stdio::Stdout); |
||||||
|
|
||||||
|
/// A handle to a raw instance of the standard output stream of this process.
|
||||||
|
///
|
||||||
|
/// This handle is not synchronized or buffered in any fashion. Constructed via
|
||||||
|
/// the `std::io::stdio::stderr_raw` function.
|
||||||
|
struct StderrRaw(stdio::Stderr); |
||||||
|
|
||||||
|
/// Constructs a new raw handle to the standard input of this process.
|
||||||
|
///
|
||||||
|
/// The returned handle does not interact with any other handles created nor
|
||||||
|
/// handles returned by `std::io::stdin`. Data buffered by the `std::io::stdin`
|
||||||
|
/// handles is **not** available to raw handles returned from this function.
|
||||||
|
///
|
||||||
|
/// The returned handle has no external synchronization or buffering.
|
||||||
|
fn stdin_raw() -> io::Result<StdinRaw> { stdio::Stdin::new().map(StdinRaw) } |
||||||
|
|
||||||
|
/// Constructs a new raw handle to the standard output stream of this process.
|
||||||
|
///
|
||||||
|
/// The returned handle does not interact with any other handles created nor
|
||||||
|
/// handles returned by `std::io::stdout`. Note that data is buffered by the
|
||||||
|
/// `std::io::stdout` handles so writes which happen via this raw handle may
|
||||||
|
/// appear before previous writes.
|
||||||
|
///
|
||||||
|
/// The returned handle has no external synchronization or buffering layered on
|
||||||
|
/// top.
|
||||||
|
fn stdout_raw() -> io::Result<StdoutRaw> { stdio::Stdout::new().map(StdoutRaw) } |
||||||
|
|
||||||
|
/// Constructs a new raw handle to the standard error stream of this process.
|
||||||
|
///
|
||||||
|
/// The returned handle does not interact with any other handles created nor
|
||||||
|
/// handles returned by `std::io::stderr`.
|
||||||
|
///
|
||||||
|
/// The returned handle has no external synchronization or buffering layered on
|
||||||
|
/// top.
|
||||||
|
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) |
||||||
|
} |
||||||
|
} |
||||||
|
impl Write for StdoutRaw { |
||||||
|
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { self.0.write(buf) } |
||||||
|
fn flush(&mut self) -> io::Result<()> { self.0.flush() } |
||||||
|
} |
||||||
|
impl Write for StderrRaw { |
||||||
|
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { self.0.write(buf) } |
||||||
|
fn flush(&mut self) -> io::Result<()> { self.0.flush() } |
||||||
|
} |
||||||
|
|
||||||
|
enum Maybe<T> { |
||||||
|
Real(T), |
||||||
|
Fake, |
||||||
|
} |
||||||
|
|
||||||
|
impl<W: io::Write> io::Write for Maybe<W> { |
||||||
|
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { |
||||||
|
match *self { |
||||||
|
Maybe::Real(ref mut w) => handle_ebadf(w.write(buf), buf.len()), |
||||||
|
Maybe::Fake => Ok(buf.len()) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fn flush(&mut self) -> io::Result<()> { |
||||||
|
match *self { |
||||||
|
Maybe::Real(ref mut w) => handle_ebadf(w.flush(), ()), |
||||||
|
Maybe::Fake => Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl<R: io::Read> io::Read for Maybe<R> { |
||||||
|
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { |
||||||
|
match *self { |
||||||
|
Maybe::Real(ref mut r) => handle_ebadf(r.read(buf), 0), |
||||||
|
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), |
||||||
|
r => r |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// A handle to the standard input stream of a process.
|
||||||
|
///
|
||||||
|
/// Each handle is a shared reference to a global buffer of input data to this
|
||||||
|
/// process. A handle can be `lock`'d to gain full access to [`BufRead`] methods
|
||||||
|
/// (e.g. `.lines()`). Reads to this handle are otherwise locked with respect
|
||||||
|
/// to other reads.
|
||||||
|
///
|
||||||
|
/// This handle implements the `Read` trait, but beware that concurrent reads
|
||||||
|
/// of `Stdin` must be executed with care.
|
||||||
|
///
|
||||||
|
/// Created by the [`io::stdin`] method.
|
||||||
|
///
|
||||||
|
/// [`io::stdin`]: fn.stdin.html
|
||||||
|
/// [`BufRead`]: trait.BufRead.html
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")] |
||||||
|
pub struct Stdin { |
||||||
|
inner: Arc<Mutex<BufReader<Maybe<StdinRaw>>>>, |
||||||
|
} |
||||||
|
|
||||||
|
/// A locked reference to the `Stdin` handle.
|
||||||
|
///
|
||||||
|
/// This handle implements both the [`Read`] and [`BufRead`] traits, and
|
||||||
|
/// is constructed via the [`Stdin::lock`] method.
|
||||||
|
///
|
||||||
|
/// [`Read`]: trait.Read.html
|
||||||
|
/// [`BufRead`]: trait.BufRead.html
|
||||||
|
/// [`Stdin::lock`]: struct.Stdin.html#method.lock
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")] |
||||||
|
pub struct StdinLock<'a> { |
||||||
|
inner: MutexGuard<'a, BufReader<Maybe<StdinRaw>>>, |
||||||
|
} |
||||||
|
|
||||||
|
/// Constructs a new handle to the standard input of the current process.
|
||||||
|
///
|
||||||
|
/// Each handle returned is a reference to a shared global buffer whose access
|
||||||
|
/// is synchronized via a mutex. If you need more explicit control over
|
||||||
|
/// locking, see the [`lock() method`][lock].
|
||||||
|
///
|
||||||
|
/// [lock]: struct.Stdin.html#method.lock
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// Using implicit synchronization:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::io::{self, Read};
|
||||||
|
///
|
||||||
|
/// # fn foo() -> io::Result<String> {
|
||||||
|
/// let mut buffer = String::new();
|
||||||
|
/// io::stdin().read_to_string(&mut buffer)?;
|
||||||
|
/// # Ok(buffer)
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Using explicit synchronization:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::io::{self, Read};
|
||||||
|
///
|
||||||
|
/// # fn foo() -> io::Result<String> {
|
||||||
|
/// let mut buffer = String::new();
|
||||||
|
/// let stdin = io::stdin();
|
||||||
|
/// let mut handle = stdin.lock();
|
||||||
|
///
|
||||||
|
/// handle.read_to_string(&mut buffer)?;
|
||||||
|
/// # Ok(buffer)
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")] |
||||||
|
pub fn stdin() -> Stdin { |
||||||
|
static INSTANCE: Lazy<Mutex<BufReader<Maybe<StdinRaw>>>> = Lazy::new(stdin_init); |
||||||
|
return Stdin { |
||||||
|
inner: INSTANCE.get().expect("cannot access stdin during shutdown"), |
||||||
|
}; |
||||||
|
|
||||||
|
fn stdin_init() -> Arc<Mutex<BufReader<Maybe<StdinRaw>>>> { |
||||||
|
let stdin = match stdin_raw() { |
||||||
|
Ok(stdin) => Maybe::Real(stdin), |
||||||
|
_ => Maybe::Fake |
||||||
|
}; |
||||||
|
|
||||||
|
Arc::new(Mutex::new(BufReader::with_capacity(stdio::STDIN_BUF_SIZE, stdin))) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Stdin { |
||||||
|
/// Locks this handle to the standard input stream, returning a readable
|
||||||
|
/// guard.
|
||||||
|
///
|
||||||
|
/// The lock is released when the returned lock goes out of scope. The
|
||||||
|
/// returned guard also implements the [`Read`] and [`BufRead`] traits for
|
||||||
|
/// accessing the underlying data.
|
||||||
|
///
|
||||||
|
/// [`Read`]: trait.Read.html
|
||||||
|
/// [`BufRead`]: trait.BufRead.html
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::io::{self, Read};
|
||||||
|
///
|
||||||
|
/// # fn foo() -> io::Result<String> {
|
||||||
|
/// let mut buffer = String::new();
|
||||||
|
/// let stdin = io::stdin();
|
||||||
|
/// let mut handle = stdin.lock();
|
||||||
|
///
|
||||||
|
/// handle.read_to_string(&mut buffer)?;
|
||||||
|
/// # Ok(buffer)
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")] |
||||||
|
pub fn lock(&self) -> StdinLock { |
||||||
|
StdinLock { inner: self.inner.lock().unwrap_or_else(|e| e.into_inner()) } |
||||||
|
} |
||||||
|
|
||||||
|
/// Locks this handle and reads a line of input into the specified buffer.
|
||||||
|
///
|
||||||
|
/// For detailed semantics of this method, see the documentation on
|
||||||
|
/// [`BufRead::read_line`].
|
||||||
|
///
|
||||||
|
/// [`BufRead::read_line`]: trait.BufRead.html#method.read_line
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use std::io;
|
||||||
|
///
|
||||||
|
/// let mut input = String::new();
|
||||||
|
/// match io::stdin().read_line(&mut input) {
|
||||||
|
/// Ok(n) => {
|
||||||
|
/// println!("{} bytes read", n);
|
||||||
|
/// println!("{}", input);
|
||||||
|
/// }
|
||||||
|
/// Err(error) => println!("error: {}", error),
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// You can run the example one of two ways:
|
||||||
|
///
|
||||||
|
/// - Pipe some text to it, e.g. `printf foo | path/to/executable`
|
||||||
|
/// - Give it text interactively by running the executable directly,
|
||||||
|
/// in which case it will wait for the Enter key to be pressed before
|
||||||
|
/// continuing
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")] |
||||||
|
pub fn read_line(&self, buf: &mut String) -> io::Result<usize> { |
||||||
|
self.lock().read_line(buf) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[stable(feature = "std_debug", since = "1.16.0")] |
||||||
|
impl fmt::Debug for Stdin { |
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
||||||
|
f.pad("Stdin { .. }") |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")] |
||||||
|
impl Read for Stdin { |
||||||
|
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { |
||||||
|
self.lock().read(buf) |
||||||
|
} |
||||||
|
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> { |
||||||
|
self.lock().read_to_end(buf) |
||||||
|
} |
||||||
|
fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> { |
||||||
|
self.lock().read_to_string(buf) |
||||||
|
} |
||||||
|
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { |
||||||
|
self.lock().read_exact(buf) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")] |
||||||
|
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) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")] |
||||||
|
impl<'a> BufRead for StdinLock<'a> { |
||||||
|
fn fill_buf(&mut self) -> io::Result<&[u8]> { self.inner.fill_buf() } |
||||||
|
fn consume(&mut self, n: usize) { self.inner.consume(n) } |
||||||
|
} |
||||||
|
|
||||||
|
#[stable(feature = "std_debug", since = "1.16.0")] |
||||||
|
impl<'a> fmt::Debug for StdinLock<'a> { |
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
||||||
|
f.pad("StdinLock { .. }") |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// A handle to the global standard output stream of the current process.
|
||||||
|
///
|
||||||
|
/// 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.
|
||||||
|
///
|
||||||
|
/// Created by the [`io::stdout`] method.
|
||||||
|
///
|
||||||
|
/// [`lock()`]: #method.lock
|
||||||
|
/// [`io::stdout`]: fn.stdout.html
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")] |
||||||
|
pub struct Stdout { |
||||||
|
// FIXME: this should be LineWriter or BufWriter depending on the state of
|
||||||
|
// stdout (tty or not). Note that if this is not line buffered it
|
||||||
|
// should also flush-on-panic or some form of flush-on-abort.
|
||||||
|
inner: Arc<ReentrantMutex<RefCell<LineWriter<Maybe<StdoutRaw>>>>>, |
||||||
|
} |
||||||
|
|
||||||
|
/// A locked reference to the `Stdout` handle.
|
||||||
|
///
|
||||||
|
/// This handle implements the [`Write`] trait, and is constructed via
|
||||||
|
/// the [`Stdout::lock`] method.
|
||||||
|
///
|
||||||
|
/// [`Write`]: trait.Write.html
|
||||||
|
/// [`Stdout::lock`]: struct.Stdout.html#method.lock
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")] |
||||||
|
pub struct StdoutLock<'a> { |
||||||
|
inner: ReentrantMutexGuard<'a, RefCell<LineWriter<Maybe<StdoutRaw>>>>, |
||||||
|
} |
||||||
|
|
||||||
|
/// Constructs a new handle to the standard output of the current process.
|
||||||
|
///
|
||||||
|
/// Each handle returned is a reference to a shared global buffer whose access
|
||||||
|
/// is synchronized via a mutex. If you need more explicit control over
|
||||||
|
/// locking, see the [Stdout::lock] method.
|
||||||
|
///
|
||||||
|
/// [Stdout::lock]: struct.Stdout.html#method.lock
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// Using implicit synchronization:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::io::{self, Write};
|
||||||
|
///
|
||||||
|
/// # fn foo() -> io::Result<()> {
|
||||||
|
/// io::stdout().write(b"hello world")?;
|
||||||
|
///
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Using explicit synchronization:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::io::{self, Write};
|
||||||
|
///
|
||||||
|
/// # fn foo() -> io::Result<()> {
|
||||||
|
/// let stdout = io::stdout();
|
||||||
|
/// let mut handle = stdout.lock();
|
||||||
|
///
|
||||||
|
/// handle.write(b"hello world")?;
|
||||||
|
///
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")] |
||||||
|
pub fn stdout() -> Stdout { |
||||||
|
static INSTANCE: Lazy<ReentrantMutex<RefCell<LineWriter<Maybe<StdoutRaw>>>>> |
||||||
|
= Lazy::new(stdout_init); |
||||||
|
return Stdout { |
||||||
|
inner: INSTANCE.get().expect("cannot access stdout during shutdown"), |
||||||
|
}; |
||||||
|
|
||||||
|
fn stdout_init() -> Arc<ReentrantMutex<RefCell<LineWriter<Maybe<StdoutRaw>>>>> { |
||||||
|
let stdout = match stdout_raw() { |
||||||
|
Ok(stdout) => Maybe::Real(stdout), |
||||||
|
_ => Maybe::Fake, |
||||||
|
}; |
||||||
|
Arc::new(ReentrantMutex::new(RefCell::new(LineWriter::new(stdout)))) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Stdout { |
||||||
|
/// Locks this handle to the standard output stream, returning a writable
|
||||||
|
/// guard.
|
||||||
|
///
|
||||||
|
/// The lock is released when the returned lock goes out of scope. The
|
||||||
|
/// returned guard also implements the `Write` trait for writing data.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::io::{self, Write};
|
||||||
|
///
|
||||||
|
/// # fn foo() -> io::Result<()> {
|
||||||
|
/// let stdout = io::stdout();
|
||||||
|
/// let mut handle = stdout.lock();
|
||||||
|
///
|
||||||
|
/// handle.write(b"hello world")?;
|
||||||
|
///
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")] |
||||||
|
pub fn lock(&self) -> StdoutLock { |
||||||
|
StdoutLock { inner: self.inner.lock().unwrap_or_else(|e| e.into_inner()) } |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[stable(feature = "std_debug", since = "1.16.0")] |
||||||
|
impl fmt::Debug for Stdout { |
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
||||||
|
f.pad("Stdout { .. }") |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")] |
||||||
|
impl Write for Stdout { |
||||||
|
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { |
||||||
|
self.lock().write(buf) |
||||||
|
} |
||||||
|
fn flush(&mut self) -> io::Result<()> { |
||||||
|
self.lock().flush() |
||||||
|
} |
||||||
|
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { |
||||||
|
self.lock().write_all(buf) |
||||||
|
} |
||||||
|
fn write_fmt(&mut self, args: fmt::Arguments) -> io::Result<()> { |
||||||
|
self.lock().write_fmt(args) |
||||||
|
} |
||||||
|
} |
||||||
|
#[stable(feature = "rust1", since = "1.0.0")] |
||||||
|
impl<'a> Write for StdoutLock<'a> { |
||||||
|
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { |
||||||
|
self.inner.borrow_mut().write(buf) |
||||||
|
} |
||||||
|
fn flush(&mut self) -> io::Result<()> { |
||||||
|
self.inner.borrow_mut().flush() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[stable(feature = "std_debug", since = "1.16.0")] |
||||||
|
impl<'a> fmt::Debug for StdoutLock<'a> { |
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
||||||
|
f.pad("StdoutLock { .. }") |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// A handle to the standard error stream of a process.
|
||||||
|
///
|
||||||
|
/// For more information, see the [`io::stderr`] method.
|
||||||
|
///
|
||||||
|
/// [`io::stderr`]: fn.stderr.html
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")] |
||||||
|
pub struct Stderr { |
||||||
|
inner: Arc<ReentrantMutex<RefCell<Maybe<StderrRaw>>>>, |
||||||
|
} |
||||||
|
|
||||||
|
/// A locked reference to the `Stderr` handle.
|
||||||
|
///
|
||||||
|
/// This handle implements the `Write` trait and is constructed via
|
||||||
|
/// the [`Stderr::lock`] method.
|
||||||
|
///
|
||||||
|
/// [`Stderr::lock`]: struct.Stderr.html#method.lock
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")] |
||||||
|
pub struct StderrLock<'a> { |
||||||
|
inner: ReentrantMutexGuard<'a, RefCell<Maybe<StderrRaw>>>, |
||||||
|
} |
||||||
|
|
||||||
|
/// Constructs a new handle to the standard error of the current process.
|
||||||
|
///
|
||||||
|
/// This handle is not buffered.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// Using implicit synchronization:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::io::{self, Write};
|
||||||
|
///
|
||||||
|
/// # fn foo() -> io::Result<()> {
|
||||||
|
/// io::stderr().write(b"hello world")?;
|
||||||
|
///
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Using explicit synchronization:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::io::{self, Write};
|
||||||
|
///
|
||||||
|
/// # fn foo() -> io::Result<()> {
|
||||||
|
/// let stderr = io::stderr();
|
||||||
|
/// let mut handle = stderr.lock();
|
||||||
|
///
|
||||||
|
/// handle.write(b"hello world")?;
|
||||||
|
///
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")] |
||||||
|
pub fn stderr() -> Stderr { |
||||||
|
static INSTANCE: Lazy<ReentrantMutex<RefCell<Maybe<StderrRaw>>>> = Lazy::new(stderr_init); |
||||||
|
return Stderr { |
||||||
|
inner: INSTANCE.get().expect("cannot access stderr during shutdown"), |
||||||
|
}; |
||||||
|
|
||||||
|
fn stderr_init() -> Arc<ReentrantMutex<RefCell<Maybe<StderrRaw>>>> { |
||||||
|
let stderr = match stderr_raw() { |
||||||
|
Ok(stderr) => Maybe::Real(stderr), |
||||||
|
_ => Maybe::Fake, |
||||||
|
}; |
||||||
|
Arc::new(ReentrantMutex::new(RefCell::new(stderr))) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Stderr { |
||||||
|
/// Locks this handle to the standard error stream, returning a writable
|
||||||
|
/// guard.
|
||||||
|
///
|
||||||
|
/// The lock is released when the returned lock goes out of scope. The
|
||||||
|
/// returned guard also implements the `Write` trait for writing data.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::io::{self, Write};
|
||||||
|
///
|
||||||
|
/// fn foo() -> io::Result<()> {
|
||||||
|
/// let stderr = io::stderr();
|
||||||
|
/// let mut handle = stderr.lock();
|
||||||
|
///
|
||||||
|
/// handle.write(b"hello world")?;
|
||||||
|
///
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")] |
||||||
|
pub fn lock(&self) -> StderrLock { |
||||||
|
StderrLock { inner: self.inner.lock().unwrap_or_else(|e| e.into_inner()) } |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[stable(feature = "std_debug", since = "1.16.0")] |
||||||
|
impl fmt::Debug for Stderr { |
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
||||||
|
f.pad("Stderr { .. }") |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")] |
||||||
|
impl Write for Stderr { |
||||||
|
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { |
||||||
|
self.lock().write(buf) |
||||||
|
} |
||||||
|
fn flush(&mut self) -> io::Result<()> { |
||||||
|
self.lock().flush() |
||||||
|
} |
||||||
|
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { |
||||||
|
self.lock().write_all(buf) |
||||||
|
} |
||||||
|
fn write_fmt(&mut self, args: fmt::Arguments) -> io::Result<()> { |
||||||
|
self.lock().write_fmt(args) |
||||||
|
} |
||||||
|
} |
||||||
|
#[stable(feature = "rust1", since = "1.0.0")] |
||||||
|
impl<'a> Write for StderrLock<'a> { |
||||||
|
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { |
||||||
|
self.inner.borrow_mut().write(buf) |
||||||
|
} |
||||||
|
fn flush(&mut self) -> io::Result<()> { |
||||||
|
self.inner.borrow_mut().flush() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[stable(feature = "std_debug", since = "1.16.0")] |
||||||
|
impl<'a> fmt::Debug for StderrLock<'a> { |
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
||||||
|
f.pad("StderrLock { .. }") |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Resets the thread-local stderr handle to the specified writer
|
||||||
|
///
|
||||||
|
/// This will replace the current thread's stderr handle, returning the old
|
||||||
|
/// handle. All future calls to `panic!` and friends will emit their output to
|
||||||
|
/// this specified handle.
|
||||||
|
///
|
||||||
|
/// Note that this does not need to be called for all new threads; the default
|
||||||
|
/// output handle is to the process's stderr stream.
|
||||||
|
#[unstable(feature = "set_stdio",
|
||||||
|
reason = "this function may disappear completely or be replaced \ |
||||||
|
with a more general mechanism", |
||||||
|
issue = "0")] |
||||||
|
#[doc(hidden)] |
||||||
|
pub fn set_panic(sink: Option<Box<Write + Send>>) -> Option<Box<Write + Send>> { |
||||||
|
use panicking::LOCAL_STDERR; |
||||||
|
use mem; |
||||||
|
LOCAL_STDERR.with(move |slot| { |
||||||
|
mem::replace(&mut *slot.borrow_mut(), sink) |
||||||
|
}).and_then(|mut s| { |
||||||
|
let _ = s.flush(); |
||||||
|
Some(s) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
/// Resets the thread-local stdout handle to the specified writer
|
||||||
|
///
|
||||||
|
/// This will replace the current thread's stdout handle, returning the old
|
||||||
|
/// handle. All future calls to `print!` and friends will emit their output to
|
||||||
|
/// this specified handle.
|
||||||
|
///
|
||||||
|
/// Note that this does not need to be called for all new threads; the default
|
||||||
|
/// output handle is to the process's stdout stream.
|
||||||
|
#[unstable(feature = "set_stdio",
|
||||||
|
reason = "this function may disappear completely or be replaced \ |
||||||
|
with a more general mechanism", |
||||||
|
issue = "0")] |
||||||
|
#[doc(hidden)] |
||||||
|
pub fn set_print(sink: Option<Box<Write + Send>>) -> Option<Box<Write + Send>> { |
||||||
|
use mem; |
||||||
|
LOCAL_STDOUT.with(move |slot| { |
||||||
|
mem::replace(&mut *slot.borrow_mut(), sink) |
||||||
|
}).and_then(|mut s| { |
||||||
|
let _ = s.flush(); |
||||||
|
Some(s) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
#[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() { |
||||||
|
LocalKeyState::Uninitialized | |
||||||
|
LocalKeyState::Destroyed => stdout().write_fmt(args), |
||||||
|
LocalKeyState::Valid => { |
||||||
|
LOCAL_STDOUT.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) |
||||||
|
}) |
||||||
|
} |
||||||
|
}; |
||||||
|
if let Err(e) = result { |
||||||
|
panic!("failed printing to stdout: {}", e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(test)] |
||||||
|
mod tests { |
||||||
|
use thread; |
||||||
|
use super::*; |
||||||
|
|
||||||
|
#[test] |
||||||
|
#[cfg_attr(target_os = "emscripten", ignore)] |
||||||
|
fn panic_doesnt_poison() { |
||||||
|
thread::spawn(|| { |
||||||
|
let _a = stdin(); |
||||||
|
let _a = _a.lock(); |
||||||
|
let _a = stdout(); |
||||||
|
let _a = _a.lock(); |
||||||
|
let _a = stderr(); |
||||||
|
let _a = _a.lock(); |
||||||
|
panic!(); |
||||||
|
}).join().unwrap_err(); |
||||||
|
|
||||||
|
let _a = stdin(); |
||||||
|
let _a = _a.lock(); |
||||||
|
let _a = stdout(); |
||||||
|
let _a = _a.lock(); |
||||||
|
let _a = stderr(); |
||||||
|
let _a = _a.lock(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,137 @@ |
|||||||
|
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#![unstable(reason = "not public", issue = "0", feature = "fd")] |
||||||
|
|
||||||
|
use cmp; |
||||||
|
use io::{self, Read}; |
||||||
|
use libc::{self, c_int, c_void, ssize_t}; |
||||||
|
use mem; |
||||||
|
use sys::cvt; |
||||||
|
use sys_common::AsInner; |
||||||
|
use sys_common::io::read_to_end_uninitialized; |
||||||
|
|
||||||
|
#[derive(Debug)] |
||||||
|
pub struct FileDesc { |
||||||
|
fd: c_int, |
||||||
|
} |
||||||
|
|
||||||
|
fn max_len() -> usize { |
||||||
|
// The maximum read limit on most posix-like systems is `SSIZE_MAX`,
|
||||||
|
// with the man page quoting that if the count of bytes to read is
|
||||||
|
// greater than `SSIZE_MAX` the result is "unspecified".
|
||||||
|
//
|
||||||
|
// On OSX, however, apparently the 64-bit libc is either buggy or
|
||||||
|
// intentionally showing odd behavior by rejecting any read with a size
|
||||||
|
// larger than or equal to INT_MAX. To handle both of these the read
|
||||||
|
// size is capped on both platforms.
|
||||||
|
if cfg!(target_os = "macos") { |
||||||
|
<c_int>::max_value() as usize - 1 |
||||||
|
} else { |
||||||
|
<ssize_t>::max_value() as usize |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl FileDesc { |
||||||
|
pub fn new(fd: c_int) -> FileDesc { |
||||||
|
FileDesc { fd: fd } |
||||||
|
} |
||||||
|
|
||||||
|
pub fn raw(&self) -> c_int { self.fd } |
||||||
|
|
||||||
|
/// Extracts the actual filedescriptor without closing it.
|
||||||
|
pub fn into_raw(self) -> c_int { |
||||||
|
let fd = self.fd; |
||||||
|
mem::forget(self); |
||||||
|
fd |
||||||
|
} |
||||||
|
|
||||||
|
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { |
||||||
|
let ret = cvt(unsafe { |
||||||
|
libc::read(self.fd, |
||||||
|
buf.as_mut_ptr() as *mut c_void, |
||||||
|
cmp::min(buf.len(), max_len())) |
||||||
|
})?; |
||||||
|
Ok(ret as usize) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> { |
||||||
|
let mut me = self; |
||||||
|
(&mut me).read_to_end(buf) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> { |
||||||
|
unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: usize, offset: i64) |
||||||
|
-> io::Result<isize> |
||||||
|
{ |
||||||
|
use libc::pread as pread64; |
||||||
|
cvt(pread64(fd, buf, count, offset)) |
||||||
|
} |
||||||
|
|
||||||
|
unsafe { |
||||||
|
cvt_pread64(self.fd, |
||||||
|
buf.as_mut_ptr() as *mut c_void, |
||||||
|
cmp::min(buf.len(), max_len()), |
||||||
|
offset as i64) |
||||||
|
.map(|n| n as usize) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn write(&self, buf: &[u8]) -> io::Result<usize> { |
||||||
|
let ret = cvt(unsafe { |
||||||
|
libc::write(self.fd, |
||||||
|
buf.as_ptr() as *const c_void, |
||||||
|
cmp::min(buf.len(), max_len())) |
||||||
|
})?; |
||||||
|
Ok(ret as usize) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> { |
||||||
|
unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: usize, offset: i64) |
||||||
|
-> io::Result<isize> |
||||||
|
{ |
||||||
|
use libc::pwrite as pwrite64; |
||||||
|
cvt(pwrite64(fd, buf, count, offset)) |
||||||
|
} |
||||||
|
|
||||||
|
unsafe { |
||||||
|
cvt_pwrite64(self.fd, |
||||||
|
buf.as_ptr() as *const c_void, |
||||||
|
cmp::min(buf.len(), max_len()), |
||||||
|
offset as i64) |
||||||
|
.map(|n| n as usize) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl<'a> Read for &'a FileDesc { |
||||||
|
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { |
||||||
|
(**self).read(buf) |
||||||
|
} |
||||||
|
|
||||||
|
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> { |
||||||
|
unsafe { read_to_end_uninitialized(self, buf) } |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl AsInner<c_int> for FileDesc { |
||||||
|
fn as_inner(&self) -> &c_int { &self.fd } |
||||||
|
} |
||||||
|
|
||||||
|
impl Drop for FileDesc { |
||||||
|
fn drop(&mut self) { |
||||||
|
// Note that errors are ignored when closing a file descriptor. The
|
||||||
|
// reason for this is that if an error occurs we don't actually know if
|
||||||
|
// the file descriptor was closed or not, and if we retried (for
|
||||||
|
// something like EINTR), we might close another valid file descriptor
|
||||||
|
// (opened after we closed ours.
|
||||||
|
let _ = unsafe { libc::close(self.fd) }; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,81 @@ |
|||||||
|
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
use io; |
||||||
|
use libc; |
||||||
|
use sys::fd::FileDesc; |
||||||
|
|
||||||
|
pub struct Stdin(()); |
||||||
|
pub struct Stdout(()); |
||||||
|
pub struct Stderr(()); |
||||||
|
|
||||||
|
impl Stdin { |
||||||
|
pub fn new() -> io::Result<Stdin> { Ok(Stdin(())) } |
||||||
|
|
||||||
|
pub fn read(&self, data: &mut [u8]) -> io::Result<usize> { |
||||||
|
let fd = FileDesc::new(libc::STDIN_FILENO); |
||||||
|
let ret = fd.read(data); |
||||||
|
fd.into_raw(); |
||||||
|
ret |
||||||
|
} |
||||||
|
|
||||||
|
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> { |
||||||
|
let fd = FileDesc::new(libc::STDIN_FILENO); |
||||||
|
let ret = fd.read_to_end(buf); |
||||||
|
fd.into_raw(); |
||||||
|
ret |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Stdout { |
||||||
|
pub fn new() -> io::Result<Stdout> { Ok(Stdout(())) } |
||||||
|
|
||||||
|
pub fn write(&self, data: &[u8]) -> io::Result<usize> { |
||||||
|
let fd = FileDesc::new(libc::STDOUT_FILENO); |
||||||
|
let ret = fd.write(data); |
||||||
|
fd.into_raw(); |
||||||
|
ret |
||||||
|
} |
||||||
|
|
||||||
|
pub fn flush(&self) -> io::Result<()> { |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Stderr { |
||||||
|
pub fn new() -> io::Result<Stderr> { Ok(Stderr(())) } |
||||||
|
|
||||||
|
pub fn write(&self, data: &[u8]) -> io::Result<usize> { |
||||||
|
let fd = FileDesc::new(libc::STDERR_FILENO); |
||||||
|
let ret = fd.write(data); |
||||||
|
fd.into_raw(); |
||||||
|
ret |
||||||
|
} |
||||||
|
|
||||||
|
pub fn flush(&self) -> io::Result<()> { |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// FIXME: right now this raw stderr handle is used in a few places because
|
||||||
|
// std::io::stderr_raw isn't exposed, but once that's exposed this impl
|
||||||
|
// should go away
|
||||||
|
impl io::Write for Stderr { |
||||||
|
fn write(&mut self, data: &[u8]) -> io::Result<usize> { |
||||||
|
Stderr::write(self, data) |
||||||
|
} |
||||||
|
|
||||||
|
fn flush(&mut self) -> io::Result<()> { |
||||||
|
Stderr::flush(self) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub const EBADF_ERR: i32 = ::libc::EBADF as i32; |
||||||
|
pub const STDIN_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE; |
@ -0,0 +1,81 @@ |
|||||||
|
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
use io; |
||||||
|
use libc; |
||||||
|
use sys::fd::FileDesc; |
||||||
|
|
||||||
|
pub struct Stdin(()); |
||||||
|
pub struct Stdout(()); |
||||||
|
pub struct Stderr(()); |
||||||
|
|
||||||
|
impl Stdin { |
||||||
|
pub fn new() -> io::Result<Stdin> { Ok(Stdin(())) } |
||||||
|
|
||||||
|
pub fn read(&self, data: &mut [u8]) -> io::Result<usize> { |
||||||
|
let fd = FileDesc::new(libc::STDIN_FILENO); |
||||||
|
let ret = fd.read(data); |
||||||
|
fd.into_raw(); |
||||||
|
ret |
||||||
|
} |
||||||
|
|
||||||
|
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> { |
||||||
|
let fd = FileDesc::new(libc::STDIN_FILENO); |
||||||
|
let ret = fd.read_to_end(buf); |
||||||
|
fd.into_raw(); |
||||||
|
ret |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Stdout { |
||||||
|
pub fn new() -> io::Result<Stdout> { Ok(Stdout(())) } |
||||||
|
|
||||||
|
pub fn write(&self, data: &[u8]) -> io::Result<usize> { |
||||||
|
let fd = FileDesc::new(libc::STDOUT_FILENO); |
||||||
|
let ret = fd.write(data); |
||||||
|
fd.into_raw(); |
||||||
|
ret |
||||||
|
} |
||||||
|
|
||||||
|
pub fn flush(&self) -> io::Result<()> { |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Stderr { |
||||||
|
pub fn new() -> io::Result<Stderr> { Ok(Stderr(())) } |
||||||
|
|
||||||
|
pub fn write(&self, data: &[u8]) -> io::Result<usize> { |
||||||
|
let fd = FileDesc::new(libc::STDERR_FILENO); |
||||||
|
let ret = fd.write(data); |
||||||
|
fd.into_raw(); |
||||||
|
ret |
||||||
|
} |
||||||
|
|
||||||
|
pub fn flush(&self) -> io::Result<()> { |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// FIXME: right now this raw stderr handle is used in a few places because
|
||||||
|
// std::io::stderr_raw isn't exposed, but once that's exposed this impl
|
||||||
|
// should go away
|
||||||
|
impl io::Write for Stderr { |
||||||
|
fn write(&mut self, data: &[u8]) -> io::Result<usize> { |
||||||
|
Stderr::write(self, data) |
||||||
|
} |
||||||
|
|
||||||
|
fn flush(&mut self) -> io::Result<()> { |
||||||
|
Stderr::flush(self) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub const EBADF_ERR: i32 = ::libc::EBADF as i32; |
||||||
|
pub const STDIN_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE; |
@ -0,0 +1,80 @@ |
|||||||
|
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
//! Implementation of running at_exit routines
|
||||||
|
//!
|
||||||
|
//! Documentation can be found on the `rt::at_exit` function.
|
||||||
|
|
||||||
|
use alloc::boxed::FnBox; |
||||||
|
use ptr; |
||||||
|
use sys_common::mutex::Mutex; |
||||||
|
|
||||||
|
type Queue = Vec<Box<FnBox()>>; |
||||||
|
|
||||||
|
// NB these are specifically not types from `std::sync` as they currently rely
|
||||||
|
// on poisoning and this module needs to operate at a lower level than requiring
|
||||||
|
// the thread infrastructure to be in place (useful on the borders of
|
||||||
|
// initialization/destruction).
|
||||||
|
static LOCK: Mutex = Mutex::new(); |
||||||
|
static mut QUEUE: *mut Queue = ptr::null_mut(); |
||||||
|
|
||||||
|
// The maximum number of times the cleanup routines will be run. While running
|
||||||
|
// the at_exit closures new ones may be registered, and this count is the number
|
||||||
|
// of times the new closures will be allowed to register successfully. After
|
||||||
|
// this number of iterations all new registrations will return `false`.
|
||||||
|
const ITERS: usize = 10; |
||||||
|
|
||||||
|
unsafe fn init() -> bool { |
||||||
|
if QUEUE.is_null() { |
||||||
|
let state: Box<Queue> = box Vec::new(); |
||||||
|
QUEUE = Box::into_raw(state); |
||||||
|
} else if QUEUE as usize == 1 { |
||||||
|
// can't re-init after a cleanup
|
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
true |
||||||
|
} |
||||||
|
|
||||||
|
pub fn cleanup() { |
||||||
|
for i in 0..ITERS { |
||||||
|
unsafe { |
||||||
|
LOCK.lock(); |
||||||
|
let queue = QUEUE; |
||||||
|
QUEUE = if i == ITERS - 1 {1} else {0} as *mut _; |
||||||
|
LOCK.unlock(); |
||||||
|
|
||||||
|
// make sure we're not recursively cleaning up
|
||||||
|
assert!(queue as usize != 1); |
||||||
|
|
||||||
|
// If we never called init, not need to cleanup!
|
||||||
|
if queue as usize != 0 { |
||||||
|
let queue: Box<Queue> = Box::from_raw(queue); |
||||||
|
for to_run in *queue { |
||||||
|
to_run(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn push(f: Box<FnBox()>) -> bool { |
||||||
|
let mut ret = true; |
||||||
|
unsafe { |
||||||
|
LOCK.lock(); |
||||||
|
if init() { |
||||||
|
(*QUEUE).push(f); |
||||||
|
} else { |
||||||
|
ret = false; |
||||||
|
} |
||||||
|
LOCK.unlock(); |
||||||
|
} |
||||||
|
ret |
||||||
|
} |
Loading…
Reference in new issue