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)]

`