Pipe OK.
This commit is contained in:
parent
2e6734027d
commit
8e178c0080
14 changed files with 218 additions and 18 deletions
|
@ -11,10 +11,11 @@ pub trait File : Any + Send + Sync {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl dyn File {
|
impl dyn File {
|
||||||
|
#[allow(unused)]
|
||||||
pub fn downcast_ref<T: File>(&self) -> Option<&T> {
|
pub fn downcast_ref<T: File>(&self) -> Option<&T> {
|
||||||
self.as_any_ref().downcast_ref::<T>()
|
self.as_any_ref().downcast_ref::<T>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use pipe::{Pipe};
|
pub use pipe::{Pipe, make_pipe};
|
||||||
pub use stdio::{Stdin, Stdout};
|
pub use stdio::{Stdin, Stdout};
|
|
@ -44,7 +44,7 @@ pub struct PipeRingBuffer {
|
||||||
head: usize,
|
head: usize,
|
||||||
tail: usize,
|
tail: usize,
|
||||||
status: RingBufferStatus,
|
status: RingBufferStatus,
|
||||||
write_end: Option<Weak<Mutex<Pipe>>>,
|
write_end: Option<Weak<Pipe>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PipeRingBuffer {
|
impl PipeRingBuffer {
|
||||||
|
@ -57,7 +57,7 @@ impl PipeRingBuffer {
|
||||||
write_end: None,
|
write_end: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn set_write_end(&mut self, write_end: &Arc<Mutex<Pipe>>) {
|
pub fn set_write_end(&mut self, write_end: &Arc<Pipe>) {
|
||||||
self.write_end = Some(Arc::downgrade(write_end));
|
self.write_end = Some(Arc::downgrade(write_end));
|
||||||
}
|
}
|
||||||
pub fn write_byte(&mut self, byte: u8) {
|
pub fn write_byte(&mut self, byte: u8) {
|
||||||
|
@ -101,14 +101,14 @@ impl PipeRingBuffer {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return (read_end, write_end)
|
/// Return (read_end, write_end)
|
||||||
pub fn make_pipe() -> (Arc<Mutex<Pipe>>, Arc<Mutex<Pipe>>) {
|
pub fn make_pipe() -> (Arc<Pipe>, Arc<Pipe>) {
|
||||||
let buffer = Arc::new(Mutex::new(PipeRingBuffer::new()));
|
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())
|
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())
|
Pipe::write_end_with_buffer(buffer.clone())
|
||||||
));
|
);
|
||||||
buffer.lock().set_write_end(&write_end);
|
buffer.lock().set_write_end(&write_end);
|
||||||
(read_end, write_end)
|
(read_end, write_end)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use super::File;
|
use super::File;
|
||||||
use crate::mm::{UserBuffer, UserBufferIterator};
|
use crate::mm::{UserBuffer};
|
||||||
use crate::sbi::console_getchar;
|
use crate::sbi::console_getchar;
|
||||||
use crate::task::suspend_current_and_run_next;
|
use crate::task::suspend_current_and_run_next;
|
||||||
use core::any::Any;
|
use core::any::Any;
|
||||||
|
|
|
@ -164,7 +164,11 @@ pub fn translated_byte_buffer(token: usize, ptr: *const u8, len: usize) -> Vec<&
|
||||||
vpn.step();
|
vpn.step();
|
||||||
let mut end_va: VirtAddr = vpn.into();
|
let mut end_va: VirtAddr = vpn.into();
|
||||||
end_va = end_va.min(VirtAddr::from(end));
|
end_va = end_va.min(VirtAddr::from(end));
|
||||||
|
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()]);
|
v.push(&mut ppn.get_bytes_array()[start_va.page_offset()..end_va.page_offset()]);
|
||||||
|
}
|
||||||
start = end_va.into();
|
start = end_va.into();
|
||||||
}
|
}
|
||||||
v
|
v
|
||||||
|
|
|
@ -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::task::{current_user_token, current_task};
|
||||||
|
use crate::fs::{make_pipe};
|
||||||
|
|
||||||
pub fn sys_write(fd: usize, buf: *const u8, len: usize) -> isize {
|
pub fn sys_write(fd: usize, buf: *const u8, len: usize) -> isize {
|
||||||
let token = current_user_token();
|
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();
|
let file = file.clone();
|
||||||
// release Task lock manually to avoid deadlock
|
// release Task lock manually to avoid deadlock
|
||||||
drop(inner);
|
drop(inner);
|
||||||
file.write(UserBuffer {
|
file.write(
|
||||||
buffers: translated_byte_buffer(token, buf, len),
|
UserBuffer::new(translated_byte_buffer(token, buf, len))
|
||||||
}) as isize
|
) as isize
|
||||||
} else {
|
} else {
|
||||||
-1
|
-1
|
||||||
}
|
}
|
||||||
|
@ -31,10 +32,37 @@ pub fn sys_read(fd: usize, buf: *const u8, len: usize) -> isize {
|
||||||
let file = file.clone();
|
let file = file.clone();
|
||||||
// release Task lock manually to avoid deadlock
|
// release Task lock manually to avoid deadlock
|
||||||
drop(inner);
|
drop(inner);
|
||||||
file.read(UserBuffer {
|
file.read(
|
||||||
buffers: translated_byte_buffer(token, buf, len),
|
UserBuffer::new(translated_byte_buffer(token, buf, len))
|
||||||
}) as isize
|
) as isize
|
||||||
} else {
|
} else {
|
||||||
-1
|
-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
|
||||||
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
|
const SYSCALL_CLOSE: usize = 57;
|
||||||
|
const SYSCALL_PIPE: usize = 59;
|
||||||
const SYSCALL_READ: usize = 63;
|
const SYSCALL_READ: usize = 63;
|
||||||
const SYSCALL_WRITE: usize = 64;
|
const SYSCALL_WRITE: usize = 64;
|
||||||
const SYSCALL_EXIT: usize = 93;
|
const SYSCALL_EXIT: usize = 93;
|
||||||
|
@ -16,6 +18,8 @@ use process::*;
|
||||||
|
|
||||||
pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize {
|
pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize {
|
||||||
match syscall_id {
|
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_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_WRITE => sys_write(args[0], args[1] as *const u8, args[2]),
|
||||||
SYSCALL_EXIT => sys_exit(args[0] as i32),
|
SYSCALL_EXIT => sys_exit(args[0] as i32),
|
||||||
|
|
|
@ -45,6 +45,15 @@ impl TaskControlBlockInner {
|
||||||
pub fn is_zombie(&self) -> bool {
|
pub fn is_zombie(&self) -> bool {
|
||||||
self.get_status() == TaskStatus::Zombie
|
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 {
|
impl TaskControlBlock {
|
||||||
|
@ -78,7 +87,11 @@ impl TaskControlBlock {
|
||||||
children: Vec::new(),
|
children: Vec::new(),
|
||||||
exit_code: 0,
|
exit_code: 0,
|
||||||
fd_table: vec![
|
fd_table: vec![
|
||||||
|
// 0 -> stdin
|
||||||
Some(Arc::new(Stdin)),
|
Some(Arc::new(Stdin)),
|
||||||
|
// 1 -> stdout
|
||||||
|
Some(Arc::new(Stdout)),
|
||||||
|
// 2 -> stderr
|
||||||
Some(Arc::new(Stdout)),
|
Some(Arc::new(Stdout)),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
@ -181,6 +194,7 @@ impl TaskControlBlock {
|
||||||
pub fn getpid(&self) -> usize {
|
pub fn getpid(&self) -> usize {
|
||||||
self.pid.0
|
self.pid.0
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
|
|
|
@ -108,6 +108,7 @@ pub fn trap_return() -> ! {
|
||||||
}
|
}
|
||||||
let restore_va = __restore as usize - __alltraps as usize + TRAMPOLINE;
|
let restore_va = __restore as usize - __alltraps as usize + TRAMPOLINE;
|
||||||
unsafe {
|
unsafe {
|
||||||
|
llvm_asm!("fence.i" :::: "volatile");
|
||||||
llvm_asm!("jr $0" :: "r"(restore_va), "{a0}"(trap_cx_ptr), "{a1}"(user_satp) :: "volatile");
|
llvm_asm!("jr $0" :: "r"(restore_va), "{a0}"(trap_cx_ptr), "{a1}"(user_satp) :: "volatile");
|
||||||
}
|
}
|
||||||
panic!("Unreachable in back_to_user!");
|
panic!("Unreachable in back_to_user!");
|
||||||
|
|
69
user/src/bin/pipe_large_test.rs
Normal file
69
user/src/bin/pipe_large_test.rs
Normal file
|
@ -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::<usize>();
|
||||||
|
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::<usize>();
|
||||||
|
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::<usize>(
|
||||||
|
core::str::from_utf8(&child_result[..result_len]).unwrap()
|
||||||
|
).unwrap()
|
||||||
|
);
|
||||||
|
let mut _unused: i32 = 0;
|
||||||
|
wait(&mut _unused);
|
||||||
|
println!("pipe_large_test passed!");
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
42
user/src/bin/pipetest.rs
Normal file
42
user/src/bin/pipetest.rs
Normal file
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
21
user/src/bin/run_pipe_test.rs
Normal file
21
user/src/bin/run_pipe_test.rs
Normal file
|
@ -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
|
||||||
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
|
use super::exit;
|
||||||
|
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
fn panic_handler(panic_info: &core::panic::PanicInfo) -> ! {
|
fn panic_handler(panic_info: &core::panic::PanicInfo) -> ! {
|
||||||
let err = panic_info.message().unwrap();
|
let err = panic_info.message().unwrap();
|
||||||
|
@ -6,5 +8,5 @@ fn panic_handler(panic_info: &core::panic::PanicInfo) -> ! {
|
||||||
} else {
|
} else {
|
||||||
println!("Panicked: {}", err);
|
println!("Panicked: {}", err);
|
||||||
}
|
}
|
||||||
loop {}
|
exit(-1);
|
||||||
}
|
}
|
|
@ -9,6 +9,8 @@ pub mod console;
|
||||||
mod syscall;
|
mod syscall;
|
||||||
mod lang_items;
|
mod lang_items;
|
||||||
|
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
use syscall::*;
|
use syscall::*;
|
||||||
use buddy_system_allocator::LockedHeap;
|
use buddy_system_allocator::LockedHeap;
|
||||||
|
|
||||||
|
@ -40,6 +42,8 @@ fn main() -> i32 {
|
||||||
panic!("Cannot find main!");
|
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 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 write(fd: usize, buf: &[u8]) -> isize { sys_write(fd, buf) }
|
||||||
pub fn exit(exit_code: i32) -> ! { sys_exit(exit_code); }
|
pub fn exit(exit_code: i32) -> ! { sys_exit(exit_code); }
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
const SYSCALL_CLOSE: usize = 57;
|
||||||
|
const SYSCALL_PIPE: usize = 59;
|
||||||
const SYSCALL_READ: usize = 63;
|
const SYSCALL_READ: usize = 63;
|
||||||
const SYSCALL_WRITE: usize = 64;
|
const SYSCALL_WRITE: usize = 64;
|
||||||
const SYSCALL_EXIT: usize = 93;
|
const SYSCALL_EXIT: usize = 93;
|
||||||
|
@ -21,6 +23,14 @@ fn syscall(id: usize, args: [usize; 3]) -> isize {
|
||||||
ret
|
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 {
|
pub fn sys_read(fd: usize, buffer: &mut [u8]) -> isize {
|
||||||
syscall(SYSCALL_READ, [fd, buffer.as_mut_ptr() as usize, buffer.len()])
|
syscall(SYSCALL_READ, [fd, buffer.as_mut_ptr() as usize, buffer.len()])
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue