Hi I'm trying to understand how stdio::_print_to works internally, in libstd/io/stdio.rs
thread_local! {
/// Stdout used by print! and println! macros
static LOCAL_STDOUT: RefCell<Option<Box<dyn Write + Send>>> = {
RefCell::new(None)
}
}
LOCAL_STDOUT was initialized to None, but when I run a simple "Hello Rust" program with rust-gdb, I saw the value is not None.
p local_s
$1 = (struct LocalKey<core::cell::RefCell<core::option::Option<alloc::boxed::Box<Write>>>> *) 0x5555558227d8
My question is who initialized LOCAL_STDOUT? Thanks.
Wait, wrong code
LOCAL_STDOUT
should only be Some
when during tests.
Looking at the code I see that _print calls
print_to with a reference to
LOCAL_STDOUT`: https://github.com/rust-lang/rust/blob/f8d394e5184fe3af761ea1e5ba73f993cfb36dfe/src/libstd/io/stdio.rs#L890
print_to
then simply uses the global output when LOCAL_STDOUT
is none: https://github.com/rust-lang/rust/blob/f8d394e5184fe3af761ea1e5ba73f993cfb36dfe/src/libstd/io/stdio.rs#L854-L880
Thanks! @bjorn3 seems LOCAL_STDOUT is not none in my simple "Hello Rust" program. I compiled rustc by myself, so line number is little different.
Breakpoint 1, std::io::stdio::print_to::_$u7b$$u7b$closure$u7d$$u7d$::h42c135b27158b526 (s=0x7ffff7fa0760) at src/libstd/io/stdio.rs:781
781 if let Ok(mut borrowed) = s.try_borrow_mut() {
(gdb) p s
$2 = (struct RefCell<core::option::Option<alloc::boxed::Box<Write>>> *) 0x7ffff7fa0760
(gdb) n
781 if let Ok(mut borrowed) = s.try_borrow_mut() {
782 if let Some(w) = borrowed.as_mut() {
(gdb) p borrowed
$3 = RefMut<core::option::Option<alloc::boxed::Box<Write>>> = {value = 0x7ffff7fa0768, borrow = BorrowRefMut = {borrow = 0x7ffff7fa0760}}
borrowed.as_mut() returned None, so it called global_s().write_fmt(args)
I don't understand who set LOCAL_STDOUT to Some()
using grep, I found LOCAL_STDOUT in src/librustc_codegen_llvm/consts.rs, not sure if that related.
What does borrowed.value
dereference to? borrowed.value
is a pointer to the Option<Box<dyn Write>>
.
@yunhua ^
@bjorn3
(gdb) p borrowed
$16 = RefMut<core::option::Option<alloc::boxed::Box<Write>>> = {value = 0x7ffff7fa0768, borrow = BorrowRefMut = {borrow = 0x7ffff7fa0760}}
(gdb) p *borrowed.value
$17 = Option<alloc::boxed::Box<Write>>
(gdb) x/2w borrowed.value
0x7ffff7fa0768: 0 0
So can we confirm borrowed.value is None here? As x/2w given 0,0. Thanks.