Rollup merge of #78714 - m-ou-se:simplify-local-streams, r=KodrAus · rust-lang/rust@11ce918 (original) (raw)
`@@ -5,44 +5,38 @@ mod tests;
`
5
5
``
6
6
`use crate::io::prelude::*;
`
7
7
``
8
``
`-
use crate::cell::RefCell;
`
``
8
`+
use crate::cell::{Cell, RefCell};
`
9
9
`use crate::fmt;
`
10
10
`use crate::io::{self, BufReader, Initializer, IoSlice, IoSliceMut, LineWriter};
`
11
11
`use crate:🦥:SyncOnceCell;
`
12
12
`use crate::sync::atomic::{AtomicBool, Ordering};
`
13
``
`-
use crate::sync::{Mutex, MutexGuard};
`
``
13
`+
use crate::sync::{Arc, Mutex, MutexGuard};
`
14
14
`use crate::sys::stdio;
`
15
15
`use crate::sys_common;
`
16
16
`use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
`
17
``
`-
use crate::thread::LocalKey;
`
18
17
``
19
``
`-
thread_local! {
`
20
``
`-
/// Used by the test crate to capture the output of the print! and println! macros.
`
21
``
`-
static LOCAL_STDOUT: RefCell<Option<Box>> = {
`
22
``
`-
RefCell::new(None)
`
23
``
`-
}
`
24
``
`-
}
`
``
18
`+
type LocalStream = Arc<Mutex<Vec>>;
`
25
19
``
26
20
`thread_local! {
`
27
``
`-
/// Used by the test crate to capture the output of the eprint! and eprintln! macros, and panics.
`
28
``
`-
static LOCAL_STDERR: RefCell<Option<Box>> = {
`
29
``
`-
RefCell::new(None)
`
``
21
`+
/// Used by the test crate to capture the output of the print macros and panics.
`
``
22
`+
static OUTPUT_CAPTURE: Cell<Option> = {
`
``
23
`+
Cell::new(None)
`
30
24
`}
`
31
25
`}
`
32
26
``
33
``
`-
/// Flag to indicate LOCAL_STDOUT and/or LOCAL_STDERR is used.
`
``
27
`+
/// Flag to indicate OUTPUT_CAPTURE is used.
`
34
28
`///
`
35
``
`-
/// If both are None and were never set on any thread, this flag is set to
`
36
``
`-
/// false, and both LOCAL_STDOUT and LOCAL_STDOUT can be safely ignored on all
`
37
``
`-
/// threads, saving some time and memory registering an unused thread local.
`
``
29
`+
/// If it is None and was never set on any thread, this flag is set to false,
`
``
30
`+
/// and OUTPUT_CAPTURE can be safely ignored on all threads, saving some time
`
``
31
`+
/// and memory registering an unused thread local.
`
38
32
`///
`
39
``
`-
/// Note about memory ordering: This contains information about whether two
`
40
``
`-
/// thread local variables might be in use. Although this is a global flag, the
`
``
33
`+
/// Note about memory ordering: This contains information about whether a
`
``
34
`+
/// thread local variable might be in use. Although this is a global flag, the
`
41
35
`/// memory ordering between threads does not matter: we only want this flag to
`
42
``
`-
/// have a consistent order between set_print/set_panic and print_to *within
`
``
36
`+
/// have a consistent order between set_output_capture and print_to *within
`
43
37
`/// the same thread*. Within the same thread, things always have a perfectly
`
44
38
`/// consistent order. So Ordering::Relaxed is fine.
`
45
``
`-
static LOCAL_STREAMS: AtomicBool = AtomicBool::new(false);
`
``
39
`+
static OUTPUT_CAPTURE_USED: AtomicBool = AtomicBool::new(false);
`
46
40
``
47
41
`/// A handle to a raw instance of the standard input stream of this process.
`
48
42
`///
`
`@@ -896,97 +890,24 @@ impl fmt::Debug for StderrLock<'_> {
`
896
890
`}
`
897
891
`}
`
898
892
``
899
``
`-
/// A writer than can be cloned to new threads.
`
900
``
`-
#[unstable(
`
901
``
`-
feature = "set_stdio",
`
902
``
`-
reason = "this trait may disappear completely or be replaced \
`
903
``
`-
with a more general mechanism",
`
904
``
`-
issue = "none"
`
905
``
`-
)]
`
906
``
`-
#[doc(hidden)]
`
907
``
`-
pub trait LocalOutput: Write + Send {
`
908
``
`-
fn clone_box(&self) -> Box;
`
909
``
`-
}
`
910
``
-
911
``
`-
/// Resets the thread-local stderr handle to the specified writer
`
912
``
`-
///
`
913
``
`-
/// This will replace the current thread's stderr handle, returning the old
`
914
``
`` -
/// handle. All future calls to panic!
and friends will emit their output to
``
915
``
`-
/// this specified handle.
`
916
``
`-
///
`
917
``
`-
/// Note that this does not need to be called for all new threads; the default
`
918
``
`-
/// output handle is to the process's stderr stream.
`
919
``
`-
#[unstable(
`
920
``
`-
feature = "set_stdio",
`
921
``
`-
reason = "this function may disappear completely or be replaced \
`
922
``
`-
with a more general mechanism",
`
923
``
`-
issue = "none"
`
924
``
`-
)]
`
925
``
`-
#[doc(hidden)]
`
926
``
`-
pub fn set_panic(sink: Option<Box>) -> Option<Box> {
`
927
``
`-
use crate::mem;
`
928
``
`-
if sink.is_none() && !LOCAL_STREAMS.load(Ordering::Relaxed) {
`
929
``
`-
// LOCAL_STDERR is definitely None since LOCAL_STREAMS is false.
`
930
``
`-
return None;
`
931
``
`-
}
`
932
``
`-
let s = LOCAL_STDERR.with(move |slot| mem::replace(&mut *slot.borrow_mut(), sink)).and_then(
`
933
``
`-
|mut s| {
`
934
``
`-
let _ = s.flush();
`
935
``
`-
Some(s)
`
936
``
`-
},
`
937
``
`-
);
`
938
``
`-
LOCAL_STREAMS.store(true, Ordering::Relaxed);
`
939
``
`-
s
`
940
``
`-
}
`
941
``
-
942
``
`-
/// Resets the thread-local stdout handle to the specified writer
`
943
``
`-
///
`
944
``
`-
/// This will replace the current thread's stdout handle, returning the old
`
945
``
`` -
/// handle. All future calls to print!
and friends will emit their output to
``
946
``
`-
/// this specified handle.
`
947
``
`-
///
`
948
``
`-
/// Note that this does not need to be called for all new threads; the default
`
949
``
`-
/// output handle is to the process's stdout stream.
`
``
893
`+
/// Sets the thread-local output capture buffer and returns the old one.
`
950
894
`#[unstable(
`
951
``
`-
feature = "set_stdio",
`
952
``
`-
reason = "this function may disappear completely or be replaced \
`
953
``
`-
with a more general mechanism",
`
``
895
`+
feature = "internal_output_capture",
`
``
896
`+
reason = "this function is meant for use in the test crate \
`
``
897
`+
and may disappear in the future",
`
954
898
` issue = "none"
`
955
899
`)]
`
956
900
`#[doc(hidden)]
`
957
``
`-
pub fn set_print(sink: Option<Box>) -> Option<Box> {
`
958
``
`-
use crate::mem;
`
959
``
`-
if sink.is_none() && !LOCAL_STREAMS.load(Ordering::Relaxed) {
`
960
``
`-
// LOCAL_STDOUT is definitely None since LOCAL_STREAMS is false.
`
``
901
`+
pub fn set_output_capture(sink: Option) -> Option {
`
``
902
`+
if sink.is_none() && !OUTPUT_CAPTURE_USED.load(Ordering::Relaxed) {
`
``
903
`+
// OUTPUT_CAPTURE is definitely None since OUTPUT_CAPTURE_USED is false.
`
961
904
`return None;
`
962
905
`}
`
963
``
`-
let s = LOCAL_STDOUT.with(move |slot| mem::replace(&mut *slot.borrow_mut(), sink)).and_then(
`
964
``
`-
|mut s| {
`
965
``
`-
let _ = s.flush();
`
966
``
`-
Some(s)
`
967
``
`-
},
`
968
``
`-
);
`
969
``
`-
LOCAL_STREAMS.store(true, Ordering::Relaxed);
`
970
``
`-
s
`
971
``
`-
}
`
972
``
-
973
``
`-
pub(crate) fn clone_io() -> (Option<Box>, Option<Box>) {
`
974
``
`-
// Don't waste time when LOCAL_{STDOUT,STDERR} are definitely None.
`
975
``
`-
if !LOCAL_STREAMS.load(Ordering::Relaxed) {
`
976
``
`-
return (None, None);
`
977
``
`-
}
`
978
``
-
979
``
`-
LOCAL_STDOUT.with(|stdout| {
`
980
``
`-
LOCAL_STDERR.with(|stderr| {
`
981
``
`-
(
`
982
``
`-
stdout.borrow().as_ref().map(|o| o.clone_box()),
`
983
``
`-
stderr.borrow().as_ref().map(|o| o.clone_box()),
`
984
``
`-
)
`
985
``
`-
})
`
986
``
`-
})
`
``
906
`+
OUTPUT_CAPTURE_USED.store(true, Ordering::Relaxed);
`
``
907
`+
OUTPUT_CAPTURE.with(move |slot| slot.replace(sink))
`
987
908
`}
`
988
909
``
989
``
`` -
/// Write args
to output stream local_s
if possible, global_s
``
``
910
`` +
/// Write args
to the capture buffer if enabled and possible, or global_s
``
990
911
`` /// otherwise. label
identifies the stream in a panic message.
``
991
912
`///
`
992
913
`/// This function is used to print error messages, so it takes extra
`
`@@ -996,36 +917,26 @@ pub(crate) fn clone_io() -> (Option<Box>, Option<Box<dyn LocalO
`
996
917
`/// thread, it will just fall back to the global stream.
`
997
918
`///
`
998
919
`/// However, if the actual I/O causes an error, this function does panic.
`
999
``
`-
fn print_to(
`
1000
``
`-
args: fmt::Arguments<'_>,
`
1001
``
`-
local_s: &'static LocalKey<RefCell<Option<Box>>>,
`
1002
``
`-
global_s: fn() -> T,
`
1003
``
`-
label: &str,
`
1004
``
`-
) where
`
``
920
`+
fn print_to(args: fmt::Arguments<'_>, global_s: fn() -> T, label: &str)
`
``
921
`+
where
`
1005
922
`T: Write,
`
1006
923
`{
`
1007
``
`-
let result = LOCAL_STREAMS
`
1008
``
`-
.load(Ordering::Relaxed)
`
1009
``
`-
.then(|| {
`
1010
``
`-
local_s
`
1011
``
`-
.try_with(|s| {
`
1012
``
`-
// Note that we completely remove a local sink to write to in case
`
1013
``
`-
// our printing recursively panics/prints, so the recursive
`
1014
``
`-
// panic/print goes to the global sink instead of our local sink.
`
1015
``
`-
let prev = s.borrow_mut().take();
`
1016
``
`-
if let Some(mut w) = prev {
`
1017
``
`-
let result = w.write_fmt(args);
`
1018
``
`-
*s.borrow_mut() = Some(w);
`
1019
``
`-
return result;
`
1020
``
`-
}
`
1021
``
`-
global_s().write_fmt(args)
`
1022
``
`-
})
`
1023
``
`-
.ok()
`
1024
``
`-
})
`
1025
``
`-
.flatten()
`
1026
``
`-
.unwrap_or_else(|| global_s().write_fmt(args));
`
1027
``
-
1028
``
`-
if let Err(e) = result {
`
``
924
`+
if OUTPUT_CAPTURE_USED.load(Ordering::Relaxed)
`
``
925
`+
&& OUTPUT_CAPTURE.try_with(|s| {
`
``
926
`+
// Note that we completely remove a local sink to write to in case
`
``
927
`+
// our printing recursively panics/prints, so the recursive
`
``
928
`+
// panic/print goes to the global sink instead of our local sink.
`
``
929
`+
s.take().map(|w| {
`
``
930
`+
let _ = w.lock().unwrap_or_else(|e| e.into_inner()).write_fmt(args);
`
``
931
`+
s.set(Some(w));
`
``
932
`+
})
`
``
933
`+
}) == Ok(Some(()))
`
``
934
`+
{
`
``
935
`+
// Succesfully wrote to capture buffer.
`
``
936
`+
return;
`
``
937
`+
}
`
``
938
+
``
939
`+
if let Err(e) = global_s().write_fmt(args) {
`
1029
940
`panic!("failed printing to {}: {}", label, e);
`
1030
941
`}
`
1031
942
`}
`
`@@ -1038,7 +949,7 @@ fn print_to(
`
1038
949
`#[doc(hidden)]
`
1039
950
`#[cfg(not(test))]
`
1040
951
`pub fn _print(args: fmt::Arguments<'_>) {
`
1041
``
`-
print_to(args, &LOCAL_STDOUT, stdout, "stdout");
`
``
952
`+
print_to(args, stdout, "stdout");
`
1042
953
`}
`
1043
954
``
1044
955
`#[unstable(
`
`@@ -1049,7 +960,7 @@ pub fn _print(args: fmt::Arguments<'_>) {
`
1049
960
`#[doc(hidden)]
`
1050
961
`#[cfg(not(test))]
`
1051
962
`pub fn _eprint(args: fmt::Arguments<'_>) {
`
1052
``
`-
print_to(args, &LOCAL_STDERR, stderr, "stderr");
`
``
963
`+
print_to(args, stderr, "stderr");
`
1053
964
`}
`
1054
965
``
1055
966
`#[cfg(test)]
`