Skip to main content

jsph_tg_arceos_tutorial_exercise_hashmap_axstd/io/
stdio.rs

1use crate::io::{self, BufReader, prelude::*};
2use crate::sync::{Mutex, MutexGuard};
3use lazyinit::LazyInit;
4
5#[cfg(feature = "alloc")]
6use alloc::{string::String, vec::Vec};
7
8struct StdinRaw;
9struct StdoutRaw;
10
11impl Read for StdinRaw {
12    // Non-blocking read, returns number of bytes read.
13    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
14        let mut read_len = 0;
15        while read_len < buf.len() {
16            let len = arceos_api::stdio::ax_console_read_bytes(buf[read_len..].as_mut())?;
17            if len == 0 {
18                break;
19            }
20            read_len += len;
21        }
22        Ok(read_len)
23    }
24}
25
26impl Write for StdoutRaw {
27    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
28        arceos_api::stdio::ax_console_write_bytes(buf)
29    }
30    fn flush(&mut self) -> io::Result<()> {
31        Ok(())
32    }
33}
34
35/// A handle to the standard input stream of a process.
36pub struct Stdin {
37    inner: &'static Mutex<BufReader<StdinRaw>>,
38}
39
40/// A locked reference to the [`Stdin`] handle.
41pub struct StdinLock<'a> {
42    inner: MutexGuard<'a, BufReader<StdinRaw>>,
43}
44
45impl Stdin {
46    /// Locks this handle to the standard input stream, returning a readable
47    /// guard.
48    ///
49    /// The lock is released when the returned lock goes out of scope. The
50    /// returned guard also implements the [`Read`] and [`BufRead`] traits for
51    /// accessing the underlying data.
52    pub fn lock(&self) -> StdinLock<'static> {
53        // Locks this handle with 'static lifetime. This depends on the
54        // implementation detail that the underlying `Mutex` is static.
55        StdinLock {
56            inner: self.inner.lock(),
57        }
58    }
59
60    /// Locks this handle and reads a line of input, appending it to the specified buffer.
61    #[cfg(feature = "alloc")]
62    pub fn read_line(&self, buf: &mut String) -> io::Result<usize> {
63        self.inner.lock().read_line(buf)
64    }
65}
66
67impl Read for Stdin {
68    // Block until at least one byte is read.
69    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
70        let read_len = self.inner.lock().read(buf)?;
71        if buf.is_empty() || read_len > 0 {
72            return Ok(read_len);
73        }
74        // try again until we got something
75        loop {
76            let read_len = self.inner.lock().read(buf)?;
77            if read_len > 0 {
78                return Ok(read_len);
79            }
80            crate::thread::yield_now();
81        }
82    }
83}
84
85impl Read for StdinLock<'_> {
86    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
87        self.inner.read(buf)
88    }
89}
90
91impl BufRead for StdinLock<'_> {
92    fn fill_buf(&mut self) -> io::Result<&[u8]> {
93        self.inner.fill_buf()
94    }
95
96    fn consume(&mut self, n: usize) {
97        self.inner.consume(n)
98    }
99
100    #[cfg(feature = "alloc")]
101    fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> io::Result<usize> {
102        self.inner.read_until(byte, buf)
103    }
104
105    #[cfg(feature = "alloc")]
106    fn read_line(&mut self, buf: &mut String) -> io::Result<usize> {
107        self.inner.read_line(buf)
108    }
109}
110
111/// A handle to the global standard output stream of the current process.
112pub struct Stdout {
113    inner: &'static Mutex<StdoutRaw>,
114}
115
116/// A locked reference to the [`Stdout`] handle.
117pub struct StdoutLock<'a> {
118    inner: MutexGuard<'a, StdoutRaw>,
119}
120
121impl Stdout {
122    /// Locks this handle to the standard output stream, returning a writable
123    /// guard.
124    ///
125    /// The lock is released when the returned lock goes out of scope. The
126    /// returned guard also implements the `Write` trait for writing data.
127    pub fn lock(&self) -> StdoutLock<'static> {
128        StdoutLock {
129            inner: self.inner.lock(),
130        }
131    }
132}
133
134impl Write for Stdout {
135    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
136        self.inner.lock().write(buf)
137    }
138    fn flush(&mut self) -> io::Result<()> {
139        self.inner.lock().flush()
140    }
141}
142
143impl Write for StdoutLock<'_> {
144    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
145        self.inner.write(buf)
146    }
147    fn flush(&mut self) -> io::Result<()> {
148        self.inner.flush()
149    }
150}
151
152/// Constructs a new handle to the standard input of the current process.
153pub fn stdin() -> Stdin {
154    static INSTANCE: LazyInit<Mutex<BufReader<StdinRaw>>> = LazyInit::new();
155    if !INSTANCE.is_inited() {
156        INSTANCE.init_once(Mutex::new(BufReader::new(StdinRaw)));
157    }
158    Stdin { inner: &INSTANCE }
159}
160
161/// Constructs a new handle to the standard output of the current process.
162pub fn stdout() -> Stdout {
163    static INSTANCE: LazyInit<Mutex<StdoutRaw>> = LazyInit::new();
164    if !INSTANCE.is_inited() {
165        INSTANCE.init_once(Mutex::new(StdoutRaw));
166    }
167    Stdout { inner: &INSTANCE }
168}
169
170#[doc(hidden)]
171pub fn __print_impl(args: core::fmt::Arguments) {
172    if cfg!(feature = "smp") {
173        // synchronize using the lock in axlog, to avoid interleaving
174        // with kernel logs
175        arceos_api::stdio::ax_console_write_fmt(args).unwrap();
176    } else {
177        stdout().lock().write_fmt(args).unwrap();
178    }
179}