From f97e8458b8181b5e09f933d034a0188d663dacbc Mon Sep 17 00:00:00 2001 From: WangRunji Date: Sun, 11 Nov 2018 23:08:59 +0800 Subject: [PATCH] impl stdin & stdout as INode --- kernel/src/console.rs | 30 +----------------- kernel/src/fs.rs | 74 +++++++++++++++++++++++++++++++++++++++++-- kernel/src/logging.rs | 2 +- kernel/src/syscall.rs | 42 ++++++++---------------- kernel/src/trap.rs | 2 +- 5 files changed, 89 insertions(+), 61 deletions(-) diff --git a/kernel/src/console.rs b/kernel/src/console.rs index 178b268..01798ad 100644 --- a/kernel/src/console.rs +++ b/kernel/src/console.rs @@ -1,8 +1,6 @@ use core::ops::Deref; use alloc::string::String; use alloc::collections::VecDeque; -use sync::Condvar; -use sync::SpinNoIrqLock as Mutex; pub fn get_line() -> String { let mut s = String::new(); @@ -27,32 +25,6 @@ pub fn get_line() -> String { } } -#[derive(Default)] -pub struct InputQueue { - buf: Mutex>, - pushed: Condvar, -} - -impl InputQueue { - pub fn push(&self, c: char) { - self.buf.lock().push_back(c); - self.pushed.notify_one(); - } - pub fn pop(&self) -> char { - loop { - let ret = self.buf.lock().pop_front(); - match ret { - Some(c) => return c, - None => self.pushed._wait(), - } - } - } -} - -lazy_static! { - pub static ref CONSOLE_INPUT: InputQueue = InputQueue::default(); -} - pub fn get_char() -> char { - CONSOLE_INPUT.pop() + ::fs::STDIN.pop() } diff --git a/kernel/src/fs.rs b/kernel/src/fs.rs index b7b85d3..bb8c965 100644 --- a/kernel/src/fs.rs +++ b/kernel/src/fs.rs @@ -1,8 +1,10 @@ use simple_filesystem::*; -use alloc::{boxed::Box, sync::Arc}; +use alloc::{boxed::Box, sync::Arc, string::String, collections::VecDeque}; #[cfg(target_arch = "x86_64")] use arch::driver::ide; -use spin::Mutex; +use sync::Condvar; +use sync::SpinNoIrqLock as Mutex; +use core::any::Any; // Hard link user program #[cfg(target_arch = "riscv32")] @@ -101,4 +103,72 @@ impl BlockedDevice for ide::IDE { let buf = unsafe { slice::from_raw_parts(buf.as_ptr() as *mut u32, ide::BLOCK_SIZE / 4) }; self.write(block_id as u64, 1, buf).is_ok() } +} + +#[derive(Default)] +pub struct Stdin { + buf: Mutex>, + pushed: Condvar, +} + +impl Stdin { + pub fn push(&self, c: char) { + self.buf.lock().push_back(c); + self.pushed.notify_one(); + } + pub fn pop(&self) -> char { + loop { + let ret = self.buf.lock().pop_front(); + match ret { + Some(c) => return c, + None => self.pushed._wait(), + } + } + } +} + +#[derive(Default)] +pub struct Stdout; + +lazy_static! { + pub static ref STDIN: Arc = Arc::new(Stdin::default()); + pub static ref STDOUT: Arc = Arc::new(Stdout::default()); +} + +// TODO: better way to provide default impl? +macro_rules! impl_inode { + () => { + fn info(&self) -> Result { unimplemented!() } + fn sync(&self) -> Result<()> { unimplemented!() } + fn resize(&self, len: usize) -> Result<()> { unimplemented!() } + fn create(&self, name: &str, type_: FileType) -> Result> { unimplemented!() } + fn unlink(&self, name: &str) -> Result<()> { unimplemented!() } + fn link(&self, name: &str, other: &Arc) -> Result<()> { unimplemented!() } + fn rename(&self, old_name: &str, new_name: &str) -> Result<()> { unimplemented!() } + fn move_(&self, old_name: &str, target: &Arc, new_name: &str) -> Result<()> { unimplemented!() } + fn find(&self, name: &str) -> Result> { unimplemented!() } + fn get_entry(&self, id: usize) -> Result { unimplemented!() } + fn fs(&self) -> Arc { unimplemented!() } + fn as_any_ref(&self) -> &Any { self } + }; +} + +impl INode for Stdin { + fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result { + buf[0] = self.pop() as u8; + Ok(1) + } + fn write_at(&self, offset: usize, buf: &[u8]) -> Result { unimplemented!() } + impl_inode!(); +} + +impl INode for Stdout { + fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result { unimplemented!() } + fn write_at(&self, offset: usize, buf: &[u8]) -> Result { + use core::str; + let s = str::from_utf8(buf).map_err(|_| ())?; + print!("{}", s); + Ok(buf.len()) + } + impl_inode!(); } \ No newline at end of file diff --git a/kernel/src/logging.rs b/kernel/src/logging.rs index b860de6..33edd25 100644 --- a/kernel/src/logging.rs +++ b/kernel/src/logging.rs @@ -78,7 +78,7 @@ impl From for Color { Level::Error => Color::Red, Level::Warn => Color::Yellow, Level::Info => Color::Blue, - Level::Debug => Color::LightRed, + Level::Debug => Color::Green, Level::Trace => Color::DarkGray, } } diff --git a/kernel/src/syscall.rs b/kernel/src/syscall.rs index 61d8d80..6a330e0 100644 --- a/kernel/src/syscall.rs +++ b/kernel/src/syscall.rs @@ -59,27 +59,16 @@ fn sys_read(fd: usize, base: *mut u8, len: usize) -> SysResult { // TODO: check ptr info!("read: fd: {}, base: {:?}, len: {:#x}", fd, base, len); let slice = unsafe { slice::from_raw_parts_mut(base, len) }; - match fd { - 0 => unimplemented!(), - 1 | 2 => return Err(SysError::InvalidFile), - _ => { get_file(fd)?.lock().read(slice)?; } - } - Ok(0) + let len = get_file(fd)?.lock().read(slice)?; + Ok(len as i32) } fn sys_write(fd: usize, base: *const u8, len: usize) -> SysResult { // TODO: check ptr info!("write: fd: {}, base: {:?}, len: {:#x}", fd, base, len); let slice = unsafe { slice::from_raw_parts(base, len) }; - match fd { - 0 => return Err(SysError::InvalidFile), - 1 | 2 => { - let s = str::from_utf8(slice).map_err(|_| SysError::InvalidArgument)?; - print!("{}", s); - }, - _ => { get_file(fd)?.lock().write(slice)?; } - } - Ok(0) + let len = get_file(fd)?.lock().write(slice)?; + Ok(len as i32) } fn sys_open(path: *const u8, flags: usize) -> SysResult { @@ -87,25 +76,22 @@ fn sys_open(path: *const u8, flags: usize) -> SysResult { let path = unsafe { util::from_cstr(path) }; let flags = VfsFlags::from_ucore_flags(flags); info!("open: path: {:?}, flags: {:?}", path, flags); - match path { - "stdin:" => return Ok(0), - "stdout:" => return Ok(1), - "stderr:" => return Ok(2), - _ => {} - } - let inode = ::fs::ROOT_INODE.lookup(path)?; - let files = &mut process().files; - let fd = (3..).find(|i| !files.contains_key(i)).unwrap(); + let (fd, inode) = match path { + "stdin:" => (0, ::fs::STDIN.clone() as Arc), + "stdout:" => (1, ::fs::STDOUT.clone() as Arc), + _ => { + let fd = (3..).find(|i| !process().files.contains_key(i)).unwrap(); + let inode = ::fs::ROOT_INODE.lookup(path)?; + (fd, inode) + } + }; let file = File::new(inode, flags.contains(VfsFlags::READABLE), flags.contains(VfsFlags::WRITABLE)); - files.insert(fd, Arc::new(Mutex::new(file))); + process().files.insert(fd, Arc::new(Mutex::new(file))); Ok(fd as i32) } fn sys_close(fd: usize) -> SysResult { info!("close: fd: {:?}", fd); - if fd < 3 { - return Ok(0); - } match process().files.remove(&fd) { Some(_) => Ok(0), None => Err(SysError::InvalidFile), diff --git a/kernel/src/trap.rs b/kernel/src/trap.rs index acfd17a..99ba7b1 100644 --- a/kernel/src/trap.rs +++ b/kernel/src/trap.rs @@ -22,5 +22,5 @@ pub fn error(tf: &TrapFrame) -> ! { } pub fn serial(c: char) { - ::console::CONSOLE_INPUT.push(c); + ::fs::STDIN.push(c); } \ No newline at end of file