Remove io::LocalOutput and use Arc<Mutex<dyn>> for local streams.
This commit is contained in:
parent
cf9cf7c923
commit
72e96604c0
9 changed files with 51 additions and 118 deletions
|
@ -25,7 +25,7 @@ use rustc_span::symbol::{sym, Symbol};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
|
use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
|
||||||
use std::io::{self, Write};
|
use std::io;
|
||||||
use std::lazy::SyncOnceCell;
|
use std::lazy::SyncOnceCell;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops::DerefMut;
|
use std::ops::DerefMut;
|
||||||
|
@ -106,21 +106,6 @@ fn get_stack_size() -> Option<usize> {
|
||||||
env::var_os("RUST_MIN_STACK").is_none().then_some(STACK_SIZE)
|
env::var_os("RUST_MIN_STACK").is_none().then_some(STACK_SIZE)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Sink(Arc<Mutex<Vec<u8>>>);
|
|
||||||
impl Write for Sink {
|
|
||||||
fn write(&mut self, data: &[u8]) -> io::Result<usize> {
|
|
||||||
Write::write(&mut *self.0.lock().unwrap(), data)
|
|
||||||
}
|
|
||||||
fn flush(&mut self) -> io::Result<()> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl io::LocalOutput for Sink {
|
|
||||||
fn clone_box(&self) -> Box<dyn io::LocalOutput> {
|
|
||||||
Box::new(Self(self.0.clone()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Like a `thread::Builder::spawn` followed by a `join()`, but avoids the need
|
/// Like a `thread::Builder::spawn` followed by a `join()`, but avoids the need
|
||||||
/// for `'static` bounds.
|
/// for `'static` bounds.
|
||||||
#[cfg(not(parallel_compiler))]
|
#[cfg(not(parallel_compiler))]
|
||||||
|
@ -164,7 +149,7 @@ pub fn setup_callbacks_and_run_in_thread_pool_with_globals<F: FnOnce() -> R + Se
|
||||||
let main_handler = move || {
|
let main_handler = move || {
|
||||||
rustc_span::with_session_globals(edition, || {
|
rustc_span::with_session_globals(edition, || {
|
||||||
if let Some(stderr) = stderr {
|
if let Some(stderr) = stderr {
|
||||||
io::set_panic(Some(box Sink(stderr.clone())));
|
io::set_panic(Some(stderr.clone()));
|
||||||
}
|
}
|
||||||
f()
|
f()
|
||||||
})
|
})
|
||||||
|
@ -204,7 +189,7 @@ pub fn setup_callbacks_and_run_in_thread_pool_with_globals<F: FnOnce() -> R + Se
|
||||||
let main_handler = move |thread: rayon::ThreadBuilder| {
|
let main_handler = move |thread: rayon::ThreadBuilder| {
|
||||||
rustc_span::SESSION_GLOBALS.set(session_globals, || {
|
rustc_span::SESSION_GLOBALS.set(session_globals, || {
|
||||||
if let Some(stderr) = stderr {
|
if let Some(stderr) = stderr {
|
||||||
io::set_panic(Some(box Sink(stderr.clone())));
|
io::set_panic(Some(stderr.clone()));
|
||||||
}
|
}
|
||||||
thread.run()
|
thread.run()
|
||||||
})
|
})
|
||||||
|
|
|
@ -209,20 +209,6 @@ impl<B: BufRead + ?Sized> BufRead for Box<B> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used by panicking::default_hook
|
|
||||||
#[cfg(test)]
|
|
||||||
/// This impl is only used by printing logic, so any error returned is always
|
|
||||||
/// of kind `Other`, and should be ignored.
|
|
||||||
impl Write for dyn ::realstd::io::LocalOutput {
|
|
||||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
|
||||||
(*self).write(buf).map_err(|_| ErrorKind::Other.into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn flush(&mut self) -> io::Result<()> {
|
|
||||||
(*self).flush().map_err(|_| ErrorKind::Other.into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
// In-memory buffer implementations
|
// In-memory buffer implementations
|
||||||
|
|
||||||
|
|
|
@ -277,7 +277,7 @@ pub use self::stdio::{StderrLock, StdinLock, StdoutLock};
|
||||||
pub use self::stdio::{_eprint, _print};
|
pub use self::stdio::{_eprint, _print};
|
||||||
#[unstable(feature = "libstd_io_internals", issue = "42788")]
|
#[unstable(feature = "libstd_io_internals", issue = "42788")]
|
||||||
#[doc(no_inline, hidden)]
|
#[doc(no_inline, hidden)]
|
||||||
pub use self::stdio::{set_panic, set_print, LocalOutput};
|
pub use self::stdio::{set_panic, set_print};
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub use self::util::{copy, empty, repeat, sink, Empty, Repeat, Sink};
|
pub use self::util::{copy, empty, repeat, sink, Empty, Repeat, Sink};
|
||||||
|
|
||||||
|
|
|
@ -10,22 +10,24 @@ use crate::fmt;
|
||||||
use crate::io::{self, BufReader, Initializer, IoSlice, IoSliceMut, LineWriter};
|
use crate::io::{self, BufReader, Initializer, IoSlice, IoSliceMut, LineWriter};
|
||||||
use crate::lazy::SyncOnceCell;
|
use crate::lazy::SyncOnceCell;
|
||||||
use crate::sync::atomic::{AtomicBool, Ordering};
|
use crate::sync::atomic::{AtomicBool, Ordering};
|
||||||
use crate::sync::{Mutex, MutexGuard};
|
use crate::sync::{Arc, Mutex, MutexGuard};
|
||||||
use crate::sys::stdio;
|
use crate::sys::stdio;
|
||||||
use crate::sys_common;
|
use crate::sys_common;
|
||||||
use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
|
use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
|
||||||
use crate::thread::LocalKey;
|
use crate::thread::LocalKey;
|
||||||
|
|
||||||
|
type LocalStream = Arc<Mutex<dyn Write + Send>>;
|
||||||
|
|
||||||
thread_local! {
|
thread_local! {
|
||||||
/// Used by the test crate to capture the output of the print! and println! macros.
|
/// Used by the test crate to capture the output of the print! and println! macros.
|
||||||
static LOCAL_STDOUT: RefCell<Option<Box<dyn LocalOutput>>> = {
|
static LOCAL_STDOUT: RefCell<Option<LocalStream>> = {
|
||||||
RefCell::new(None)
|
RefCell::new(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
thread_local! {
|
thread_local! {
|
||||||
/// Used by the test crate to capture the output of the eprint! and eprintln! macros, and panics.
|
/// Used by the test crate to capture the output of the eprint! and eprintln! macros, and panics.
|
||||||
static LOCAL_STDERR: RefCell<Option<Box<dyn LocalOutput>>> = {
|
static LOCAL_STDERR: RefCell<Option<LocalStream>> = {
|
||||||
RefCell::new(None)
|
RefCell::new(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -888,18 +890,6 @@ impl fmt::Debug for StderrLock<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A writer than can be cloned to new threads.
|
|
||||||
#[unstable(
|
|
||||||
feature = "set_stdio",
|
|
||||||
reason = "this trait may disappear completely or be replaced \
|
|
||||||
with a more general mechanism",
|
|
||||||
issue = "none"
|
|
||||||
)]
|
|
||||||
#[doc(hidden)]
|
|
||||||
pub trait LocalOutput: Write + Send {
|
|
||||||
fn clone_box(&self) -> Box<dyn LocalOutput>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Resets the thread-local stderr handle to the specified writer
|
/// Resets the thread-local stderr handle to the specified writer
|
||||||
///
|
///
|
||||||
/// This will replace the current thread's stderr handle, returning the old
|
/// This will replace the current thread's stderr handle, returning the old
|
||||||
|
@ -915,18 +905,17 @@ pub trait LocalOutput: Write + Send {
|
||||||
issue = "none"
|
issue = "none"
|
||||||
)]
|
)]
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn set_panic(sink: Option<Box<dyn LocalOutput>>) -> Option<Box<dyn LocalOutput>> {
|
pub fn set_panic(sink: Option<LocalStream>) -> Option<LocalStream> {
|
||||||
use crate::mem;
|
use crate::mem;
|
||||||
if sink.is_none() && !LOCAL_STREAMS.load(Ordering::Relaxed) {
|
if sink.is_none() && !LOCAL_STREAMS.load(Ordering::Relaxed) {
|
||||||
// LOCAL_STDERR is definitely None since LOCAL_STREAMS is false.
|
// LOCAL_STDERR is definitely None since LOCAL_STREAMS is false.
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let s = LOCAL_STDERR.with(move |slot| mem::replace(&mut *slot.borrow_mut(), sink)).and_then(
|
let s =
|
||||||
|mut s| {
|
LOCAL_STDERR.with(move |slot| mem::replace(&mut *slot.borrow_mut(), sink)).and_then(|s| {
|
||||||
let _ = s.flush();
|
let _ = s.lock().unwrap_or_else(|e| e.into_inner()).flush();
|
||||||
Some(s)
|
Some(s)
|
||||||
},
|
});
|
||||||
);
|
|
||||||
LOCAL_STREAMS.store(true, Ordering::Relaxed);
|
LOCAL_STREAMS.store(true, Ordering::Relaxed);
|
||||||
s
|
s
|
||||||
}
|
}
|
||||||
|
@ -946,35 +935,29 @@ pub fn set_panic(sink: Option<Box<dyn LocalOutput>>) -> Option<Box<dyn LocalOutp
|
||||||
issue = "none"
|
issue = "none"
|
||||||
)]
|
)]
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn set_print(sink: Option<Box<dyn LocalOutput>>) -> Option<Box<dyn LocalOutput>> {
|
pub fn set_print(sink: Option<LocalStream>) -> Option<LocalStream> {
|
||||||
use crate::mem;
|
use crate::mem;
|
||||||
if sink.is_none() && !LOCAL_STREAMS.load(Ordering::Relaxed) {
|
if sink.is_none() && !LOCAL_STREAMS.load(Ordering::Relaxed) {
|
||||||
// LOCAL_STDOUT is definitely None since LOCAL_STREAMS is false.
|
// LOCAL_STDOUT is definitely None since LOCAL_STREAMS is false.
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let s = LOCAL_STDOUT.with(move |slot| mem::replace(&mut *slot.borrow_mut(), sink)).and_then(
|
let s =
|
||||||
|mut s| {
|
LOCAL_STDOUT.with(move |slot| mem::replace(&mut *slot.borrow_mut(), sink)).and_then(|s| {
|
||||||
let _ = s.flush();
|
let _ = s.lock().unwrap_or_else(|e| e.into_inner()).flush();
|
||||||
Some(s)
|
Some(s)
|
||||||
},
|
});
|
||||||
);
|
|
||||||
LOCAL_STREAMS.store(true, Ordering::Relaxed);
|
LOCAL_STREAMS.store(true, Ordering::Relaxed);
|
||||||
s
|
s
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn clone_io() -> (Option<Box<dyn LocalOutput>>, Option<Box<dyn LocalOutput>>) {
|
pub(crate) fn clone_io() -> (Option<LocalStream>, Option<LocalStream>) {
|
||||||
// Don't waste time when LOCAL_{STDOUT,STDERR} are definitely None.
|
// Don't waste time when LOCAL_{STDOUT,STDERR} are definitely None.
|
||||||
if !LOCAL_STREAMS.load(Ordering::Relaxed) {
|
if !LOCAL_STREAMS.load(Ordering::Relaxed) {
|
||||||
return (None, None);
|
return (None, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
LOCAL_STDOUT.with(|stdout| {
|
LOCAL_STDOUT.with(|stdout| {
|
||||||
LOCAL_STDERR.with(|stderr| {
|
LOCAL_STDERR.with(|stderr| (stdout.borrow().clone(), stderr.borrow().clone()))
|
||||||
(
|
|
||||||
stdout.borrow().as_ref().map(|o| o.clone_box()),
|
|
||||||
stderr.borrow().as_ref().map(|o| o.clone_box()),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -990,7 +973,7 @@ pub(crate) fn clone_io() -> (Option<Box<dyn LocalOutput>>, Option<Box<dyn LocalO
|
||||||
/// However, if the actual I/O causes an error, this function does panic.
|
/// However, if the actual I/O causes an error, this function does panic.
|
||||||
fn print_to<T>(
|
fn print_to<T>(
|
||||||
args: fmt::Arguments<'_>,
|
args: fmt::Arguments<'_>,
|
||||||
local_s: &'static LocalKey<RefCell<Option<Box<dyn LocalOutput>>>>,
|
local_s: &'static LocalKey<RefCell<Option<LocalStream>>>,
|
||||||
global_s: fn() -> T,
|
global_s: fn() -> T,
|
||||||
label: &str,
|
label: &str,
|
||||||
) where
|
) where
|
||||||
|
@ -1005,8 +988,8 @@ fn print_to<T>(
|
||||||
// our printing recursively panics/prints, so the recursive
|
// our printing recursively panics/prints, so the recursive
|
||||||
// panic/print goes to the global sink instead of our local sink.
|
// panic/print goes to the global sink instead of our local sink.
|
||||||
let prev = s.borrow_mut().take();
|
let prev = s.borrow_mut().take();
|
||||||
if let Some(mut w) = prev {
|
if let Some(w) = prev {
|
||||||
let result = w.write_fmt(args);
|
let result = w.lock().unwrap_or_else(|e| e.into_inner()).write_fmt(args);
|
||||||
*s.borrow_mut() = Some(w);
|
*s.borrow_mut() = Some(w);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -218,10 +218,29 @@ fn default_hook(info: &PanicInfo<'_>) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(mut local) = set_panic(None) {
|
if let Some(local) = set_panic(None) {
|
||||||
// NB. In `cfg(test)` this uses the forwarding impl
|
let mut stream = local.lock().unwrap_or_else(|e| e.into_inner());
|
||||||
// for `dyn ::realstd::io::LocalOutput`.
|
|
||||||
write(&mut local);
|
#[cfg(test)]
|
||||||
|
{
|
||||||
|
use crate::io;
|
||||||
|
struct Wrapper<'a>(&'a mut (dyn ::realstd::io::Write + Send));
|
||||||
|
impl io::Write for Wrapper<'_> {
|
||||||
|
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||||
|
self.0.write(buf).map_err(|_| io::ErrorKind::Other.into())
|
||||||
|
}
|
||||||
|
fn flush(&mut self) -> io::Result<()> {
|
||||||
|
self.0.flush().map_err(|_| io::ErrorKind::Other.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
write(&mut Wrapper(&mut *stream));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(test))]
|
||||||
|
write(&mut *stream);
|
||||||
|
|
||||||
|
drop(stream);
|
||||||
|
|
||||||
set_panic(Some(local));
|
set_panic(Some(local));
|
||||||
} else if let Some(mut out) = panic_output() {
|
} else if let Some(mut out) = panic_output() {
|
||||||
write(&mut out);
|
write(&mut out);
|
||||||
|
|
|
@ -2,8 +2,7 @@
|
||||||
pub use std::hint::black_box;
|
pub use std::hint::black_box;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
event::CompletedTest, helpers::sink::Sink, options::BenchMode, test_result::TestResult,
|
event::CompletedTest, options::BenchMode, test_result::TestResult, types::TestDesc, Sender,
|
||||||
types::TestDesc, Sender,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::stats;
|
use crate::stats;
|
||||||
|
@ -186,10 +185,7 @@ where
|
||||||
|
|
||||||
let data = Arc::new(Mutex::new(Vec::new()));
|
let data = Arc::new(Mutex::new(Vec::new()));
|
||||||
let oldio = if !nocapture {
|
let oldio = if !nocapture {
|
||||||
Some((
|
Some((io::set_print(Some(data.clone())), io::set_panic(Some(data.clone()))))
|
||||||
io::set_print(Some(Sink::new_boxed(&data))),
|
|
||||||
io::set_panic(Some(Sink::new_boxed(&data))),
|
|
||||||
))
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,4 +5,3 @@ pub mod concurrency;
|
||||||
pub mod exit_code;
|
pub mod exit_code;
|
||||||
pub mod isatty;
|
pub mod isatty;
|
||||||
pub mod metrics;
|
pub mod metrics;
|
||||||
pub mod sink;
|
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
//! Module providing a helper structure to capture output in subprocesses.
|
|
||||||
|
|
||||||
use std::{
|
|
||||||
io,
|
|
||||||
io::prelude::Write,
|
|
||||||
sync::{Arc, Mutex},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Sink(Arc<Mutex<Vec<u8>>>);
|
|
||||||
|
|
||||||
impl Sink {
|
|
||||||
pub fn new_boxed(data: &Arc<Mutex<Vec<u8>>>) -> Box<Self> {
|
|
||||||
Box::new(Self(data.clone()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl io::LocalOutput for Sink {
|
|
||||||
fn clone_box(&self) -> Box<dyn io::LocalOutput> {
|
|
||||||
Box::new(self.clone())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Write for Sink {
|
|
||||||
fn write(&mut self, data: &[u8]) -> io::Result<usize> {
|
|
||||||
Write::write(&mut *self.0.lock().unwrap(), data)
|
|
||||||
}
|
|
||||||
fn flush(&mut self) -> io::Result<()> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -89,7 +89,6 @@ mod tests;
|
||||||
use event::{CompletedTest, TestEvent};
|
use event::{CompletedTest, TestEvent};
|
||||||
use helpers::concurrency::get_concurrency;
|
use helpers::concurrency::get_concurrency;
|
||||||
use helpers::exit_code::get_exit_code;
|
use helpers::exit_code::get_exit_code;
|
||||||
use helpers::sink::Sink;
|
|
||||||
use options::{Concurrent, RunStrategy};
|
use options::{Concurrent, RunStrategy};
|
||||||
use test_result::*;
|
use test_result::*;
|
||||||
use time::TestExecTime;
|
use time::TestExecTime;
|
||||||
|
@ -532,10 +531,7 @@ fn run_test_in_process(
|
||||||
let data = Arc::new(Mutex::new(Vec::new()));
|
let data = Arc::new(Mutex::new(Vec::new()));
|
||||||
|
|
||||||
let oldio = if !nocapture {
|
let oldio = if !nocapture {
|
||||||
Some((
|
Some((io::set_print(Some(data.clone())), io::set_panic(Some(data.clone()))))
|
||||||
io::set_print(Some(Sink::new_boxed(&data))),
|
|
||||||
io::set_panic(Some(Sink::new_boxed(&data))),
|
|
||||||
))
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
@ -556,7 +552,7 @@ fn run_test_in_process(
|
||||||
Ok(()) => calc_result(&desc, Ok(()), &time_opts, &exec_time),
|
Ok(()) => calc_result(&desc, Ok(()), &time_opts, &exec_time),
|
||||||
Err(e) => calc_result(&desc, Err(e.as_ref()), &time_opts, &exec_time),
|
Err(e) => calc_result(&desc, Err(e.as_ref()), &time_opts, &exec_time),
|
||||||
};
|
};
|
||||||
let stdout = data.lock().unwrap().to_vec();
|
let stdout = data.lock().unwrap_or_else(|e| e.into_inner()).to_vec();
|
||||||
let message = CompletedTest::new(desc, test_result, exec_time, stdout);
|
let message = CompletedTest::new(desc, test_result, exec_time, stdout);
|
||||||
monitor_ch.send(message).unwrap();
|
monitor_ch.send(message).unwrap();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue