diff --git a/os/src/fs/mod.rs b/os/src/fs/mod.rs index e481a78f..853ef41a 100644 --- a/os/src/fs/mod.rs +++ b/os/src/fs/mod.rs @@ -11,10 +11,11 @@ pub trait File : Any + Send + Sync { } impl dyn File { + #[allow(unused)] pub fn downcast_ref(&self) -> Option<&T> { self.as_any_ref().downcast_ref::() } } -pub use pipe::{Pipe}; +pub use pipe::{Pipe, make_pipe}; pub use stdio::{Stdin, Stdout}; \ No newline at end of file diff --git a/os/src/fs/pipe.rs b/os/src/fs/pipe.rs index 266c43a0..ccbc53e0 100644 --- a/os/src/fs/pipe.rs +++ b/os/src/fs/pipe.rs @@ -44,7 +44,7 @@ pub struct PipeRingBuffer { head: usize, tail: usize, status: RingBufferStatus, - write_end: Option>>, + write_end: Option>, } impl PipeRingBuffer { @@ -57,7 +57,7 @@ impl PipeRingBuffer { write_end: None, } } - pub fn set_write_end(&mut self, write_end: &Arc>) { + pub fn set_write_end(&mut self, write_end: &Arc) { self.write_end = Some(Arc::downgrade(write_end)); } pub fn write_byte(&mut self, byte: u8) { @@ -101,14 +101,14 @@ impl PipeRingBuffer { } /// Return (read_end, write_end) -pub fn make_pipe() -> (Arc>, Arc>) { +pub fn make_pipe() -> (Arc, Arc) { let buffer = Arc::new(Mutex::new(PipeRingBuffer::new())); - let read_end = Arc::new(Mutex::new( + let read_end = Arc::new( Pipe::read_end_with_buffer(buffer.clone()) - )); - let write_end = Arc::new(Mutex::new( + ); + let write_end = Arc::new( Pipe::write_end_with_buffer(buffer.clone()) - )); + ); buffer.lock().set_write_end(&write_end); (read_end, write_end) } diff --git a/os/src/fs/stdio.rs b/os/src/fs/stdio.rs index 4854118b..841849ef 100644 --- a/os/src/fs/stdio.rs +++ b/os/src/fs/stdio.rs @@ -1,5 +1,5 @@ use super::File; -use crate::mm::{UserBuffer, UserBufferIterator}; +use crate::mm::{UserBuffer}; use crate::sbi::console_getchar; use crate::task::suspend_current_and_run_next; use core::any::Any; diff --git a/os/src/mm/page_table.rs b/os/src/mm/page_table.rs index 93364e18..47f39a76 100644 --- a/os/src/mm/page_table.rs +++ b/os/src/mm/page_table.rs @@ -164,7 +164,11 @@ pub fn translated_byte_buffer(token: usize, ptr: *const u8, len: usize) -> Vec<& vpn.step(); let mut end_va: VirtAddr = vpn.into(); end_va = end_va.min(VirtAddr::from(end)); - v.push(&mut ppn.get_bytes_array()[start_va.page_offset()..end_va.page_offset()]); + if end_va.page_offset() == 0 { + v.push(&mut ppn.get_bytes_array()[start_va.page_offset()..]); + } else { + v.push(&mut ppn.get_bytes_array()[start_va.page_offset()..end_va.page_offset()]); + } start = end_va.into(); } v diff --git a/os/src/syscall/fs.rs b/os/src/syscall/fs.rs index 1192af17..e4800fa9 100644 --- a/os/src/syscall/fs.rs +++ b/os/src/syscall/fs.rs @@ -1,5 +1,6 @@ -use crate::mm::{UserBuffer, translated_byte_buffer}; +use crate::mm::{UserBuffer, translated_byte_buffer, translated_refmut}; use crate::task::{current_user_token, current_task}; +use crate::fs::{make_pipe}; pub fn sys_write(fd: usize, buf: *const u8, len: usize) -> isize { let token = current_user_token(); @@ -12,9 +13,9 @@ pub fn sys_write(fd: usize, buf: *const u8, len: usize) -> isize { let file = file.clone(); // release Task lock manually to avoid deadlock drop(inner); - file.write(UserBuffer { - buffers: translated_byte_buffer(token, buf, len), - }) as isize + file.write( + UserBuffer::new(translated_byte_buffer(token, buf, len)) + ) as isize } else { -1 } @@ -31,10 +32,37 @@ pub fn sys_read(fd: usize, buf: *const u8, len: usize) -> isize { let file = file.clone(); // release Task lock manually to avoid deadlock drop(inner); - file.read(UserBuffer { - buffers: translated_byte_buffer(token, buf, len), - }) as isize + file.read( + UserBuffer::new(translated_byte_buffer(token, buf, len)) + ) as isize } else { -1 } +} + +pub fn sys_close(fd: usize) -> isize { + let task = current_task().unwrap(); + let mut inner = task.acquire_inner_lock(); + if fd >= inner.fd_table.len() { + return -1; + } + if inner.fd_table[fd].is_none() { + return -1; + } + inner.fd_table[fd].take(); + 0 +} + +pub fn sys_pipe(pipe: *mut usize) -> isize { + let task = current_task().unwrap(); + let token = current_user_token(); + let mut inner = task.acquire_inner_lock(); + let (pipe_read, pipe_write) = make_pipe(); + let read_fd = inner.alloc_fd(); + inner.fd_table[read_fd] = Some(pipe_read); + let write_fd = inner.alloc_fd(); + inner.fd_table[write_fd] = Some(pipe_write); + *translated_refmut(token, pipe) = read_fd; + *translated_refmut(token, unsafe { pipe.add(1) }) = write_fd; + 0 } \ No newline at end of file diff --git a/os/src/syscall/mod.rs b/os/src/syscall/mod.rs index 81ade837..1699e8ca 100644 --- a/os/src/syscall/mod.rs +++ b/os/src/syscall/mod.rs @@ -1,3 +1,5 @@ +const SYSCALL_CLOSE: usize = 57; +const SYSCALL_PIPE: usize = 59; const SYSCALL_READ: usize = 63; const SYSCALL_WRITE: usize = 64; const SYSCALL_EXIT: usize = 93; @@ -16,6 +18,8 @@ use process::*; pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize { match syscall_id { + SYSCALL_CLOSE => sys_close(args[0]), + SYSCALL_PIPE => sys_pipe(args[0] as *mut usize), SYSCALL_READ => sys_read(args[0], args[1] as *const u8, args[2]), SYSCALL_WRITE => sys_write(args[0], args[1] as *const u8, args[2]), SYSCALL_EXIT => sys_exit(args[0] as i32), diff --git a/os/src/task/task.rs b/os/src/task/task.rs index e1be05a4..b0fe7a49 100644 --- a/os/src/task/task.rs +++ b/os/src/task/task.rs @@ -45,6 +45,15 @@ impl TaskControlBlockInner { pub fn is_zombie(&self) -> bool { self.get_status() == TaskStatus::Zombie } + pub fn alloc_fd(&mut self) -> usize { + if let Some(fd) = (0..self.fd_table.len()) + .find(|fd| self.fd_table[*fd].is_none()) { + fd + } else { + self.fd_table.push(None); + self.fd_table.len() - 1 + } + } } impl TaskControlBlock { @@ -78,7 +87,11 @@ impl TaskControlBlock { children: Vec::new(), exit_code: 0, fd_table: vec![ + // 0 -> stdin Some(Arc::new(Stdin)), + // 1 -> stdout + Some(Arc::new(Stdout)), + // 2 -> stderr Some(Arc::new(Stdout)), ], }), @@ -181,6 +194,7 @@ impl TaskControlBlock { pub fn getpid(&self) -> usize { self.pid.0 } + } #[derive(Copy, Clone, PartialEq)] diff --git a/os/src/trap/mod.rs b/os/src/trap/mod.rs index f7b0bc29..58881b1b 100644 --- a/os/src/trap/mod.rs +++ b/os/src/trap/mod.rs @@ -108,6 +108,7 @@ pub fn trap_return() -> ! { } let restore_va = __restore as usize - __alltraps as usize + TRAMPOLINE; unsafe { + llvm_asm!("fence.i" :::: "volatile"); llvm_asm!("jr $0" :: "r"(restore_va), "{a0}"(trap_cx_ptr), "{a1}"(user_satp) :: "volatile"); } panic!("Unreachable in back_to_user!"); diff --git a/user/src/bin/pipe_large_test.rs b/user/src/bin/pipe_large_test.rs new file mode 100644 index 00000000..121987be --- /dev/null +++ b/user/src/bin/pipe_large_test.rs @@ -0,0 +1,69 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +extern crate alloc; + +use user_lib::{fork, close, pipe, read, write, wait, get_time}; +use alloc::format; + +const LENGTH: usize = 3000; +#[no_mangle] +pub fn main() -> i32 { + // create pipes + // parent write to child + let mut down_pipe_fd = [0usize; 2]; + // child write to parent + let mut up_pipe_fd = [0usize; 2]; + pipe(&mut down_pipe_fd); + pipe(&mut up_pipe_fd); + let mut random_str = [0u8; LENGTH]; + if fork() == 0 { + // close write end of down pipe + close(down_pipe_fd[1]); + // close read end of up pipe + close(up_pipe_fd[0]); + assert_eq!(read(down_pipe_fd[0], &mut random_str) as usize, LENGTH); + close(down_pipe_fd[0]); + let sum: usize = random_str.iter().map(|v| *v as usize).sum::(); + println!("sum = {}(child)", sum); + let sum_str = format!("{}", sum); + write(up_pipe_fd[1], sum_str.as_bytes()); + close(up_pipe_fd[1]); + println!("Child process exited!"); + 0 + } else { + // close read end of down pipe + close(down_pipe_fd[0]); + // close write end of up pipe + close(up_pipe_fd[1]); + // generate a long random string + for i in 0..LENGTH { + random_str[i] = get_time() as u8; + } + // send it + assert_eq!(write(down_pipe_fd[1], &random_str) as usize, random_str.len()); + // close write end of down pipe + close(down_pipe_fd[1]); + // calculate sum(parent) + let sum: usize = random_str.iter().map(|v| *v as usize).sum::(); + println!("sum = {}(parent)", sum); + // recv sum(child) + let mut child_result = [0u8; 32]; + let result_len = read(up_pipe_fd[0], &mut child_result) as usize; + close(up_pipe_fd[0]); + // check + assert_eq!( + sum, + str::parse::( + core::str::from_utf8(&child_result[..result_len]).unwrap() + ).unwrap() + ); + let mut _unused: i32 = 0; + wait(&mut _unused); + println!("pipe_large_test passed!"); + 0 + } +} \ No newline at end of file diff --git a/user/src/bin/pipetest.rs b/user/src/bin/pipetest.rs new file mode 100644 index 00000000..58237847 --- /dev/null +++ b/user/src/bin/pipetest.rs @@ -0,0 +1,42 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::{fork, close, pipe, read, write, wait}; + +static STR: &str = "Hello, world!"; + +#[no_mangle] +pub fn main() -> i32 { + // create pipe + let mut pipe_fd = [0usize; 2]; + pipe(&mut pipe_fd); + // read end + assert_eq!(pipe_fd[0], 3); + // write end + assert_eq!(pipe_fd[1], 4); + if fork() == 0 { + // child process, read from parent + // close write_end + close(pipe_fd[1]); + let mut buffer = [0u8; 32]; + let len_read = read(pipe_fd[0], &mut buffer) as usize; + assert_eq!(core::str::from_utf8(&buffer[..len_read]).unwrap(), STR); + println!("Read OK, child process exited!"); + 0 + } else { + // parent process, write to child + // close read end + close(pipe_fd[0]); + assert_eq!(write(pipe_fd[1], STR.as_bytes()), STR.len() as isize); + // close write end + close(pipe_fd[1]); + let mut child_exit_code: i32 = 0; + wait(&mut child_exit_code); + assert_eq!(child_exit_code, 0); + println!("pipetest passed!"); + 0 + } +} \ No newline at end of file diff --git a/user/src/bin/run_pipe_test.rs b/user/src/bin/run_pipe_test.rs new file mode 100644 index 00000000..ca2afd15 --- /dev/null +++ b/user/src/bin/run_pipe_test.rs @@ -0,0 +1,21 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::{fork, exec, wait}; + +#[no_mangle] +pub fn main() -> i32 { + for i in 0..1000 { + if fork() == 0 { + exec("pipe_large_test\0"); + } else { + let mut _unused: i32 = 0; + wait(&mut _unused); + println!("Iter {} OK.", i); + } + } + 0 +} \ No newline at end of file diff --git a/user/src/lang_items.rs b/user/src/lang_items.rs index c90d297f..b5b98e08 100644 --- a/user/src/lang_items.rs +++ b/user/src/lang_items.rs @@ -1,3 +1,5 @@ +use super::exit; + #[panic_handler] fn panic_handler(panic_info: &core::panic::PanicInfo) -> ! { let err = panic_info.message().unwrap(); @@ -6,5 +8,5 @@ fn panic_handler(panic_info: &core::panic::PanicInfo) -> ! { } else { println!("Panicked: {}", err); } - loop {} + exit(-1); } \ No newline at end of file diff --git a/user/src/lib.rs b/user/src/lib.rs index 5c434e6d..32482859 100644 --- a/user/src/lib.rs +++ b/user/src/lib.rs @@ -9,6 +9,8 @@ pub mod console; mod syscall; mod lang_items; +extern crate alloc; + use syscall::*; use buddy_system_allocator::LockedHeap; @@ -40,6 +42,8 @@ fn main() -> i32 { panic!("Cannot find main!"); } +pub fn close(fd: usize) -> isize { sys_close(fd) } +pub fn pipe(pipe_fd: &mut [usize]) -> isize { sys_pipe(pipe_fd) } pub fn read(fd: usize, buf: &mut [u8]) -> isize { sys_read(fd, buf) } pub fn write(fd: usize, buf: &[u8]) -> isize { sys_write(fd, buf) } pub fn exit(exit_code: i32) -> ! { sys_exit(exit_code); } diff --git a/user/src/syscall.rs b/user/src/syscall.rs index 6a6721f2..76683649 100644 --- a/user/src/syscall.rs +++ b/user/src/syscall.rs @@ -1,3 +1,5 @@ +const SYSCALL_CLOSE: usize = 57; +const SYSCALL_PIPE: usize = 59; const SYSCALL_READ: usize = 63; const SYSCALL_WRITE: usize = 64; const SYSCALL_EXIT: usize = 93; @@ -21,6 +23,14 @@ fn syscall(id: usize, args: [usize; 3]) -> isize { ret } +pub fn sys_close(fd: usize) -> isize { + syscall(SYSCALL_CLOSE, [fd, 0, 0]) +} + +pub fn sys_pipe(pipe: &mut [usize]) -> isize { + syscall(SYSCALL_PIPE, [pipe.as_mut_ptr() as usize, 0, 0]) +} + pub fn sys_read(fd: usize, buffer: &mut [u8]) -> isize { syscall(SYSCALL_READ, [fd, buffer.as_mut_ptr() as usize, buffer.len()]) }