From 02f202ff839487895701779df9c26e16acd17748 Mon Sep 17 00:00:00 2001 From: Mateusz Tabaka <tab.debugteam@gmail.com> Date: Thu, 14 Jan 2021 17:30:46 +0100 Subject: [PATCH] Use BufWriter (instead of LineWriter) for FILEs other than stdout and stderr BufWriter has more capacity (8k vs 1k) and doesn't flush the stream after '\n'. That change helps to reduce the number of syscalls, especially when dealing with text files. Since BufWriter has a different way of getting number of pending elements than LineWriter - Pending trait was introduced to deal with that. --- src/header/stdio/default.rs | 4 ++-- src/header/stdio/ext.rs | 2 +- src/header/stdio/helpers.rs | 4 ++-- src/header/stdio/mod.rs | 34 ++++++++++++++++++++++++++-- src/header/stdlib/mod.rs | 3 +++ tests/expected/wchar/putwchar.stdout | 1 + 6 files changed, 41 insertions(+), 7 deletions(-) diff --git a/src/header/stdio/default.rs b/src/header/stdio/default.rs index 90aa709b..341d76bd 100644 --- a/src/header/stdio/default.rs +++ b/src/header/stdio/default.rs @@ -2,13 +2,13 @@ use super::{constants, Buffer, BUFSIZ, FILE}; use core::{cell::UnsafeCell, ptr}; use crate::{fs::File, io::LineWriter, platform::types::*, sync::Mutex}; -use alloc::vec::Vec; +use alloc::{boxed::Box, vec::Vec}; pub struct GlobalFile(UnsafeCell<FILE>); impl GlobalFile { fn new(file: c_int, flags: c_int) -> Self { let file = File::new(file); - let writer = LineWriter::new(unsafe { file.get_ref() }); + let writer = Box::new(LineWriter::new(unsafe { file.get_ref() })); GlobalFile(UnsafeCell::new(FILE { lock: Mutex::new(()), diff --git a/src/header/stdio/ext.rs b/src/header/stdio/ext.rs index 28bb7344..08aff1b2 100644 --- a/src/header/stdio/ext.rs +++ b/src/header/stdio/ext.rs @@ -7,7 +7,7 @@ use crate::{ pub extern "C" fn __fpending(stream: *mut FILE) -> size_t { let stream = unsafe { &mut *stream }.lock(); - stream.writer.inner.buf.len() as size_t + stream.writer.pending() } #[no_mangle] diff --git a/src/header/stdio/helpers.rs b/src/header/stdio/helpers.rs index be7aa9fa..dc42b100 100644 --- a/src/header/stdio/helpers.rs +++ b/src/header/stdio/helpers.rs @@ -4,7 +4,7 @@ use super::{constants::*, Buffer, FILE}; use crate::{ fs::File, header::{errno, fcntl::*, string::strchr}, - io::LineWriter, + io::BufWriter, platform::{self, types::*}, sync::Mutex, }; @@ -62,7 +62,7 @@ pub unsafe fn _fdopen(fd: c_int, mode: *const c_char) -> Option<*mut FILE> { } let file = File::new(fd); - let writer = LineWriter::new(file.get_ref()); + let writer = Box::new(BufWriter::new(file.get_ref())); Some(Box::into_raw(Box::new(FILE { lock: Mutex::new(()), diff --git a/src/header/stdio/mod.rs b/src/header/stdio/mod.rs index f6625766..52bee273 100644 --- a/src/header/stdio/mod.rs +++ b/src/header/stdio/mod.rs @@ -24,7 +24,7 @@ use crate::{ string::{self, strlen}, unistd, }, - io::{self, BufRead, LineWriter, Read, Write}, + io::{self, BufRead, BufWriter, LineWriter, Read, Write}, platform::{self, errno, types::*, Pal, Sys, WriteByte}, sync::Mutex, }; @@ -69,6 +69,27 @@ impl<'a> DerefMut for Buffer<'a> { } } +pub trait Pending { + fn pending(&self) -> size_t; +} + +impl<W: core_io::Write> Pending for BufWriter<W> { + fn pending(&self) -> size_t { + self.buf.len() as size_t + } +} + +impl<W: core_io::Write> Pending for LineWriter<W> { + fn pending(&self) -> size_t { + self.inner.buf.len() as size_t + } +} + +pub trait Writer: Write + Pending {} + +impl<W: core_io::Write> Writer for BufWriter<W> {} +impl<W: core_io::Write> Writer for LineWriter<W> {} + /// This struct gets exposed to the C API. pub struct FILE { lock: Mutex<()>, @@ -81,7 +102,7 @@ pub struct FILE { read_size: usize, unget: Vec<u8>, // pub for stdio_ext - pub(crate) writer: LineWriter<File>, + pub(crate) writer: Box<dyn Writer + Send>, // Optional pid for use with popen/pclose pid: Option<c_int>, @@ -1145,3 +1166,12 @@ pub unsafe extern "C" fn vsscanf(s: *const c_char, format: *const c_char, ap: va let reader = (s as *const u8).into(); scanf::scanf(reader, format, ap) } + +pub unsafe fn flush_io_streams() { + let flush = |stream: *mut FILE| { + let stream = &mut *stream; + stream.flush() + }; + flush(stdout); + flush(stderr); +} diff --git a/src/header/stdlib/mod.rs b/src/header/stdlib/mod.rs index daaf72be..db708bce 100644 --- a/src/header/stdlib/mod.rs +++ b/src/header/stdlib/mod.rs @@ -16,6 +16,7 @@ use crate::{ errno::{self, *}, fcntl::*, limits, + stdio::flush_io_streams, string::*, time::constants::CLOCK_MONOTONIC, unistd::{self, sysconf, _SC_PAGESIZE}, @@ -297,6 +298,8 @@ pub unsafe extern "C" fn exit(status: c_int) { pthread_terminate(); + flush_io_streams(); + Sys::exit(status); } diff --git a/tests/expected/wchar/putwchar.stdout b/tests/expected/wchar/putwchar.stdout index e69de29b..42d65d1d 100644 --- a/tests/expected/wchar/putwchar.stdout +++ b/tests/expected/wchar/putwchar.stdout @@ -0,0 +1 @@ +zß水🌠\ No newline at end of file -- GitLab