Hello
,
I have a question about the implementation of print macros in Rust.
It seems that the Stdout used by print! and println! macros is wrapped by a
RefCell, and locks are also used to provide thread safety in writing to Stdout.
/* From: /src/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)
}
}
/* From: src/libstd/io/stdio.rs */
#[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 write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
self.lock().write_vectored(bufs)
}
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)
}
}
It also seems that eventually, writing to stdout in Rust invokes a call to libc::write as below.
/* From: src/libstd/sys/unix/fd.rs */
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)
}
I picked up from the web that the write() function in glibc is thread-safe.
In that case, (confining just to Unix/Linux) is it safe to say that print macros in Rust suffer from redundant synchronization?
- synchronization in the Rust wrapping around invocation of
libc::write - synchronization inside the implementation of
libc::write)
Please correct me if I have misunderstood anything.. Thank you for reading.