diff --git a/.gitignore b/.gitignore index 63eceb88..b99cdbbd 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ os/target/* os/.idea/* os/src/link_app.S +os/src/linker.ld os/last-* os/Cargo.lock os/last-* @@ -13,4 +14,4 @@ easy-fs/target/* easy-fs-fuse/Cargo.lock easy-fs-fuse/target/* tools/ -pushall.sh \ No newline at end of file +pushall.sh diff --git a/README.md b/README.md index 91dc2266..7cc57d4b 100644 --- a/README.md +++ b/README.md @@ -239,7 +239,6 @@ Here are the updates since 3.5.0: * [ ] rewrite practice doc and remove some inproper questions * [ ] provide smooth debug experience at a Rust source code level * [ ] format the code using official tools -* [ ] support other platforms ### Crates diff --git a/easy-fs-fuse/src/main.rs b/easy-fs-fuse/src/main.rs index cf07b618..cac1b797 100644 --- a/easy-fs-fuse/src/main.rs +++ b/easy-fs-fuse/src/main.rs @@ -1,12 +1,9 @@ -use easy_fs::{ - BlockDevice, - EasyFileSystem, -}; -use std::fs::{File, OpenOptions, read_dir}; -use std::io::{Read, Write, Seek, SeekFrom}; -use std::sync::Mutex; +use clap::{App, Arg}; +use easy_fs::{BlockDevice, EasyFileSystem}; +use std::fs::{read_dir, File, OpenOptions}; +use std::io::{Read, Seek, SeekFrom, Write}; use std::sync::Arc; -use clap::{Arg, App}; +use std::sync::Mutex; const BLOCK_SZ: usize = 512; @@ -34,17 +31,19 @@ fn main() { fn easy_fs_pack() -> std::io::Result<()> { let matches = App::new("EasyFileSystem packer") - .arg(Arg::with_name("source") - .short("s") - .long("source") - .takes_value(true) - .help("Executable source dir(with backslash)") + .arg( + Arg::with_name("source") + .short("s") + .long("source") + .takes_value(true) + .help("Executable source dir(with backslash)"), ) - .arg(Arg::with_name("target") - .short("t") - .long("target") - .takes_value(true) - .help("Executable target dir(with backslash)") + .arg( + Arg::with_name("target") + .short("t") + .long("target") + .takes_value(true) + .help("Executable target dir(with backslash)"), ) .get_matches(); let src_path = matches.value_of("source").unwrap(); @@ -60,11 +59,7 @@ fn easy_fs_pack() -> std::io::Result<()> { f }))); // 16MiB, at most 4095 files - let efs = EasyFileSystem::create( - block_file.clone(), - 16 * 2048, - 1, - ); + let efs = EasyFileSystem::create(block_file, 16 * 2048, 1); let root_inode = Arc::new(EasyFileSystem::root_inode(&efs)); let apps: Vec<_> = read_dir(src_path) .unwrap() @@ -103,11 +98,7 @@ fn efs_test() -> std::io::Result<()> { f.set_len(8192 * 512).unwrap(); f }))); - EasyFileSystem::create( - block_file.clone(), - 4096, - 1, - ); + EasyFileSystem::create(block_file.clone(), 4096, 1); let efs = EasyFileSystem::open(block_file.clone()); let root_inode = EasyFileSystem::root_inode(&efs); root_inode.create("filea"); @@ -121,17 +112,11 @@ fn efs_test() -> std::io::Result<()> { //let mut buffer = [0u8; 512]; let mut buffer = [0u8; 233]; let len = filea.read_at(0, &mut buffer); - assert_eq!( - greet_str, - core::str::from_utf8(&buffer[..len]).unwrap(), - ); + assert_eq!(greet_str, core::str::from_utf8(&buffer[..len]).unwrap(),); let mut random_str_test = |len: usize| { filea.clear(); - assert_eq!( - filea.read_at(0, &mut buffer), - 0, - ); + assert_eq!(filea.read_at(0, &mut buffer), 0,); let mut str = String::new(); use rand; // random digit @@ -148,9 +133,7 @@ fn efs_test() -> std::io::Result<()> { break; } offset += len; - read_str.push_str( - core::str::from_utf8(&read_buffer[..len]).unwrap() - ); + read_str.push_str(core::str::from_utf8(&read_buffer[..len]).unwrap()); } assert_eq!(str, read_str); }; diff --git a/easy-fs/src/bitmap.rs b/easy-fs/src/bitmap.rs index 4feaa9cf..2cea613e 100644 --- a/easy-fs/src/bitmap.rs +++ b/easy-fs/src/bitmap.rs @@ -1,9 +1,5 @@ +use super::{get_block_cache, BlockDevice, BLOCK_SZ}; use alloc::sync::Arc; -use super::{ - BlockDevice, - BLOCK_SZ, - get_block_cache, -}; type BitmapBlock = [u64; 64]; @@ -17,7 +13,7 @@ pub struct Bitmap { /// Return (block_pos, bits64_pos, inner_pos) fn decomposition(mut bit: usize) -> (usize, usize, usize) { let block_pos = bit / BLOCK_BITS; - bit = bit % BLOCK_BITS; + bit %= BLOCK_BITS; (block_pos, bit / 64, bit % 64) } @@ -34,14 +30,15 @@ impl Bitmap { let pos = get_block_cache( block_id + self.start_block_id as usize, Arc::clone(block_device), - ).lock().modify(0, |bitmap_block: &mut BitmapBlock| { + ) + .lock() + .modify(0, |bitmap_block: &mut BitmapBlock| { if let Some((bits64_pos, inner_pos)) = bitmap_block .iter() .enumerate() .find(|(_, bits64)| **bits64 != u64::MAX) - .map(|(bits64_pos, bits64)| { - (bits64_pos, bits64.trailing_ones() as usize) - }) { + .map(|(bits64_pos, bits64)| (bits64_pos, bits64.trailing_ones() as usize)) + { // modify cache bitmap_block[bits64_pos] |= 1u64 << inner_pos; Some(block_id * BLOCK_BITS + bits64_pos * 64 + inner_pos as usize) @@ -58,16 +55,15 @@ impl Bitmap { pub fn dealloc(&self, block_device: &Arc, bit: usize) { let (block_pos, bits64_pos, inner_pos) = decomposition(bit); - get_block_cache( - block_pos + self.start_block_id, - Arc::clone(block_device) - ).lock().modify(0, |bitmap_block: &mut BitmapBlock| { - assert!(bitmap_block[bits64_pos] & (1u64 << inner_pos) > 0); - bitmap_block[bits64_pos] -= 1u64 << inner_pos; - }); + get_block_cache(block_pos + self.start_block_id, Arc::clone(block_device)) + .lock() + .modify(0, |bitmap_block: &mut BitmapBlock| { + assert!(bitmap_block[bits64_pos] & (1u64 << inner_pos) > 0); + bitmap_block[bits64_pos] -= 1u64 << inner_pos; + }); } pub fn maximum(&self) -> usize { self.blocks * BLOCK_BITS } -} \ No newline at end of file +} diff --git a/easy-fs/src/block_cache.rs b/easy-fs/src/block_cache.rs index ba945b1d..4b90294a 100644 --- a/easy-fs/src/block_cache.rs +++ b/easy-fs/src/block_cache.rs @@ -1,7 +1,4 @@ -use super::{ - BLOCK_SZ, - BlockDevice, -}; +use super::{BlockDevice, BLOCK_SZ}; use alloc::collections::VecDeque; use alloc::sync::Arc; use lazy_static::*; @@ -16,10 +13,7 @@ pub struct BlockCache { impl BlockCache { /// Load a new BlockCache from disk. - pub fn new( - block_id: usize, - block_device: Arc - ) -> Self { + pub fn new(block_id: usize, block_device: Arc) -> Self { let mut cache = [0u8; BLOCK_SZ]; block_device.read_block(block_id, &mut cache); Self { @@ -34,14 +28,20 @@ impl BlockCache { &self.cache[offset] as *const _ as usize } - pub fn get_ref(&self, offset: usize) -> &T where T: Sized { + pub fn get_ref(&self, offset: usize) -> &T + where + T: Sized, + { let type_size = core::mem::size_of::(); assert!(offset + type_size <= BLOCK_SZ); let addr = self.addr_of_offset(offset); - unsafe { &*(addr as *const T) } + unsafe { &*(addr as *const T) } } - pub fn get_mut(&mut self, offset: usize) -> &mut T where T: Sized { + pub fn get_mut(&mut self, offset: usize) -> &mut T + where + T: Sized, + { let type_size = core::mem::size_of::(); assert!(offset + type_size <= BLOCK_SZ); self.modified = true; @@ -53,7 +53,7 @@ impl BlockCache { f(self.get_ref(offset)) } - pub fn modify(&mut self, offset:usize, f: impl FnOnce(&mut T) -> V) -> V { + pub fn modify(&mut self, offset: usize, f: impl FnOnce(&mut T) -> V) -> V { f(self.get_mut(offset)) } @@ -79,7 +79,9 @@ pub struct BlockCacheManager { impl BlockCacheManager { pub fn new() -> Self { - Self { queue: VecDeque::new() } + Self { + queue: VecDeque::new(), + } } pub fn get_block_cache( @@ -87,27 +89,28 @@ impl BlockCacheManager { block_id: usize, block_device: Arc, ) -> Arc> { - if let Some(pair) = self.queue - .iter() - .find(|pair| pair.0 == block_id) { - Arc::clone(&pair.1) + if let Some(pair) = self.queue.iter().find(|pair| pair.0 == block_id) { + Arc::clone(&pair.1) } else { // substitute if self.queue.len() == BLOCK_CACHE_SIZE { // from front to tail - if let Some((idx, _)) = self.queue + if let Some((idx, _)) = self + .queue .iter() .enumerate() - .find(|(_, pair)| Arc::strong_count(&pair.1) == 1) { + .find(|(_, pair)| Arc::strong_count(&pair.1) == 1) + { self.queue.drain(idx..=idx); } else { panic!("Run out of BlockCache!"); } } // load block into mem and push back - let block_cache = Arc::new(Mutex::new( - BlockCache::new(block_id, Arc::clone(&block_device)) - )); + let block_cache = Arc::new(Mutex::new(BlockCache::new( + block_id, + Arc::clone(&block_device), + ))); self.queue.push_back((block_id, Arc::clone(&block_cache))); block_cache } @@ -115,16 +118,17 @@ impl BlockCacheManager { } lazy_static! { - pub static ref BLOCK_CACHE_MANAGER: Mutex = Mutex::new( - BlockCacheManager::new() - ); + pub static ref BLOCK_CACHE_MANAGER: Mutex = + Mutex::new(BlockCacheManager::new()); } pub fn get_block_cache( block_id: usize, - block_device: Arc + block_device: Arc, ) -> Arc> { - BLOCK_CACHE_MANAGER.lock().get_block_cache(block_id, block_device) + BLOCK_CACHE_MANAGER + .lock() + .get_block_cache(block_id, block_device) } pub fn block_cache_sync_all() { diff --git a/easy-fs/src/block_dev.rs b/easy-fs/src/block_dev.rs index 7a282751..8a01eddb 100644 --- a/easy-fs/src/block_dev.rs +++ b/easy-fs/src/block_dev.rs @@ -1,6 +1,6 @@ use core::any::Any; -pub trait BlockDevice : Send + Sync + Any { +pub trait BlockDevice: Send + Sync + Any { fn read_block(&self, block_id: usize, buf: &mut [u8]); fn write_block(&self, block_id: usize, buf: &[u8]); } diff --git a/easy-fs/src/efs.rs b/easy-fs/src/efs.rs index 8b7adf26..82e95ae0 100644 --- a/easy-fs/src/efs.rs +++ b/easy-fs/src/efs.rs @@ -1,16 +1,10 @@ -use alloc::sync::Arc; -use spin::Mutex; use super::{ - BlockDevice, - Bitmap, + block_cache_sync_all, get_block_cache, Bitmap, BlockDevice, DiskInode, DiskInodeType, Inode, SuperBlock, - DiskInode, - DiskInodeType, - Inode, - get_block_cache, - block_cache_sync_all, }; use crate::BLOCK_SZ; +use alloc::sync::Arc; +use spin::Mutex; pub struct EasyFileSystem { pub block_device: Arc, @@ -50,39 +44,36 @@ impl EasyFileSystem { }; // clear all blocks for i in 0..total_blocks { - get_block_cache( - i as usize, - Arc::clone(&block_device) - ) - .lock() - .modify(0, |data_block: &mut DataBlock| { - for byte in data_block.iter_mut() { *byte = 0; } - }); + get_block_cache(i as usize, Arc::clone(&block_device)) + .lock() + .modify(0, |data_block: &mut DataBlock| { + for byte in data_block.iter_mut() { + *byte = 0; + } + }); } // initialize SuperBlock - get_block_cache(0, Arc::clone(&block_device)) - .lock() - .modify(0, |super_block: &mut SuperBlock| { - super_block.initialize( - total_blocks, - inode_bitmap_blocks, - inode_area_blocks, - data_bitmap_blocks, - data_area_blocks, - ); - }); + get_block_cache(0, Arc::clone(&block_device)).lock().modify( + 0, + |super_block: &mut SuperBlock| { + super_block.initialize( + total_blocks, + inode_bitmap_blocks, + inode_area_blocks, + data_bitmap_blocks, + data_area_blocks, + ); + }, + ); // write back immediately // create a inode for root node "/" assert_eq!(efs.alloc_inode(), 0); let (root_inode_block_id, root_inode_offset) = efs.get_disk_inode_pos(0); - get_block_cache( - root_inode_block_id as usize, - Arc::clone(&block_device) - ) - .lock() - .modify(root_inode_offset, |disk_inode: &mut DiskInode| { - disk_inode.initialize(DiskInodeType::Directory); - }); + get_block_cache(root_inode_block_id as usize, Arc::clone(&block_device)) + .lock() + .modify(root_inode_offset, |disk_inode: &mut DiskInode| { + disk_inode.initialize(DiskInodeType::Directory); + }); block_cache_sync_all(); Arc::new(Mutex::new(efs)) } @@ -97,10 +88,7 @@ impl EasyFileSystem { super_block.inode_bitmap_blocks + super_block.inode_area_blocks; let efs = Self { block_device, - inode_bitmap: Bitmap::new( - 1, - super_block.inode_bitmap_blocks as usize - ), + inode_bitmap: Bitmap::new(1, super_block.inode_bitmap_blocks as usize), data_bitmap: Bitmap::new( (1 + inode_total_blocks) as usize, super_block.data_bitmap_blocks as usize, @@ -117,19 +105,17 @@ impl EasyFileSystem { // acquire efs lock temporarily let (block_id, block_offset) = efs.lock().get_disk_inode_pos(0); // release efs lock - Inode::new( - block_id, - block_offset, - Arc::clone(efs), - block_device, - ) + Inode::new(block_id, block_offset, Arc::clone(efs), block_device) } pub fn get_disk_inode_pos(&self, inode_id: u32) -> (u32, usize) { let inode_size = core::mem::size_of::(); let inodes_per_block = (BLOCK_SZ / inode_size) as u32; let block_id = self.inode_area_start_block + inode_id / inodes_per_block; - (block_id, (inode_id % inodes_per_block) as usize * inode_size) + ( + block_id, + (inode_id % inodes_per_block) as usize * inode_size, + ) } pub fn get_data_block_id(&self, data_block_id: u32) -> u32 { @@ -146,18 +132,16 @@ impl EasyFileSystem { } pub fn dealloc_data(&mut self, block_id: u32) { - get_block_cache( - block_id as usize, - Arc::clone(&self.block_device) - ) - .lock() - .modify(0, |data_block: &mut DataBlock| { - data_block.iter_mut().for_each(|p| { *p = 0; }) - }); + get_block_cache(block_id as usize, Arc::clone(&self.block_device)) + .lock() + .modify(0, |data_block: &mut DataBlock| { + data_block.iter_mut().for_each(|p| { + *p = 0; + }) + }); self.data_bitmap.dealloc( &self.block_device, - (block_id - self.data_area_start_block) as usize + (block_id - self.data_area_start_block) as usize, ) } - -} \ No newline at end of file +} diff --git a/easy-fs/src/layout.rs b/easy-fs/src/layout.rs index 357c2d17..618484cf 100644 --- a/easy-fs/src/layout.rs +++ b/easy-fs/src/layout.rs @@ -1,11 +1,7 @@ -use core::fmt::{Debug, Formatter, Result}; -use super::{ - BLOCK_SZ, - BlockDevice, - get_block_cache, -}; +use super::{get_block_cache, BlockDevice, BLOCK_SZ}; use alloc::sync::Arc; use alloc::vec::Vec; +use core::fmt::{Debug, Formatter, Result}; const EFS_MAGIC: u32 = 0x3b800001; const INODE_DIRECT_COUNT: usize = 28; @@ -115,7 +111,8 @@ impl DiskInode { if data_blocks > INDIRECT1_BOUND { total += 1; // sub indirect1 - total += (data_blocks - INDIRECT1_BOUND + INODE_INDIRECT1_COUNT - 1) / INODE_INDIRECT1_COUNT; + total += + (data_blocks - INDIRECT1_BOUND + INODE_INDIRECT1_COUNT - 1) / INODE_INDIRECT1_COUNT; } total as u32 } @@ -135,22 +132,16 @@ impl DiskInode { }) } else { let last = inner_id - INDIRECT1_BOUND; - let indirect1 = get_block_cache( - self.indirect2 as usize, - Arc::clone(block_device) - ) - .lock() - .read(0, |indirect2: &IndirectBlock| { - indirect2[last / INODE_INDIRECT1_COUNT] - }); - get_block_cache( - indirect1 as usize, - Arc::clone(block_device) - ) - .lock() - .read(0, |indirect1: &IndirectBlock| { - indirect1[last % INODE_INDIRECT1_COUNT] - }) + let indirect1 = get_block_cache(self.indirect2 as usize, Arc::clone(block_device)) + .lock() + .read(0, |indirect2: &IndirectBlock| { + indirect2[last / INODE_INDIRECT1_COUNT] + }); + get_block_cache(indirect1 as usize, Arc::clone(block_device)) + .lock() + .read(0, |indirect1: &IndirectBlock| { + indirect1[last % INODE_INDIRECT1_COUNT] + }) } } pub fn increase_size( @@ -169,7 +160,7 @@ impl DiskInode { current_blocks += 1; } // alloc indirect1 - if total_blocks > INODE_DIRECT_COUNT as u32{ + if total_blocks > INODE_DIRECT_COUNT as u32 { if current_blocks == INODE_DIRECT_COUNT as u32 { self.indirect1 = new_blocks.next().unwrap(); } @@ -179,60 +170,14 @@ impl DiskInode { return; } // fill indirect1 - get_block_cache( - self.indirect1 as usize, - Arc::clone(block_device) - ) - .lock() - .modify(0, |indirect1: &mut IndirectBlock| { - while current_blocks < total_blocks.min(INODE_INDIRECT1_COUNT as u32) { - indirect1[current_blocks as usize] = new_blocks.next().unwrap(); - current_blocks += 1; - } - }); - // alloc indirect2 - if total_blocks > INODE_INDIRECT1_COUNT as u32 { - if current_blocks == INODE_INDIRECT1_COUNT as u32 { - self.indirect2 = new_blocks.next().unwrap(); - } - current_blocks -= INODE_INDIRECT1_COUNT as u32; - total_blocks -= INODE_INDIRECT1_COUNT as u32; - } else { - return; - } - // fill indirect2 from (a0, b0) -> (a1, b1) - let mut a0 = current_blocks as usize / INODE_INDIRECT1_COUNT; - let mut b0 = current_blocks as usize % INODE_INDIRECT1_COUNT; - let a1 = total_blocks as usize / INODE_INDIRECT1_COUNT; - let b1 = total_blocks as usize % INODE_INDIRECT1_COUNT; - // alloc low-level indirect1 - get_block_cache( - self.indirect2 as usize, - Arc::clone(block_device) - ) - .lock() - .modify(0, |indirect2: &mut IndirectBlock| { - while (a0 < a1) || (a0 == a1 && b0 < b1) { - if b0 == 0 { - indirect2[a0] = new_blocks.next().unwrap(); - } - // fill current - get_block_cache( - indirect2[a0] as usize, - Arc::clone(block_device) - ) - .lock() - .modify(0, |indirect1: &mut IndirectBlock| { - indirect1[b0] = new_blocks.next().unwrap(); - }); - // move to next - b0 += 1; - if b0 == INODE_INDIRECT1_COUNT { - b0 = 0; - a0 += 1; + get_block_cache(self.indirect1 as usize, Arc::clone(block_device)) + .lock() + .modify(0, |indirect1: &mut IndirectBlock| { + while current_blocks < total_blocks.min(INODE_INDIRECT1_COUNT as u32) { + indirect1[current_blocks as usize] = new_blocks.next().unwrap(); + current_blocks += 1; } - } - }); + }); // alloc indirect2 if total_blocks > INODE_INDIRECT1_COUNT as u32 { if current_blocks == INODE_INDIRECT1_COUNT as u32 { @@ -249,33 +194,27 @@ impl DiskInode { let a1 = total_blocks as usize / INODE_INDIRECT1_COUNT; let b1 = total_blocks as usize % INODE_INDIRECT1_COUNT; // alloc low-level indirect1 - get_block_cache( - self.indirect2 as usize, - Arc::clone(block_device) - ) - .lock() - .modify(0, |indirect2: &mut IndirectBlock| { - while (a0 < a1) || (a0 == a1 && b0 < b1) { - if b0 == 0 { - indirect2[a0] = new_blocks.next().unwrap(); - } - // fill current - get_block_cache( - indirect2[a0] as usize, - Arc::clone(block_device) - ) - .lock() - .modify(0, |indirect1: &mut IndirectBlock| { - indirect1[b0] = new_blocks.next().unwrap(); - }); - // move to next - b0 += 1; - if b0 == INODE_INDIRECT1_COUNT { - b0 = 0; - a0 += 1; + get_block_cache(self.indirect2 as usize, Arc::clone(block_device)) + .lock() + .modify(0, |indirect2: &mut IndirectBlock| { + while (a0 < a1) || (a0 == a1 && b0 < b1) { + if b0 == 0 { + indirect2[a0] = new_blocks.next().unwrap(); + } + // fill current + get_block_cache(indirect2[a0] as usize, Arc::clone(block_device)) + .lock() + .modify(0, |indirect1: &mut IndirectBlock| { + indirect1[b0] = new_blocks.next().unwrap(); + }); + // move to next + b0 += 1; + if b0 == INODE_INDIRECT1_COUNT { + b0 = 0; + a0 += 1; + } } - } - }); + }); } /// Clear size to zero and return blocks that should be deallocated. @@ -301,18 +240,15 @@ impl DiskInode { return v; } // indirect1 - get_block_cache( - self.indirect1 as usize, - Arc::clone(block_device), - ) - .lock() - .modify(0, |indirect1: &mut IndirectBlock| { - while current_blocks < data_blocks.min(INODE_INDIRECT1_COUNT) { - v.push(indirect1[current_blocks]); - //indirect1[current_blocks] = 0; - current_blocks += 1; - } - }); + get_block_cache(self.indirect1 as usize, Arc::clone(block_device)) + .lock() + .modify(0, |indirect1: &mut IndirectBlock| { + while current_blocks < data_blocks.min(INODE_INDIRECT1_COUNT) { + v.push(indirect1[current_blocks]); + //indirect1[current_blocks] = 0; + current_blocks += 1; + } + }); self.indirect1 = 0; // indirect2 block if data_blocks > INODE_INDIRECT1_COUNT { @@ -325,45 +261,33 @@ impl DiskInode { assert!(data_blocks <= INODE_INDIRECT2_COUNT); let a1 = data_blocks / INODE_INDIRECT1_COUNT; let b1 = data_blocks % INODE_INDIRECT1_COUNT; - get_block_cache( - self.indirect2 as usize, - Arc::clone(block_device), - ) - .lock() - .modify(0, |indirect2: &mut IndirectBlock| { - // full indirect1 blocks - for i in 0..a1 { - v.push(indirect2[i]); - get_block_cache( - indirect2[i] as usize, - Arc::clone(block_device), - ) - .lock() - .modify(0, |indirect1: &mut IndirectBlock| { - for j in 0..INODE_INDIRECT1_COUNT { - v.push(indirect1[j]); - //indirect1[j] = 0; - } - }); - //indirect2[i] = 0; - } - // last indirect1 block - if b1 > 0 { - v.push(indirect2[a1]); - get_block_cache( - indirect2[a1] as usize, - Arc::clone(block_device), - ) - .lock() - .modify(0, |indirect1: &mut IndirectBlock| { - for j in 0..b1 { - v.push(indirect1[j]); - //indirect1[j] = 0; - } - }); - //indirect2[a1] = 0; - } - }); + get_block_cache(self.indirect2 as usize, Arc::clone(block_device)) + .lock() + .modify(0, |indirect2: &mut IndirectBlock| { + // full indirect1 blocks + for entry in indirect2.iter_mut().take(a1) { + v.push(*entry); + get_block_cache(*entry as usize, Arc::clone(block_device)) + .lock() + .modify(0, |indirect1: &mut IndirectBlock| { + for entry in indirect1.iter() { + v.push(*entry); + } + }); + } + // last indirect1 block + if b1 > 0 { + v.push(indirect2[a1]); + get_block_cache(indirect2[a1] as usize, Arc::clone(block_device)) + .lock() + .modify(0, |indirect1: &mut IndirectBlock| { + for entry in indirect1.iter().take(b1) { + v.push(*entry); + } + }); + //indirect2[a1] = 0; + } + }); self.indirect2 = 0; v } @@ -398,7 +322,9 @@ impl DiskInode { }); read_size += block_read_size; // move to next block - if end_current_block == end { break; } + if end_current_block == end { + break; + } start_block += 1; start = end_current_block; } @@ -424,7 +350,7 @@ impl DiskInode { let block_write_size = end_current_block - start; get_block_cache( self.get_block_id(start_block as u32, block_device) as usize, - Arc::clone(block_device) + Arc::clone(block_device), ) .lock() .modify(0, |data_block: &mut DataBlock| { @@ -434,7 +360,9 @@ impl DiskInode { }); write_size += block_write_size; // move to next block - if end_current_block == end { break; } + if end_current_block == end { + break; + } start_block += 1; start = end_current_block; } @@ -466,20 +394,10 @@ impl DirEntry { } } pub fn as_bytes(&self) -> &[u8] { - unsafe { - core::slice::from_raw_parts( - self as *const _ as usize as *const u8, - DIRENT_SZ, - ) - } + unsafe { core::slice::from_raw_parts(self as *const _ as usize as *const u8, DIRENT_SZ) } } pub fn as_bytes_mut(&mut self) -> &mut [u8] { - unsafe { - core::slice::from_raw_parts_mut( - self as *mut _ as usize as *mut u8, - DIRENT_SZ, - ) - } + unsafe { core::slice::from_raw_parts_mut(self as *mut _ as usize as *mut u8, DIRENT_SZ) } } pub fn name(&self) -> &str { let len = (0usize..).find(|i| self.name[*i] == 0).unwrap(); @@ -488,4 +406,4 @@ impl DirEntry { pub fn inode_number(&self) -> u32 { self.inode_number } -} \ No newline at end of file +} diff --git a/easy-fs/src/lib.rs b/easy-fs/src/lib.rs index afb957ac..fa36e6b7 100644 --- a/easy-fs/src/lib.rs +++ b/easy-fs/src/lib.rs @@ -2,17 +2,17 @@ extern crate alloc; +mod bitmap; +mod block_cache; mod block_dev; -mod layout; mod efs; -mod bitmap; +mod layout; mod vfs; -mod block_cache; pub const BLOCK_SZ: usize = 512; +use bitmap::Bitmap; +use block_cache::{block_cache_sync_all, get_block_cache}; pub use block_dev::BlockDevice; pub use efs::EasyFileSystem; -pub use vfs::Inode; use layout::*; -use bitmap::Bitmap; -use block_cache::{get_block_cache, block_cache_sync_all}; \ No newline at end of file +pub use vfs::Inode; diff --git a/easy-fs/src/vfs.rs b/easy-fs/src/vfs.rs index 9534c39a..7290fa47 100644 --- a/easy-fs/src/vfs.rs +++ b/easy-fs/src/vfs.rs @@ -1,15 +1,9 @@ use super::{ - BlockDevice, - DiskInode, - DiskInodeType, - DirEntry, - EasyFileSystem, - DIRENT_SZ, - get_block_cache, - block_cache_sync_all, + block_cache_sync_all, get_block_cache, BlockDevice, DirEntry, DiskInode, DiskInodeType, + EasyFileSystem, DIRENT_SZ, }; -use alloc::sync::Arc; use alloc::string::String; +use alloc::sync::Arc; use alloc::vec::Vec; use spin::{Mutex, MutexGuard}; @@ -37,35 +31,25 @@ impl Inode { } fn read_disk_inode(&self, f: impl FnOnce(&DiskInode) -> V) -> V { - get_block_cache( - self.block_id, - Arc::clone(&self.block_device) - ).lock().read(self.block_offset, f) + get_block_cache(self.block_id, Arc::clone(&self.block_device)) + .lock() + .read(self.block_offset, f) } fn modify_disk_inode(&self, f: impl FnOnce(&mut DiskInode) -> V) -> V { - get_block_cache( - self.block_id, - Arc::clone(&self.block_device) - ).lock().modify(self.block_offset, f) + get_block_cache(self.block_id, Arc::clone(&self.block_device)) + .lock() + .modify(self.block_offset, f) } - fn find_inode_id( - &self, - name: &str, - disk_inode: &DiskInode, - ) -> Option { + fn find_inode_id(&self, name: &str, disk_inode: &DiskInode) -> Option { // assert it is a directory assert!(disk_inode.is_dir()); let file_count = (disk_inode.size as usize) / DIRENT_SZ; let mut dirent = DirEntry::empty(); for i in 0..file_count { assert_eq!( - disk_inode.read_at( - DIRENT_SZ * i, - dirent.as_bytes_mut(), - &self.block_device, - ), + disk_inode.read_at(DIRENT_SZ * i, dirent.as_bytes_mut(), &self.block_device,), DIRENT_SZ, ); if dirent.name() == name { @@ -78,8 +62,7 @@ impl Inode { pub fn find(&self, name: &str) -> Option> { let fs = self.fs.lock(); self.read_disk_inode(|disk_inode| { - self.find_inode_id(name, disk_inode) - .map(|inode_id| { + self.find_inode_id(name, disk_inode).map(|inode_id| { let (block_id, block_offset) = fs.get_disk_inode_pos(inode_id); Arc::new(Self::new( block_id, @@ -110,26 +93,25 @@ impl Inode { pub fn create(&self, name: &str) -> Option> { let mut fs = self.fs.lock(); - if self.modify_disk_inode(|root_inode| { + let op = |root_inode: &mut DiskInode| { // assert it is a directory assert!(root_inode.is_dir()); // has the file been created? self.find_inode_id(name, root_inode) - }).is_some() { + }; + if self.modify_disk_inode(op).is_some() { return None; } // create a new file // alloc a inode with an indirect block let new_inode_id = fs.alloc_inode(); // initialize inode - let (new_inode_block_id, new_inode_block_offset) - = fs.get_disk_inode_pos(new_inode_id); - get_block_cache( - new_inode_block_id as usize, - Arc::clone(&self.block_device) - ).lock().modify(new_inode_block_offset, |new_inode: &mut DiskInode| { - new_inode.initialize(DiskInodeType::File); - }); + let (new_inode_block_id, new_inode_block_offset) = fs.get_disk_inode_pos(new_inode_id); + get_block_cache(new_inode_block_id as usize, Arc::clone(&self.block_device)) + .lock() + .modify(new_inode_block_offset, |new_inode: &mut DiskInode| { + new_inode.initialize(DiskInodeType::File); + }); self.modify_disk_inode(|root_inode| { // append file in the dirent let file_count = (root_inode.size as usize) / DIRENT_SZ; @@ -165,11 +147,7 @@ impl Inode { for i in 0..file_count { let mut dirent = DirEntry::empty(); assert_eq!( - disk_inode.read_at( - i * DIRENT_SZ, - dirent.as_bytes_mut(), - &self.block_device, - ), + disk_inode.read_at(i * DIRENT_SZ, dirent.as_bytes_mut(), &self.block_device,), DIRENT_SZ, ); v.push(String::from(dirent.name())); @@ -180,9 +158,7 @@ impl Inode { pub fn read_at(&self, offset: usize, buf: &mut [u8]) -> usize { let _fs = self.fs.lock(); - self.read_disk_inode(|disk_inode| { - disk_inode.read_at(offset, buf, &self.block_device) - }) + self.read_disk_inode(|disk_inode| disk_inode.read_at(offset, buf, &self.block_device)) } pub fn write_at(&self, offset: usize, buf: &[u8]) -> usize { diff --git a/os/Makefile b/os/Makefile index e3434de3..0c1fb7c7 100644 --- a/os/Makefile +++ b/os/Makefile @@ -36,9 +36,9 @@ build: env switch-check $(KERNEL_BIN) fs-img switch-check: ifeq ($(BOARD), qemu) - (which last-qemu) || (rm last-k210 -f && touch last-qemu && make clean) + (which last-qemu) || (rm -f last-k210 && touch last-qemu && make clean) else ifeq ($(BOARD), k210) - (which last-k210) || (rm last-qemu -f && touch last-k210 && make clean) + (which last-k210) || (rm -f last-qemu && touch last-k210 && make clean) endif env: @@ -57,7 +57,7 @@ $(KERNEL_BIN): kernel fs-img: $(APPS) @cd ../user && make build - @rm $(FS_IMG) -f + @rm -f $(FS_IMG) @cd ../easy-fs-fuse && cargo run --release -- -s ../user/src/bin/ -t ../user/target/riscv64gc-unknown-none-elf/release/ $(APPS): diff --git a/os/src/boards/k210.rs b/os/src/boards/k210.rs new file mode 100644 index 00000000..4b2fd444 --- /dev/null +++ b/os/src/boards/k210.rs @@ -0,0 +1,23 @@ +pub const CLOCK_FREQ: usize = 403000000 / 62; + +pub const MMIO: &[(usize, usize)] = &[ + // we don't need clint in S priv when running + // we only need claim/complete for target0 after initializing + (0x0C00_0000, 0x3000), /* PLIC */ + (0x0C20_0000, 0x1000), /* PLIC */ + (0x3800_0000, 0x1000), /* UARTHS */ + (0x3800_1000, 0x1000), /* GPIOHS */ + (0x5020_0000, 0x1000), /* GPIO */ + (0x5024_0000, 0x1000), /* SPI_SLAVE */ + (0x502B_0000, 0x1000), /* FPIOA */ + (0x502D_0000, 0x1000), /* TIMER0 */ + (0x502E_0000, 0x1000), /* TIMER1 */ + (0x502F_0000, 0x1000), /* TIMER2 */ + (0x5044_0000, 0x1000), /* SYSCTL */ + (0x5200_0000, 0x1000), /* SPI0 */ + (0x5300_0000, 0x1000), /* SPI1 */ + (0x5400_0000, 0x1000), /* SPI2 */ +]; + +pub type BlockDeviceImpl = crate::drivers::block::SDCardWrapper; + diff --git a/os/src/boards/qemu.rs b/os/src/boards/qemu.rs new file mode 100644 index 00000000..b3492526 --- /dev/null +++ b/os/src/boards/qemu.rs @@ -0,0 +1,6 @@ +pub const CLOCK_FREQ: usize = 12500000; + +pub const MMIO: &[(usize, usize)] = &[(0x10001000, 0x1000)]; + +pub type BlockDeviceImpl = crate::drivers::block::VirtIOBlock; + diff --git a/os/src/config.rs b/os/src/config.rs index 44ecc0e2..c1b2fa45 100644 --- a/os/src/config.rs +++ b/os/src/config.rs @@ -10,33 +10,5 @@ pub const PAGE_SIZE_BITS: usize = 0xc; pub const TRAMPOLINE: usize = usize::MAX - PAGE_SIZE + 1; pub const TRAP_CONTEXT_BASE: usize = TRAMPOLINE - PAGE_SIZE; -#[cfg(feature = "board_k210")] -pub const CLOCK_FREQ: usize = 403000000 / 62; +pub use crate::board::{CLOCK_FREQ, MMIO}; -#[cfg(feature = "board_qemu")] -pub const CLOCK_FREQ: usize = 12500000; - -#[cfg(feature = "board_qemu")] -pub const MMIO: &[(usize, usize)] = &[ - (0x10001000, 0x1000), -]; - -#[cfg(feature = "board_k210")] -pub const MMIO: &[(usize, usize)] = &[ - // we don't need clint in S priv when running - // we only need claim/complete for target0 after initializing - (0x0C00_0000, 0x3000), /* PLIC */ - (0x0C20_0000, 0x1000), /* PLIC */ - (0x3800_0000, 0x1000), /* UARTHS */ - (0x3800_1000, 0x1000), /* GPIOHS */ - (0x5020_0000, 0x1000), /* GPIO */ - (0x5024_0000, 0x1000), /* SPI_SLAVE */ - (0x502B_0000, 0x1000), /* FPIOA */ - (0x502D_0000, 0x1000), /* TIMER0 */ - (0x502E_0000, 0x1000), /* TIMER1 */ - (0x502F_0000, 0x1000), /* TIMER2 */ - (0x5044_0000, 0x1000), /* SYSCTL */ - (0x5200_0000, 0x1000), /* SPI0 */ - (0x5300_0000, 0x1000), /* SPI1 */ - (0x5400_0000, 0x1000), /* SPI2 */ -]; diff --git a/os/src/console.rs b/os/src/console.rs index 91988883..c8a5cd4e 100644 --- a/os/src/console.rs +++ b/os/src/console.rs @@ -1,5 +1,5 @@ -use core::fmt::{self, Write}; use crate::sbi::console_putchar; +use core::fmt::{self, Write}; struct Stdout; @@ -29,5 +29,3 @@ macro_rules! println { $crate::console::print(format_args!(concat!($fmt, "\n") $(, $($arg)+)?)) } } - - diff --git a/os/src/drivers/block/mod.rs b/os/src/drivers/block/mod.rs index f79b8b81..7c1bb55d 100644 --- a/os/src/drivers/block/mod.rs +++ b/os/src/drivers/block/mod.rs @@ -1,15 +1,13 @@ -mod virtio_blk; mod sdcard; +mod virtio_blk; + +pub use virtio_blk::VirtIOBlock; +pub use sdcard::SDCardWrapper; -use lazy_static::*; use alloc::sync::Arc; use easy_fs::BlockDevice; - -#[cfg(feature = "board_qemu")] -type BlockDeviceImpl = virtio_blk::VirtIOBlock; - -#[cfg(feature = "board_k210")] -type BlockDeviceImpl = sdcard::SDCardWrapper; +use lazy_static::*; +use crate::board::BlockDeviceImpl; lazy_static! { pub static ref BLOCK_DEVICE: Arc = Arc::new(BlockDeviceImpl::new()); @@ -21,10 +19,12 @@ pub fn block_device_test() { let mut write_buffer = [0u8; 512]; let mut read_buffer = [0u8; 512]; for i in 0..512 { - for byte in write_buffer.iter_mut() { *byte = i as u8; } + for byte in write_buffer.iter_mut() { + *byte = i as u8; + } block_device.write_block(i as usize, &write_buffer); block_device.read_block(i as usize, &mut read_buffer); assert_eq!(write_buffer, read_buffer); } println!("block device test passed!"); -} \ No newline at end of file +} diff --git a/os/src/drivers/block/sdcard.rs b/os/src/drivers/block/sdcard.rs index bb15cabf..1e9f1cc9 100644 --- a/os/src/drivers/block/sdcard.rs +++ b/os/src/drivers/block/sdcard.rs @@ -2,21 +2,21 @@ #![allow(non_camel_case_types)] #![allow(unused)] -use k210_pac::{Peripherals, SPI0}; +use super::BlockDevice; +use crate::sync::UPSafeCell; +use core::convert::TryInto; use k210_hal::prelude::*; +use k210_pac::{Peripherals, SPI0}; use k210_soc::{ + fpioa::{self, io}, //dmac::{dma_channel, DMAC, DMACExt}, gpio, gpiohs, - spi::{aitm, frame_format, tmod, work_mode, SPI, SPIExt, SPIImpl}, - fpioa::{self, io}, - sysctl, sleep::usleep, + spi::{aitm, frame_format, tmod, work_mode, SPIExt, SPIImpl, SPI}, + sysctl, }; -use crate::sync::UPSafeCell; use lazy_static::*; -use super::BlockDevice; -use core::convert::TryInto; pub struct SDCard { spi: SPI, @@ -160,7 +160,11 @@ pub struct SDCardInfo { } impl SDCard { - pub fn new(spi: X, spi_cs: u32, cs_gpionum: u8/*, dmac: &'a DMAC, channel: dma_channel*/) -> Self { + pub fn new( + spi: X, + spi_cs: u32, + cs_gpionum: u8, /*, dmac: &'a DMAC, channel: dma_channel*/ + ) -> Self { Self { spi, spi_cs, @@ -310,7 +314,7 @@ impl SDCard { timeout -= 1; } /* After time out */ - return 0xFF; + 0xFF } /* @@ -337,7 +341,7 @@ impl SDCard { self.read_data(response); } /* Return response */ - return 0; + 0 } /* @@ -367,7 +371,7 @@ impl SDCard { self.read_data(&mut csd_tab); self.end_cmd(); /* see also: https://cdn-shop.adafruit.com/datasheets/TS16GUSDHC6.pdf */ - return Ok(SDCardCSD { + Ok(SDCardCSD { /* Byte 0 */ CSDStruct: (csd_tab[0] & 0xC0) >> 6, SysSpecVersion: (csd_tab[0] & 0x3C) >> 2, @@ -419,8 +423,8 @@ impl SDCard { /* Byte 15 */ CSD_CRC: (csd_tab[15] & 0xFE) >> 1, Reserved4: 1, - /* Return the response */ - }); + /* Return the reponse */ + }) } /* @@ -449,7 +453,7 @@ impl SDCard { /* Get CRC bytes (not really needed by us, but required by SD) */ self.read_data(&mut cid_tab); self.end_cmd(); - return Ok(SDCardCID { + Ok(SDCardCID { /* Byte 0 */ ManufacturerID: cid_tab[0], /* Byte 1, 2 */ @@ -474,7 +478,7 @@ impl SDCard { /* Byte 15 */ CID_CRC: (cid_tab[15] & 0xFE) >> 1, Reserved2: 1, - }); + }) } /* @@ -606,7 +610,7 @@ impl SDCard { } let mut error = false; //let mut dma_chunk = [0u32; SEC_LEN]; - let mut tmp_chunk= [0u8; SEC_LEN]; + let mut tmp_chunk = [0u8; SEC_LEN]; for chunk in data_buf.chunks_mut(SEC_LEN) { if self.get_response() != SD_START_DATA_SINGLE_BLOCK_READ { error = true; @@ -616,7 +620,7 @@ impl SDCard { //self.read_data_dma(&mut dma_chunk); self.read_data(&mut tmp_chunk); /* Place the data received as u32 units from DMA into the u8 target buffer */ - for (a, b) in chunk.iter_mut().zip(/*dma_chunk*/tmp_chunk.iter()) { + for (a, b) in chunk.iter_mut().zip(/*dma_chunk*/ tmp_chunk.iter()) { //*a = (b & 0xff) as u8; *a = *b; } @@ -675,12 +679,12 @@ impl SDCard { /* Send the data token to signify the start of the data */ self.write_data(&frame); /* Write the block data to SD : write count data by block */ - for (a, &b) in /*dma_chunk*/tmp_chunk.iter_mut().zip(chunk.iter()) { + for (a, &b) in /*dma_chunk*/ tmp_chunk.iter_mut().zip(chunk.iter()) { //*a = b.into(); *a = b; } //self.write_data_dma(&mut dma_chunk); - self.write_data(&mut tmp_chunk); + self.write_data(&tmp_chunk); /* Put dummy CRC bytes */ self.write_data(&[0xff, 0xff]); /* Read data response */ @@ -711,9 +715,8 @@ fn io_init() { } lazy_static! { - static ref PERIPHERALS: UPSafeCell = unsafe { - UPSafeCell::new(Peripherals::take().unwrap()) - }; + static ref PERIPHERALS: UPSafeCell = + unsafe { UPSafeCell::new(Peripherals::take().unwrap()) }; } fn init_sdcard() -> SDCard> { @@ -747,9 +750,15 @@ impl SDCardWrapper { impl BlockDevice for SDCardWrapper { fn read_block(&self, block_id: usize, buf: &mut [u8]) { - self.0.exclusive_access().read_sector(buf,block_id as u32).unwrap(); + self.0 + .exclusive_access() + .read_sector(buf, block_id as u32) + .unwrap(); } fn write_block(&self, block_id: usize, buf: &[u8]) { - self.0.exclusive_access().write_sector(buf,block_id as u32).unwrap(); + self.0 + .exclusive_access() + .write_sector(buf, block_id as u32) + .unwrap(); } } diff --git a/os/src/drivers/block/virtio_blk.rs b/os/src/drivers/block/virtio_blk.rs index 6b386190..cca839da 100644 --- a/os/src/drivers/block/virtio_blk.rs +++ b/os/src/drivers/block/virtio_blk.rs @@ -1,20 +1,12 @@ - -use virtio_drivers::{VirtIOBlk, VirtIOHeader}; +use super::BlockDevice; use crate::mm::{ - PhysAddr, - VirtAddr, - frame_alloc, - frame_dealloc, - PhysPageNum, - FrameTracker, - StepByOne, - PageTable, - kernel_token, + frame_alloc, frame_dealloc, kernel_token, FrameTracker, PageTable, PhysAddr, PhysPageNum, + StepByOne, VirtAddr, }; -use super::BlockDevice; use crate::sync::UPSafeCell; use alloc::vec::Vec; use lazy_static::*; +use virtio_drivers::{VirtIOBlk, VirtIOHeader}; #[allow(unused)] const VIRTIO0: usize = 0x10001000; @@ -22,21 +14,21 @@ const VIRTIO0: usize = 0x10001000; pub struct VirtIOBlock(UPSafeCell>); lazy_static! { - static ref QUEUE_FRAMES: UPSafeCell> = unsafe { - UPSafeCell::new(Vec::new()) - }; + static ref QUEUE_FRAMES: UPSafeCell> = unsafe { UPSafeCell::new(Vec::new()) }; } impl BlockDevice for VirtIOBlock { fn read_block(&self, block_id: usize, buf: &mut [u8]) { - self.0.exclusive_access() - .read_block(block_id, buf) - .expect("Error when reading VirtIOBlk"); + self.0 + .exclusive_access() + .read_block(block_id, buf) + .expect("Error when reading VirtIOBlk"); } fn write_block(&self, block_id: usize, buf: &[u8]) { - self.0.exclusive_access() - .write_block(block_id, buf) - .expect("Error when writing VirtIOBlk"); + self.0 + .exclusive_access() + .write_block(block_id, buf) + .expect("Error when writing VirtIOBlk"); } } @@ -44,9 +36,9 @@ impl VirtIOBlock { #[allow(unused)] pub fn new() -> Self { unsafe { - Self(UPSafeCell::new(VirtIOBlk::new( - &mut *(VIRTIO0 as *mut VirtIOHeader) - ).unwrap())) + Self(UPSafeCell::new( + VirtIOBlk::new(&mut *(VIRTIO0 as *mut VirtIOHeader)).unwrap(), + )) } } } @@ -56,7 +48,9 @@ pub extern "C" fn virtio_dma_alloc(pages: usize) -> PhysAddr { let mut ppn_base = PhysPageNum(0); for i in 0..pages { let frame = frame_alloc().unwrap(); - if i == 0 { ppn_base = frame.ppn; } + if i == 0 { + ppn_base = frame.ppn; + } assert_eq!(frame.ppn.0, ppn_base.0 + i); QUEUE_FRAMES.exclusive_access().push(frame); } @@ -80,5 +74,7 @@ pub extern "C" fn virtio_phys_to_virt(paddr: PhysAddr) -> VirtAddr { #[no_mangle] pub extern "C" fn virtio_virt_to_phys(vaddr: VirtAddr) -> PhysAddr { - PageTable::from_token(kernel_token()).translate_va(vaddr).unwrap() + PageTable::from_token(kernel_token()) + .translate_va(vaddr) + .unwrap() } diff --git a/os/src/drivers/mod.rs b/os/src/drivers/mod.rs index 54c0a2cb..c2dea36b 100644 --- a/os/src/drivers/mod.rs +++ b/os/src/drivers/mod.rs @@ -1,3 +1,3 @@ -mod block; +pub mod block; -pub use block::BLOCK_DEVICE; \ No newline at end of file +pub use block::BLOCK_DEVICE; diff --git a/os/src/fs/inode.rs b/os/src/fs/inode.rs index f03225b6..19e4953d 100644 --- a/os/src/fs/inode.rs +++ b/os/src/fs/inode.rs @@ -1,15 +1,12 @@ -use easy_fs::{ - EasyFileSystem, - Inode, -}; +use super::File; use crate::drivers::BLOCK_DEVICE; +use crate::mm::UserBuffer; use crate::sync::UPSafeCell; use alloc::sync::Arc; -use lazy_static::*; -use bitflags::*; use alloc::vec::Vec; -use super::File; -use crate::mm::UserBuffer; +use bitflags::*; +use easy_fs::{EasyFileSystem, Inode}; +use lazy_static::*; pub struct OSInode { readable: bool, @@ -23,18 +20,11 @@ pub struct OSInodeInner { } impl OSInode { - pub fn new( - readable: bool, - writable: bool, - inode: Arc, - ) -> Self { + pub fn new(readable: bool, writable: bool, inode: Arc) -> Self { Self { readable, writable, - inner: unsafe { UPSafeCell::new(OSInodeInner { - offset: 0, - inode, - })}, + inner: unsafe { UPSafeCell::new(OSInodeInner { offset: 0, inode }) }, } } pub fn read_all(&self) -> Vec { @@ -98,40 +88,30 @@ pub fn open_file(name: &str, flags: OpenFlags) -> Option> { if let Some(inode) = ROOT_INODE.find(name) { // clear size inode.clear(); - Some(Arc::new(OSInode::new( - readable, - writable, - inode, - ))) + Some(Arc::new(OSInode::new(readable, writable, inode))) } else { // create file - ROOT_INODE.create(name) - .map(|inode| { - Arc::new(OSInode::new( - readable, - writable, - inode, - )) - }) + ROOT_INODE + .create(name) + .map(|inode| Arc::new(OSInode::new(readable, writable, inode))) } } else { - ROOT_INODE.find(name) - .map(|inode| { - if flags.contains(OpenFlags::TRUNC) { - inode.clear(); - } - Arc::new(OSInode::new( - readable, - writable, - inode - )) - }) + ROOT_INODE.find(name).map(|inode| { + if flags.contains(OpenFlags::TRUNC) { + inode.clear(); + } + Arc::new(OSInode::new(readable, writable, inode)) + }) } } impl File for OSInode { - fn readable(&self) -> bool { self.readable } - fn writable(&self) -> bool { self.writable } + fn readable(&self) -> bool { + self.readable + } + fn writable(&self) -> bool { + self.writable + } fn read(&self, mut buf: UserBuffer) -> usize { let mut inner = self.inner.exclusive_access(); let mut total_read_size = 0usize; @@ -156,4 +136,4 @@ impl File for OSInode { } total_write_size } -} \ No newline at end of file +} diff --git a/os/src/fs/mod.rs b/os/src/fs/mod.rs index c015702d..8ae0418c 100644 --- a/os/src/fs/mod.rs +++ b/os/src/fs/mod.rs @@ -1,16 +1,16 @@ +mod inode; mod pipe; mod stdio; -mod inode; use crate::mm::UserBuffer; -pub trait File : Send + Sync { +pub trait File: Send + Sync { fn readable(&self) -> bool; fn writable(&self) -> bool; fn read(&self, buf: UserBuffer) -> usize; fn write(&self, buf: UserBuffer) -> usize; } -pub use pipe::{Pipe, make_pipe}; +pub use inode::{list_apps, open_file, OSInode, OpenFlags}; +pub use pipe::{make_pipe, Pipe}; pub use stdio::{Stdin, Stdout}; -pub use inode::{OSInode, open_file, OpenFlags, list_apps}; \ No newline at end of file diff --git a/os/src/fs/pipe.rs b/os/src/fs/pipe.rs index ed2dde15..75caac54 100644 --- a/os/src/fs/pipe.rs +++ b/os/src/fs/pipe.rs @@ -1,7 +1,7 @@ use super::File; -use alloc::sync::{Arc, Weak}; -use crate::sync::UPSafeCell; use crate::mm::UserBuffer; +use crate::sync::UPSafeCell; +use alloc::sync::{Arc, Weak}; use crate::task::suspend_current_and_run_next; @@ -32,9 +32,9 @@ const RING_BUFFER_SIZE: usize = 32; #[derive(Copy, Clone, PartialEq)] enum RingBufferStatus { - FULL, - EMPTY, - NORMAL, + Full, + Empty, + Normal, } pub struct PipeRingBuffer { @@ -51,7 +51,7 @@ impl PipeRingBuffer { arr: [0; RING_BUFFER_SIZE], head: 0, tail: 0, - status: RingBufferStatus::EMPTY, + status: RingBufferStatus::Empty, write_end: None, } } @@ -59,35 +59,33 @@ impl PipeRingBuffer { self.write_end = Some(Arc::downgrade(write_end)); } pub fn write_byte(&mut self, byte: u8) { - self.status = RingBufferStatus::NORMAL; + self.status = RingBufferStatus::Normal; self.arr[self.tail] = byte; self.tail = (self.tail + 1) % RING_BUFFER_SIZE; if self.tail == self.head { - self.status = RingBufferStatus::FULL; + self.status = RingBufferStatus::Full; } } pub fn read_byte(&mut self) -> u8 { - self.status = RingBufferStatus::NORMAL; + self.status = RingBufferStatus::Normal; let c = self.arr[self.head]; self.head = (self.head + 1) % RING_BUFFER_SIZE; if self.head == self.tail { - self.status = RingBufferStatus::EMPTY; + self.status = RingBufferStatus::Empty; } c } pub fn available_read(&self) -> usize { - if self.status == RingBufferStatus::EMPTY { + if self.status == RingBufferStatus::Empty { 0 + } else if self.tail > self.head { + self.tail - self.head } else { - if self.tail > self.head { - self.tail - self.head - } else { - self.tail + RING_BUFFER_SIZE - self.head - } + self.tail + RING_BUFFER_SIZE - self.head } } pub fn available_write(&self) -> usize { - if self.status == RingBufferStatus::FULL { + if self.status == RingBufferStatus::Full { 0 } else { RING_BUFFER_SIZE - self.available_read() @@ -100,24 +98,22 @@ impl PipeRingBuffer { /// Return (read_end, write_end) pub fn make_pipe() -> (Arc, Arc) { - let buffer = Arc::new(unsafe { - UPSafeCell::new(PipeRingBuffer::new()) - }); - let read_end = Arc::new( - Pipe::read_end_with_buffer(buffer.clone()) - ); - let write_end = Arc::new( - Pipe::write_end_with_buffer(buffer.clone()) - ); + let buffer = Arc::new(unsafe { UPSafeCell::new(PipeRingBuffer::new()) }); + let read_end = Arc::new(Pipe::read_end_with_buffer(buffer.clone())); + let write_end = Arc::new(Pipe::write_end_with_buffer(buffer.clone())); buffer.exclusive_access().set_write_end(&write_end); (read_end, write_end) } impl File for Pipe { - fn readable(&self) -> bool { self.readable } - fn writable(&self) -> bool { self.writable } + fn readable(&self) -> bool { + self.readable + } + fn writable(&self) -> bool { + self.writable + } fn read(&self, buf: UserBuffer) -> usize { - assert_eq!(self.readable(), true); + assert!(self.readable()); let mut buf_iter = buf.into_iter(); let mut read_size = 0usize; loop { @@ -134,7 +130,9 @@ impl File for Pipe { // read at most loop_read bytes for _ in 0..loop_read { if let Some(byte_ref) = buf_iter.next() { - unsafe { *byte_ref = ring_buffer.read_byte(); } + unsafe { + *byte_ref = ring_buffer.read_byte(); + } read_size += 1; } else { return read_size; @@ -143,7 +141,7 @@ impl File for Pipe { } } fn write(&self, buf: UserBuffer) -> usize { - assert_eq!(self.writable(), true); + assert!(self.writable()); let mut buf_iter = buf.into_iter(); let mut write_size = 0usize; loop { @@ -165,4 +163,4 @@ impl File for Pipe { } } } -} \ No newline at end of file +} diff --git a/os/src/fs/stdio.rs b/os/src/fs/stdio.rs index e8df7950..7c74d3e1 100644 --- a/os/src/fs/stdio.rs +++ b/os/src/fs/stdio.rs @@ -1,5 +1,5 @@ use super::File; -use crate::mm::{UserBuffer}; +use crate::mm::UserBuffer; use crate::sbi::console_getchar; use crate::task::suspend_current_and_run_next; @@ -8,8 +8,12 @@ pub struct Stdin; pub struct Stdout; impl File for Stdin { - fn readable(&self) -> bool { true } - fn writable(&self) -> bool { false } + fn readable(&self) -> bool { + true + } + fn writable(&self) -> bool { + false + } fn read(&self, mut user_buf: UserBuffer) -> usize { assert_eq!(user_buf.len(), 1); // busy loop @@ -24,7 +28,9 @@ impl File for Stdin { } } let ch = c as u8; - unsafe { user_buf.buffers[0].as_mut_ptr().write_volatile(ch); } + unsafe { + user_buf.buffers[0].as_mut_ptr().write_volatile(ch); + } 1 } fn write(&self, _user_buf: UserBuffer) -> usize { @@ -33,9 +39,13 @@ impl File for Stdin { } impl File for Stdout { - fn readable(&self) -> bool { false } - fn writable(&self) -> bool { true } - fn read(&self, _user_buf: UserBuffer) -> usize{ + fn readable(&self) -> bool { + false + } + fn writable(&self) -> bool { + true + } + fn read(&self, _user_buf: UserBuffer) -> usize { panic!("Cannot read from stdout!"); } fn write(&self, user_buf: UserBuffer) -> usize { @@ -44,4 +54,4 @@ impl File for Stdout { } user_buf.len() } -} \ No newline at end of file +} diff --git a/os/src/lang_items.rs b/os/src/lang_items.rs index 21c7c512..6788148a 100644 --- a/os/src/lang_items.rs +++ b/os/src/lang_items.rs @@ -1,22 +1,23 @@ -use core::panic::PanicInfo; -use core::arch::asm; use crate::sbi::shutdown; use crate::task::current_kstack_top; +use core::arch::asm; +use core::panic::PanicInfo; #[panic_handler] fn panic(info: &PanicInfo) -> ! { - match info.location() { - Some(location) => { - println!("[kernel] panicked at '{}', {}:{}:{}", - info.message().unwrap(), - location.file(), - location.line(), - location.column() - ); - } - None => println!("[kernel] panicked at '{}'", info.message().unwrap()) + if let Some(location) = info.location() { + println!( + "[kernel] Panicked at {}:{} {}", + location.file(), + location.line(), + info.message().unwrap() + ); + } else { + println!("[kernel] Panicked: {}", info.message().unwrap()); + } + unsafe { + backtrace(); } - unsafe { backtrace(); } shutdown() } @@ -26,9 +27,11 @@ unsafe fn backtrace() { asm!("mv {}, s0", out(reg) fp); println!("---START BACKTRACE---"); for i in 0..10 { - if fp == stop { break; } - println!("#{}:ra={:#x}", i, *((fp-8) as *const usize)); - fp = *((fp-16) as *const usize); + if fp == stop { + break; + } + println!("#{}:ra={:#x}", i, *((fp - 8) as *const usize)); + fp = *((fp - 16) as *const usize); } println!("---END BACKTRACE---"); } diff --git a/os/src/loader.rs b/os/src/loader.rs deleted file mode 100644 index bfdc3970..00000000 --- a/os/src/loader.rs +++ /dev/null @@ -1,62 +0,0 @@ -use alloc::vec::Vec; -use lazy_static::*; - -pub fn get_num_app() -> usize { - extern "C" { fn _num_app(); } - unsafe { (_num_app as usize as *const usize).read_volatile() } -} - -pub fn get_app_data(app_id: usize) -> &'static [u8] { - extern "C" { fn _num_app(); } - let num_app_ptr = _num_app as usize as *const usize; - let num_app = get_num_app(); - let app_start = unsafe { - core::slice::from_raw_parts(num_app_ptr.add(1), num_app + 1) - }; - assert!(app_id < num_app); - unsafe { - core::slice::from_raw_parts( - app_start[app_id] as *const u8, - app_start[app_id + 1] - app_start[app_id] - ) - } -} - -lazy_static! { - static ref APP_NAMES: Vec<&'static str> = { - let num_app = get_num_app(); - extern "C" { fn _app_names(); } - let mut start = _app_names as usize as *const u8; - let mut v = Vec::new(); - unsafe { - for _ in 0..num_app { - let mut end = start; - while end.read_volatile() != '\0' as u8 { - end = end.add(1); - } - let slice = core::slice::from_raw_parts(start, end as usize - start as usize); - let str = core::str::from_utf8(slice).unwrap(); - v.push(str); - start = end.add(1); - } - } - v - }; -} - - -#[allow(unused)] -pub fn get_app_data_by_name(name: &str) -> Option<&'static [u8]> { - let num_app = get_num_app(); - (0..num_app) - .find(|&i| APP_NAMES[i] == name) - .map(|i| get_app_data(i)) -} - -pub fn list_apps() { - println!("/**** APPS ****"); - for app in APP_NAMES.iter() { - println!("{}", app); - } - println!("**************/"); -} \ No newline at end of file diff --git a/os/src/main.rs b/os/src/main.rs index 60192128..cbc4ab40 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -8,21 +8,28 @@ extern crate alloc; #[macro_use] extern crate bitflags; -use core::arch::global_asm; +#[cfg(feature = "board_k210")] +#[path = "boards/k210.rs"] +mod board; +#[cfg(not(any(feature = "board_k210")))] +#[path = "boards/qemu.rs"] +mod board; #[macro_use] mod console; +mod config; +mod drivers; +mod fs; mod lang_items; +mod mm; mod sbi; +mod sync; mod syscall; -mod trap; -mod config; mod task; mod timer; -mod sync; -mod mm; -mod fs; -mod drivers; +mod trap; + +use core::arch::global_asm; global_asm!(include_str!("entry.asm")); @@ -32,10 +39,8 @@ fn clear_bss() { fn ebss(); } unsafe { - core::slice::from_raw_parts_mut( - sbss as usize as *mut u8, - ebss as usize - sbss as usize, - ).fill(0); + core::slice::from_raw_parts_mut(sbss as usize as *mut u8, ebss as usize - sbss as usize) + .fill(0); } } diff --git a/os/src/mm/address.rs b/os/src/mm/address.rs index 107f35c6..dc5d08a8 100644 --- a/os/src/mm/address.rs +++ b/os/src/mm/address.rs @@ -1,5 +1,5 @@ -use crate::config::{PAGE_SIZE, PAGE_SIZE_BITS}; use super::PageTableEntry; +use crate::config::{PAGE_SIZE, PAGE_SIZE_BITS}; use core::fmt::{self, Debug, Formatter}; const PA_WIDTH_SV39: usize = 56; @@ -52,35 +52,59 @@ impl Debug for PhysPageNum { /// usize -> T: usize.into() impl From for PhysAddr { - fn from(v: usize) -> Self { Self(v & ( (1 << PA_WIDTH_SV39) - 1 )) } + fn from(v: usize) -> Self { + Self(v & ((1 << PA_WIDTH_SV39) - 1)) + } } impl From for PhysPageNum { - fn from(v: usize) -> Self { Self(v & ( (1 << PPN_WIDTH_SV39) - 1 )) } + fn from(v: usize) -> Self { + Self(v & ((1 << PPN_WIDTH_SV39) - 1)) + } } impl From for VirtAddr { - fn from(v: usize) -> Self { Self(v & ( (1 << VA_WIDTH_SV39) - 1 )) } + fn from(v: usize) -> Self { + Self(v & ((1 << VA_WIDTH_SV39) - 1)) + } } impl From for VirtPageNum { - fn from(v: usize) -> Self { Self(v & ( (1 << VPN_WIDTH_SV39) - 1 )) } + fn from(v: usize) -> Self { + Self(v & ((1 << VPN_WIDTH_SV39) - 1)) + } } impl From for usize { - fn from(v: PhysAddr) -> Self { v.0 } + fn from(v: PhysAddr) -> Self { + v.0 + } } impl From for usize { - fn from(v: PhysPageNum) -> Self { v.0 } + fn from(v: PhysPageNum) -> Self { + v.0 + } } impl From for usize { - fn from(v: VirtAddr) -> Self { v.0 } + fn from(v: VirtAddr) -> Self { + v.0 + } } impl From for usize { - fn from(v: VirtPageNum) -> Self { v.0 } + fn from(v: VirtPageNum) -> Self { + v.0 + } } impl VirtAddr { - pub fn floor(&self) -> VirtPageNum { VirtPageNum(self.0 / PAGE_SIZE) } - pub fn ceil(&self) -> VirtPageNum { VirtPageNum((self.0 - 1 + PAGE_SIZE) / PAGE_SIZE) } - pub fn page_offset(&self) -> usize { self.0 & (PAGE_SIZE - 1) } - pub fn aligned(&self) -> bool { self.page_offset() == 0 } + pub fn floor(&self) -> VirtPageNum { + VirtPageNum(self.0 / PAGE_SIZE) + } + pub fn ceil(&self) -> VirtPageNum { + VirtPageNum((self.0 - 1 + PAGE_SIZE) / PAGE_SIZE) + } + pub fn page_offset(&self) -> usize { + self.0 & (PAGE_SIZE - 1) + } + pub fn aligned(&self) -> bool { + self.page_offset() == 0 + } } impl From for VirtPageNum { fn from(v: VirtAddr) -> Self { @@ -89,13 +113,23 @@ impl From for VirtPageNum { } } impl From for VirtAddr { - fn from(v: VirtPageNum) -> Self { Self(v.0 << PAGE_SIZE_BITS) } + fn from(v: VirtPageNum) -> Self { + Self(v.0 << PAGE_SIZE_BITS) + } } impl PhysAddr { - pub fn floor(&self) -> PhysPageNum { PhysPageNum(self.0 / PAGE_SIZE) } - pub fn ceil(&self) -> PhysPageNum { PhysPageNum((self.0 - 1 + PAGE_SIZE) / PAGE_SIZE) } - pub fn page_offset(&self) -> usize { self.0 & (PAGE_SIZE - 1) } - pub fn aligned(&self) -> bool { self.page_offset() == 0 } + pub fn floor(&self) -> PhysPageNum { + PhysPageNum(self.0 / PAGE_SIZE) + } + pub fn ceil(&self) -> PhysPageNum { + PhysPageNum((self.0 - 1 + PAGE_SIZE) / PAGE_SIZE) + } + pub fn page_offset(&self) -> usize { + self.0 & (PAGE_SIZE - 1) + } + pub fn aligned(&self) -> bool { + self.page_offset() == 0 + } } impl From for PhysPageNum { fn from(v: PhysAddr) -> Self { @@ -104,7 +138,9 @@ impl From for PhysPageNum { } } impl From for PhysAddr { - fn from(v: PhysPageNum) -> Self { Self(v.0 << PAGE_SIZE_BITS) } + fn from(v: PhysPageNum) -> Self { + Self(v.0 << PAGE_SIZE_BITS) + } } impl VirtPageNum { @@ -121,31 +157,23 @@ impl VirtPageNum { impl PhysAddr { pub fn get_ref(&self) -> &'static T { - unsafe { - (self.0 as *const T).as_ref().unwrap() - } + unsafe { (self.0 as *const T).as_ref().unwrap() } } pub fn get_mut(&self) -> &'static mut T { - unsafe { - (self.0 as *mut T).as_mut().unwrap() - } + unsafe { (self.0 as *mut T).as_mut().unwrap() } } } impl PhysPageNum { pub fn get_pte_array(&self) -> &'static mut [PageTableEntry] { - let pa: PhysAddr = self.clone().into(); - unsafe { - core::slice::from_raw_parts_mut(pa.0 as *mut PageTableEntry, 512) - } + let pa: PhysAddr = (*self).into(); + unsafe { core::slice::from_raw_parts_mut(pa.0 as *mut PageTableEntry, 512) } } pub fn get_bytes_array(&self) -> &'static mut [u8] { - let pa: PhysAddr = self.clone().into(); - unsafe { - core::slice::from_raw_parts_mut(pa.0 as *mut u8, 4096) - } + let pa: PhysAddr = (*self).into(); + unsafe { core::slice::from_raw_parts_mut(pa.0 as *mut u8, 4096) } } pub fn get_mut(&self) -> &'static mut T { - let pa: PhysAddr = self.clone().into(); + let pa: PhysAddr = (*self).into(); pa.get_mut() } } @@ -165,41 +193,57 @@ impl StepByOne for PhysPageNum { } #[derive(Copy, Clone)] -pub struct SimpleRange where - T: StepByOne + Copy + PartialEq + PartialOrd + Debug, { +pub struct SimpleRange +where + T: StepByOne + Copy + PartialEq + PartialOrd + Debug, +{ l: T, r: T, } -impl SimpleRange where - T: StepByOne + Copy + PartialEq + PartialOrd + Debug, { +impl SimpleRange +where + T: StepByOne + Copy + PartialEq + PartialOrd + Debug, +{ pub fn new(start: T, end: T) -> Self { assert!(start <= end, "start {:?} > end {:?}!", start, end); Self { l: start, r: end } } - pub fn get_start(&self) -> T { self.l } - pub fn get_end(&self) -> T { self.r } + pub fn get_start(&self) -> T { + self.l + } + pub fn get_end(&self) -> T { + self.r + } } -impl IntoIterator for SimpleRange where - T: StepByOne + Copy + PartialEq + PartialOrd + Debug, { +impl IntoIterator for SimpleRange +where + T: StepByOne + Copy + PartialEq + PartialOrd + Debug, +{ type Item = T; type IntoIter = SimpleRangeIterator; fn into_iter(self) -> Self::IntoIter { SimpleRangeIterator::new(self.l, self.r) } } -pub struct SimpleRangeIterator where - T: StepByOne + Copy + PartialEq + PartialOrd + Debug, { +pub struct SimpleRangeIterator +where + T: StepByOne + Copy + PartialEq + PartialOrd + Debug, +{ current: T, end: T, } -impl SimpleRangeIterator where - T: StepByOne + Copy + PartialEq + PartialOrd + Debug, { +impl SimpleRangeIterator +where + T: StepByOne + Copy + PartialEq + PartialOrd + Debug, +{ pub fn new(l: T, r: T) -> Self { - Self { current: l, end: r, } + Self { current: l, end: r } } } -impl Iterator for SimpleRangeIterator where - T: StepByOne + Copy + PartialEq + PartialOrd + Debug, { +impl Iterator for SimpleRangeIterator +where + T: StepByOne + Copy + PartialEq + PartialOrd + Debug, +{ type Item = T; fn next(&mut self) -> Option { if self.current == self.end { diff --git a/os/src/mm/frame_allocator.rs b/os/src/mm/frame_allocator.rs index 357db707..4bc7db26 100644 --- a/os/src/mm/frame_allocator.rs +++ b/os/src/mm/frame_allocator.rs @@ -1,9 +1,9 @@ use super::{PhysAddr, PhysPageNum}; -use alloc::vec::Vec; -use crate::sync::UPSafeCell; use crate::config::MEMORY_END; -use lazy_static::*; +use crate::sync::UPSafeCell; +use alloc::vec::Vec; use core::fmt::{self, Debug, Formatter}; +use lazy_static::*; pub struct FrameTracker { pub ppn: PhysPageNum, @@ -62,22 +62,17 @@ impl FrameAllocator for StackFrameAllocator { fn alloc(&mut self) -> Option { if let Some(ppn) = self.recycled.pop() { Some(ppn.into()) + } else if self.current == self.end { + None } else { - if self.current == self.end { - None - } else { - self.current += 1; - Some((self.current - 1).into()) - } + self.current += 1; + Some((self.current - 1).into()) } } fn dealloc(&mut self, ppn: PhysPageNum) { let ppn = ppn.0; // validity check - if ppn >= self.current || self.recycled - .iter() - .find(|&v| {*v == ppn}) - .is_some() { + if ppn >= self.current || self.recycled.iter().any(|&v| v == ppn) { panic!("Frame ppn={:#x} has not been allocated!", ppn); } // recycle @@ -88,31 +83,29 @@ impl FrameAllocator for StackFrameAllocator { type FrameAllocatorImpl = StackFrameAllocator; lazy_static! { - pub static ref FRAME_ALLOCATOR: UPSafeCell = unsafe { - UPSafeCell::new(FrameAllocatorImpl::new()) - }; + pub static ref FRAME_ALLOCATOR: UPSafeCell = + unsafe { UPSafeCell::new(FrameAllocatorImpl::new()) }; } pub fn init_frame_allocator() { extern "C" { fn ekernel(); } - FRAME_ALLOCATOR - .exclusive_access() - .init(PhysAddr::from(ekernel as usize).ceil(), PhysAddr::from(MEMORY_END).floor()); + FRAME_ALLOCATOR.exclusive_access().init( + PhysAddr::from(ekernel as usize).ceil(), + PhysAddr::from(MEMORY_END).floor(), + ); } pub fn frame_alloc() -> Option { FRAME_ALLOCATOR .exclusive_access() .alloc() - .map(|ppn| FrameTracker::new(ppn)) + .map(FrameTracker::new) } pub fn frame_dealloc(ppn: PhysPageNum) { - FRAME_ALLOCATOR - .exclusive_access() - .dealloc(ppn); + FRAME_ALLOCATOR.exclusive_access().dealloc(ppn); } #[allow(unused)] @@ -131,4 +124,4 @@ pub fn frame_allocator_test() { } drop(v); println!("frame_allocator_test passed!"); -} \ No newline at end of file +} diff --git a/os/src/mm/heap_allocator.rs b/os/src/mm/heap_allocator.rs index 2c7468f2..42a6d769 100644 --- a/os/src/mm/heap_allocator.rs +++ b/os/src/mm/heap_allocator.rs @@ -1,5 +1,5 @@ -use buddy_system_allocator::LockedHeap; use crate::config::KERNEL_HEAP_SIZE; +use buddy_system_allocator::LockedHeap; #[global_allocator] static HEAP_ALLOCATOR: LockedHeap = LockedHeap::empty(); @@ -36,8 +36,8 @@ pub fn heap_test() { for i in 0..500 { v.push(i); } - for i in 0..500 { - assert_eq!(v[i], i); + for (i, val) in v.iter().take(500).enumerate() { + assert_eq!(*val, i); } assert!(bss_range.contains(&(v.as_ptr() as usize))); drop(v); diff --git a/os/src/mm/memory_set.rs b/os/src/mm/memory_set.rs index 30bc7689..0d0b0f1d 100644 --- a/os/src/mm/memory_set.rs +++ b/os/src/mm/memory_set.rs @@ -1,20 +1,15 @@ -use super::{PageTable, PageTableEntry, PTEFlags}; -use super::{VirtPageNum, VirtAddr, PhysPageNum, PhysAddr}; -use super::{FrameTracker, frame_alloc}; -use super::{VPNRange, StepByOne}; +use super::{frame_alloc, FrameTracker}; +use super::{PTEFlags, PageTable, PageTableEntry}; +use super::{PhysAddr, PhysPageNum, VirtAddr, VirtPageNum}; +use super::{StepByOne, VPNRange}; +use crate::config::{MEMORY_END, MMIO, PAGE_SIZE, TRAMPOLINE}; +use crate::sync::UPSafeCell; use alloc::collections::BTreeMap; -use alloc::vec::Vec; -use riscv::register::satp; use alloc::sync::Arc; -use lazy_static::*; -use crate::sync::UPSafeCell; -use crate::config::{ - MEMORY_END, - PAGE_SIZE, - TRAMPOLINE, - MMIO, -}; +use alloc::vec::Vec; use core::arch::asm; +use lazy_static::*; +use riscv::register::satp; extern "C" { fn stext(); @@ -30,9 +25,8 @@ extern "C" { } lazy_static! { - pub static ref KERNEL_SPACE: Arc> = Arc::new(unsafe { - UPSafeCell::new(MemorySet::new_kernel()) - }); + pub static ref KERNEL_SPACE: Arc> = + Arc::new(unsafe { UPSafeCell::new(MemorySet::new_kernel()) }); } pub fn kernel_token() -> usize { @@ -55,17 +49,24 @@ impl MemorySet { self.page_table.token() } /// Assume that no conflicts. - pub fn insert_framed_area(&mut self, start_va: VirtAddr, end_va: VirtAddr, permission: MapPermission) { - self.push(MapArea::new( - start_va, - end_va, - MapType::Framed, - permission, - ), None); + pub fn insert_framed_area( + &mut self, + start_va: VirtAddr, + end_va: VirtAddr, + permission: MapPermission, + ) { + self.push( + MapArea::new(start_va, end_va, MapType::Framed, permission), + None, + ); } pub fn remove_area_with_start_vpn(&mut self, start_vpn: VirtPageNum) { - if let Some((idx, area)) = self.areas.iter_mut().enumerate() - .find(|(_, area)| area.vpn_range.get_start() == start_vpn) { + if let Some((idx, area)) = self + .areas + .iter_mut() + .enumerate() + .find(|(_, area)| area.vpn_range.get_start() == start_vpn) + { area.unmap(&mut self.page_table); self.areas.remove(idx); } @@ -94,50 +95,71 @@ impl MemorySet { println!(".text [{:#x}, {:#x})", stext as usize, etext as usize); println!(".rodata [{:#x}, {:#x})", srodata as usize, erodata as usize); println!(".data [{:#x}, {:#x})", sdata as usize, edata as usize); - println!(".bss [{:#x}, {:#x})", sbss_with_stack as usize, ebss as usize); + println!( + ".bss [{:#x}, {:#x})", + sbss_with_stack as usize, ebss as usize + ); println!("mapping .text section"); - memory_set.push(MapArea::new( - (stext as usize).into(), - (etext as usize).into(), - MapType::Identical, - MapPermission::R | MapPermission::X, - ), None); + memory_set.push( + MapArea::new( + (stext as usize).into(), + (etext as usize).into(), + MapType::Identical, + MapPermission::R | MapPermission::X, + ), + None, + ); println!("mapping .rodata section"); - memory_set.push(MapArea::new( - (srodata as usize).into(), - (erodata as usize).into(), - MapType::Identical, - MapPermission::R, - ), None); + memory_set.push( + MapArea::new( + (srodata as usize).into(), + (erodata as usize).into(), + MapType::Identical, + MapPermission::R, + ), + None, + ); println!("mapping .data section"); - memory_set.push(MapArea::new( - (sdata as usize).into(), - (edata as usize).into(), - MapType::Identical, - MapPermission::R | MapPermission::W, - ), None); + memory_set.push( + MapArea::new( + (sdata as usize).into(), + (edata as usize).into(), + MapType::Identical, + MapPermission::R | MapPermission::W, + ), + None, + ); println!("mapping .bss section"); - memory_set.push(MapArea::new( - (sbss_with_stack as usize).into(), - (ebss as usize).into(), - MapType::Identical, - MapPermission::R | MapPermission::W, - ), None); + memory_set.push( + MapArea::new( + (sbss_with_stack as usize).into(), + (ebss as usize).into(), + MapType::Identical, + MapPermission::R | MapPermission::W, + ), + None, + ); println!("mapping physical memory"); - memory_set.push(MapArea::new( - (ekernel as usize).into(), - MEMORY_END.into(), - MapType::Identical, - MapPermission::R | MapPermission::W, - ), None); - println!("mapping memory-mapped registers"); - for pair in MMIO { - memory_set.push(MapArea::new( - (*pair).0.into(), - ((*pair).0 + (*pair).1).into(), + memory_set.push( + MapArea::new( + (ekernel as usize).into(), + MEMORY_END.into(), MapType::Identical, MapPermission::R | MapPermission::W, - ), None); + ), + None, + ); + println!("mapping memory-mapped registers"); + for pair in MMIO { + memory_set.push( + MapArea::new( + (*pair).0.into(), + ((*pair).0 + (*pair).1).into(), + MapType::Identical, + MapPermission::R | MapPermission::W, + ), + None, + ); } memory_set } @@ -161,26 +183,31 @@ impl MemorySet { let end_va: VirtAddr = ((ph.virtual_addr() + ph.mem_size()) as usize).into(); let mut map_perm = MapPermission::U; let ph_flags = ph.flags(); - if ph_flags.is_read() { map_perm |= MapPermission::R; } - if ph_flags.is_write() { map_perm |= MapPermission::W; } - if ph_flags.is_execute() { map_perm |= MapPermission::X; } - let map_area = MapArea::new( - start_va, - end_va, - MapType::Framed, - map_perm, - ); + if ph_flags.is_read() { + map_perm |= MapPermission::R; + } + if ph_flags.is_write() { + map_perm |= MapPermission::W; + } + if ph_flags.is_execute() { + map_perm |= MapPermission::X; + } + let map_area = MapArea::new(start_va, end_va, MapType::Framed, map_perm); max_end_vpn = map_area.vpn_range.get_end(); memory_set.push( map_area, - Some(&elf.input[ph.offset() as usize..(ph.offset() + ph.file_size()) as usize]) + Some(&elf.input[ph.offset() as usize..(ph.offset() + ph.file_size()) as usize]), ); } } let max_end_va: VirtAddr = max_end_vpn.into(); let mut user_stack_base: usize = max_end_va.into(); user_stack_base += PAGE_SIZE; - (memory_set, user_stack_base, elf.header.pt2.entry_point() as usize) + ( + memory_set, + user_stack_base, + elf.header.pt2.entry_point() as usize, + ) } pub fn from_existed_user(user_space: &MemorySet) -> MemorySet { let mut memory_set = Self::new_bare(); @@ -194,7 +221,9 @@ impl MemorySet { for vpn in area.vpn_range { let src_ppn = user_space.translate(vpn).unwrap().ppn(); let dst_ppn = memory_set.translate(vpn).unwrap().ppn(); - dst_ppn.get_bytes_array().copy_from_slice(src_ppn.get_bytes_array()); + dst_ppn + .get_bytes_array() + .copy_from_slice(src_ppn.get_bytes_array()); } } memory_set @@ -227,7 +256,7 @@ impl MapArea { start_va: VirtAddr, end_va: VirtAddr, map_type: MapType, - map_perm: MapPermission + map_perm: MapPermission, ) -> Self { let start_vpn: VirtPageNum = start_va.floor(); let end_vpn: VirtPageNum = end_va.ceil(); @@ -262,11 +291,8 @@ impl MapArea { page_table.map(vpn, ppn, pte_flags); } pub fn unmap_one(&mut self, page_table: &mut PageTable, vpn: VirtPageNum) { - match self.map_type { - MapType::Framed => { - self.data_frames.remove(&vpn); - } - _ => {} + if self.map_type == MapType::Framed { + self.data_frames.remove(&vpn); } page_table.unmap(vpn); } @@ -325,17 +351,26 @@ pub fn remap_test() { let mid_text: VirtAddr = ((stext as usize + etext as usize) / 2).into(); let mid_rodata: VirtAddr = ((srodata as usize + erodata as usize) / 2).into(); let mid_data: VirtAddr = ((sdata as usize + edata as usize) / 2).into(); - assert_eq!( - kernel_space.page_table.translate(mid_text.floor()).unwrap().writable(), - false + assert!( + !kernel_space + .page_table + .translate(mid_text.floor()) + .unwrap() + .writable(), ); - assert_eq!( - kernel_space.page_table.translate(mid_rodata.floor()).unwrap().writable(), - false, + assert!( + !kernel_space + .page_table + .translate(mid_rodata.floor()) + .unwrap() + .writable(), ); - assert_eq!( - kernel_space.page_table.translate(mid_data.floor()).unwrap().executable(), - false, + assert!( + !kernel_space + .page_table + .translate(mid_data.floor()) + .unwrap() + .executable(), ); println!("remap_test passed!"); } diff --git a/os/src/mm/mod.rs b/os/src/mm/mod.rs index 85e8c16a..34220c4a 100644 --- a/os/src/mm/mod.rs +++ b/os/src/mm/mod.rs @@ -1,28 +1,22 @@ -mod heap_allocator; mod address; mod frame_allocator; -mod page_table; +mod heap_allocator; mod memory_set; +mod page_table; -use page_table::PTEFlags; use address::VPNRange; -pub use address::{PhysAddr, VirtAddr, PhysPageNum, VirtPageNum, StepByOne}; -pub use frame_allocator::{FrameTracker, frame_alloc, frame_dealloc,}; +pub use address::{PhysAddr, PhysPageNum, StepByOne, VirtAddr, VirtPageNum}; +pub use frame_allocator::{frame_alloc, frame_dealloc, FrameTracker}; +pub use memory_set::remap_test; +pub use memory_set::{kernel_token, MapPermission, MemorySet, KERNEL_SPACE}; +use page_table::PTEFlags; pub use page_table::{ - PageTable, - PageTableEntry, - translated_byte_buffer, - translated_str, - translated_ref, - translated_refmut, - UserBuffer, - UserBufferIterator, + translated_byte_buffer, translated_ref, translated_refmut, translated_str, PageTable, + PageTableEntry, UserBuffer, UserBufferIterator, }; -pub use memory_set::{MemorySet, KERNEL_SPACE, MapPermission, kernel_token}; -pub use memory_set::remap_test; pub fn init() { heap_allocator::init_heap(); frame_allocator::init_frame_allocator(); KERNEL_SPACE.exclusive_access().activate(); -} \ No newline at end of file +} diff --git a/os/src/mm/page_table.rs b/os/src/mm/page_table.rs index 0ce485ce..dfaf4b6c 100644 --- a/os/src/mm/page_table.rs +++ b/os/src/mm/page_table.rs @@ -1,15 +1,7 @@ -use super::{ - frame_alloc, - PhysPageNum, - FrameTracker, - VirtPageNum, - VirtAddr, - PhysAddr, - StepByOne -}; -use alloc::vec::Vec; -use alloc::vec; +use super::{frame_alloc, FrameTracker, PhysAddr, PhysPageNum, StepByOne, VirtAddr, VirtPageNum}; use alloc::string::String; +use alloc::vec; +use alloc::vec::Vec; use bitflags::*; bitflags! { @@ -38,9 +30,7 @@ impl PageTableEntry { } } pub fn empty() -> Self { - PageTableEntry { - bits: 0, - } + PageTableEntry { bits: 0 } } pub fn ppn(&self) -> PhysPageNum { (self.bits >> 10 & ((1usize << 44) - 1)).into() @@ -87,8 +77,8 @@ impl PageTable { let idxs = vpn.indexes(); let mut ppn = self.root_ppn; let mut result: Option<&mut PageTableEntry> = None; - for i in 0..3 { - let pte = &mut ppn.get_pte_array()[idxs[i]]; + for (i, idx) in idxs.iter().enumerate() { + let pte = &mut ppn.get_pte_array()[*idx]; if i == 2 { result = Some(pte); break; @@ -106,8 +96,8 @@ impl PageTable { let idxs = vpn.indexes(); let mut ppn = self.root_ppn; let mut result: Option<&mut PageTableEntry> = None; - for i in 0..3 { - let pte = &mut ppn.get_pte_array()[idxs[i]]; + for (i, idx) in idxs.iter().enumerate() { + let pte = &mut ppn.get_pte_array()[*idx]; if i == 2 { result = Some(pte); break; @@ -132,17 +122,15 @@ impl PageTable { *pte = PageTableEntry::empty(); } pub fn translate(&self, vpn: VirtPageNum) -> Option { - self.find_pte(vpn) - .map(|pte| {pte.clone()}) + self.find_pte(vpn).map(|pte| *pte) } pub fn translate_va(&self, va: VirtAddr) -> Option { - self.find_pte(va.clone().floor()) - .map(|pte| { - let aligned_pa: PhysAddr = pte.ppn().into(); - let offset = va.page_offset(); - let aligned_pa_usize: usize = aligned_pa.into(); - (aligned_pa_usize + offset).into() - }) + self.find_pte(va.clone().floor()).map(|pte| { + let aligned_pa: PhysAddr = pte.ppn().into(); + let offset = va.page_offset(); + let aligned_pa_usize: usize = aligned_pa.into(); + (aligned_pa_usize + offset).into() + }) } pub fn token(&self) -> usize { 8usize << 60 | self.root_ppn.0 @@ -157,10 +145,7 @@ pub fn translated_byte_buffer(token: usize, ptr: *const u8, len: usize) -> Vec<& while start < end { let start_va = VirtAddr::from(start); let mut vpn = start_va.floor(); - let ppn = page_table - .translate(vpn) - .unwrap() - .ppn(); + let ppn = page_table.translate(vpn).unwrap().ppn(); vpn.step(); let mut end_va: VirtAddr = vpn.into(); end_va = end_va.min(VirtAddr::from(end)); @@ -180,7 +165,10 @@ pub fn translated_str(token: usize, ptr: *const u8) -> String { let mut string = String::new(); let mut va = ptr as usize; loop { - let ch: u8 = *(page_table.translate_va(VirtAddr::from(va)).unwrap().get_mut()); + let ch: u8 = *(page_table + .translate_va(VirtAddr::from(va)) + .unwrap() + .get_mut()); if ch == 0 { break; } @@ -192,13 +180,19 @@ pub fn translated_str(token: usize, ptr: *const u8) -> String { pub fn translated_ref(token: usize, ptr: *const T) -> &'static T { let page_table = PageTable::from_token(token); - page_table.translate_va(VirtAddr::from(ptr as usize)).unwrap().get_ref() + page_table + .translate_va(VirtAddr::from(ptr as usize)) + .unwrap() + .get_ref() } pub fn translated_refmut(token: usize, ptr: *mut T) -> &'static mut T { let page_table = PageTable::from_token(token); let va = ptr as usize; - page_table.translate_va(VirtAddr::from(va)).unwrap().get_mut() + page_table + .translate_va(VirtAddr::from(va)) + .unwrap() + .get_mut() } pub struct UserBuffer { diff --git a/os/src/sbi.rs b/os/src/sbi.rs index 6231c9c3..75b2f432 100644 --- a/os/src/sbi.rs +++ b/os/src/sbi.rs @@ -1,5 +1,7 @@ #![allow(unused)] +use core::arch::asm; + const SBI_SET_TIMER: usize = 0; const SBI_CONSOLE_PUTCHAR: usize = 1; const SBI_CONSOLE_GETCHAR: usize = 2; @@ -41,4 +43,3 @@ pub fn shutdown() -> ! { sbi_call(SBI_SHUTDOWN, 0, 0, 0); panic!("It should shutdown!"); } - diff --git a/os/src/sync/condvar.rs b/os/src/sync/condvar.rs new file mode 100644 index 00000000..f96cd915 --- /dev/null +++ b/os/src/sync/condvar.rs @@ -0,0 +1,39 @@ +use crate::sync::{Mutex, UPSafeCell}; +use crate::task::{add_task, block_current_and_run_next, current_task, TaskControlBlock}; +use alloc::{collections::VecDeque, sync::Arc}; + +pub struct Condvar { + pub inner: UPSafeCell, +} + +pub struct CondvarInner { + pub wait_queue: VecDeque>, +} + +impl Condvar { + pub fn new() -> Self { + Self { + inner: unsafe { + UPSafeCell::new(CondvarInner { + wait_queue: VecDeque::new(), + }) + }, + } + } + + pub fn signal(&self) { + let mut inner = self.inner.exclusive_access(); + if let Some(task) = inner.wait_queue.pop_front() { + add_task(task); + } + } + + pub fn wait(&self, mutex: Arc) { + mutex.unlock(); + let mut inner = self.inner.exclusive_access(); + inner.wait_queue.push_back(current_task().unwrap()); + drop(inner); + block_current_and_run_next(); + mutex.lock(); + } +} diff --git a/os/src/sync/mod.rs b/os/src/sync/mod.rs index ed39a630..7e948aa6 100644 --- a/os/src/sync/mod.rs +++ b/os/src/sync/mod.rs @@ -1,7 +1,9 @@ -mod up; +mod condvar; mod mutex; mod semaphore; +mod up; -pub use up::UPSafeCell; -pub use mutex::{Mutex, MutexSpin, MutexBlocking}; +pub use condvar::Condvar; +pub use mutex::{Mutex, MutexBlocking, MutexSpin}; pub use semaphore::Semaphore; +pub use up::UPSafeCell; diff --git a/os/src/sync/mutex.rs b/os/src/sync/mutex.rs index ef45bbf2..be58f795 100644 --- a/os/src/sync/mutex.rs +++ b/os/src/sync/mutex.rs @@ -1,8 +1,8 @@ use super::UPSafeCell; -use crate::task::{block_current_and_run_next, suspend_current_and_run_next}; use crate::task::TaskControlBlock; use crate::task::{add_task, current_task}; -use alloc::{sync::Arc, collections::VecDeque}; +use crate::task::{block_current_and_run_next, suspend_current_and_run_next}; +use alloc::{collections::VecDeque, sync::Arc}; pub trait Mutex: Sync + Send { fn lock(&self); @@ -77,11 +77,12 @@ impl Mutex for MutexBlocking { } fn unlock(&self) { - let mut mutex_inner = self.inner.exclusive_access(); - assert_eq!(mutex_inner.locked, true); - mutex_inner.locked = false; + let mut mutex_inner = self.inner.exclusive_access(); + assert!(mutex_inner.locked); if let Some(waking_task) = mutex_inner.wait_queue.pop_front() { add_task(waking_task); + } else { + mutex_inner.locked = false; } } } diff --git a/os/src/sync/semaphore.rs b/os/src/sync/semaphore.rs index 2f66b87f..7f3870f8 100644 --- a/os/src/sync/semaphore.rs +++ b/os/src/sync/semaphore.rs @@ -1,6 +1,6 @@ -use alloc::{sync::Arc, collections::VecDeque}; -use crate::task::{add_task, TaskControlBlock, current_task, block_current_and_run_next}; use crate::sync::UPSafeCell; +use crate::task::{add_task, block_current_and_run_next, current_task, TaskControlBlock}; +use alloc::{collections::VecDeque, sync::Arc}; pub struct Semaphore { pub inner: UPSafeCell, @@ -14,12 +14,12 @@ pub struct SemaphoreInner { impl Semaphore { pub fn new(res_count: usize) -> Self { Self { - inner: unsafe { UPSafeCell::new( - SemaphoreInner { + inner: unsafe { + UPSafeCell::new(SemaphoreInner { count: res_count as isize, wait_queue: VecDeque::new(), - } - )}, + }) + }, } } diff --git a/os/src/sync/up.rs b/os/src/sync/up.rs index 642668c1..c7b2c9ee 100644 --- a/os/src/sync/up.rs +++ b/os/src/sync/up.rs @@ -18,10 +18,12 @@ impl UPSafeCell { /// User is responsible to guarantee that inner struct is only used in /// uniprocessor. pub unsafe fn new(value: T) -> Self { - Self { inner: RefCell::new(value) } + Self { + inner: RefCell::new(value), + } } /// Panic if the data has been borrowed. pub fn exclusive_access(&self) -> RefMut<'_, T> { self.inner.borrow_mut() } -} \ No newline at end of file +} diff --git a/os/src/syscall/fs.rs b/os/src/syscall/fs.rs index c8c476f1..27588257 100644 --- a/os/src/syscall/fs.rs +++ b/os/src/syscall/fs.rs @@ -1,11 +1,6 @@ -use crate::mm::{ - UserBuffer, - translated_byte_buffer, - translated_refmut, - translated_str, -}; -use crate::task::{current_user_token, current_process}; -use crate::fs::{make_pipe, OpenFlags, open_file}; +use crate::fs::{make_pipe, open_file, OpenFlags}; +use crate::mm::{translated_byte_buffer, translated_refmut, translated_str, UserBuffer}; +use crate::task::{current_process, current_user_token}; use alloc::sync::Arc; pub fn sys_write(fd: usize, buf: *const u8, len: usize) -> isize { @@ -22,9 +17,7 @@ pub fn sys_write(fd: usize, buf: *const u8, len: usize) -> isize { let file = file.clone(); // release current task TCB manually to avoid multi-borrow drop(inner); - file.write( - UserBuffer::new(translated_byte_buffer(token, buf, len)) - ) as isize + file.write(UserBuffer::new(translated_byte_buffer(token, buf, len))) as isize } else { -1 } @@ -44,9 +37,7 @@ pub fn sys_read(fd: usize, buf: *const u8, len: usize) -> isize { } // release current task TCB manually to avoid multi-borrow drop(inner); - file.read( - UserBuffer::new(translated_byte_buffer(token, buf, len)) - ) as isize + file.read(UserBuffer::new(translated_byte_buffer(token, buf, len))) as isize } else { -1 } @@ -56,10 +47,7 @@ pub fn sys_open(path: *const u8, flags: u32) -> isize { let process = current_process(); let token = current_user_token(); let path = translated_str(token, path); - if let Some(inode) = open_file( - path.as_str(), - OpenFlags::from_bits(flags).unwrap() - ) { + if let Some(inode) = open_file(path.as_str(), OpenFlags::from_bits(flags).unwrap()) { let mut inner = process.inner_exclusive_access(); let fd = inner.alloc_fd(); inner.fd_table[fd] = Some(inode); diff --git a/os/src/syscall/mod.rs b/os/src/syscall/mod.rs index eac72aae..fa4a4cf1 100644 --- a/os/src/syscall/mod.rs +++ b/os/src/syscall/mod.rs @@ -7,6 +7,7 @@ const SYSCALL_WRITE: usize = 64; const SYSCALL_EXIT: usize = 93; const SYSCALL_SLEEP: usize = 101; const SYSCALL_YIELD: usize = 124; +const SYSCALL_KILL: usize = 129; const SYSCALL_GET_TIME: usize = 169; const SYSCALL_GETPID: usize = 172; const SYSCALL_FORK: usize = 220; @@ -21,20 +22,23 @@ const SYSCALL_MUTEX_UNLOCK: usize = 1012; const SYSCALL_SEMAPHORE_CREATE: usize = 1020; const SYSCALL_SEMAPHORE_UP: usize = 1021; const SYSCALL_SEMAPHORE_DOWN: usize = 1022; +const SYSCALL_CONDVAR_CREATE: usize = 1030; +const SYSCALL_CONDVAR_SIGNAL: usize = 1031; +const SYSCALL_CONDVAR_WAIT: usize = 1032; mod fs; mod process; -mod thread; mod sync; +mod thread; use fs::*; use process::*; -use thread::*; use sync::*; +use thread::*; pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize { match syscall_id { - SYSCALL_DUP=> sys_dup(args[0]), + SYSCALL_DUP => sys_dup(args[0]), SYSCALL_OPEN => sys_open(args[0] as *const u8, args[1] as u32), SYSCALL_CLOSE => sys_close(args[0]), SYSCALL_PIPE => sys_pipe(args[0] as *mut usize), @@ -43,6 +47,7 @@ pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize { SYSCALL_EXIT => sys_exit(args[0] as i32), SYSCALL_SLEEP => sys_sleep(args[0]), SYSCALL_YIELD => sys_yield(), + SYSCALL_KILL => sys_kill(args[0], args[1] as u32), SYSCALL_GET_TIME => sys_get_time(), SYSCALL_GETPID => sys_getpid(), SYSCALL_FORK => sys_fork(), @@ -54,10 +59,12 @@ pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize { SYSCALL_MUTEX_CREATE => sys_mutex_create(args[0] == 1), SYSCALL_MUTEX_LOCK => sys_mutex_lock(args[0]), SYSCALL_MUTEX_UNLOCK => sys_mutex_unlock(args[0]), - SYSCALL_SEMAPHORE_CREATE => sys_semaphore_creare(args[0]), + SYSCALL_SEMAPHORE_CREATE => sys_semaphore_create(args[0]), SYSCALL_SEMAPHORE_UP => sys_semaphore_up(args[0]), SYSCALL_SEMAPHORE_DOWN => sys_semaphore_down(args[0]), + SYSCALL_CONDVAR_CREATE => sys_condvar_create(args[0]), + SYSCALL_CONDVAR_SIGNAL => sys_condvar_signal(args[0]), + SYSCALL_CONDVAR_WAIT => sys_condvar_wait(args[0], args[1]), _ => panic!("Unsupported syscall_id: {}", syscall_id), } } - diff --git a/os/src/syscall/process.rs b/os/src/syscall/process.rs index d9c98a92..7d5b67ab 100644 --- a/os/src/syscall/process.rs +++ b/os/src/syscall/process.rs @@ -1,23 +1,13 @@ +use crate::fs::{open_file, OpenFlags}; +use crate::mm::{translated_ref, translated_refmut, translated_str}; use crate::task::{ - suspend_current_and_run_next, - exit_current_and_run_next, - current_task, - current_process, - current_user_token, + current_process, current_task, current_user_token, exit_current_and_run_next, pid2process, + suspend_current_and_run_next, SignalFlags, }; use crate::timer::get_time_ms; -use crate::mm::{ - translated_str, - translated_refmut, - translated_ref, -}; -use crate::fs::{ - open_file, - OpenFlags, -}; +use alloc::string::String; use alloc::sync::Arc; use alloc::vec::Vec; -use alloc::string::String; pub fn sys_exit(exit_code: i32) -> ! { exit_current_and_run_next(exit_code); @@ -61,7 +51,9 @@ pub fn sys_exec(path: *const u8, mut args: *const usize) -> isize { break; } args_vec.push(translated_str(token, arg_str_ptr as *const u8)); - unsafe { args = args.add(1); } + unsafe { + args = args.add(1); + } } if let Some(app_inode) = open_file(path.as_str(), OpenFlags::RDONLY) { let all_data = app_inode.read_all(); @@ -82,21 +74,19 @@ pub fn sys_waitpid(pid: isize, exit_code_ptr: *mut i32) -> isize { // find a child process let mut inner = process.inner_exclusive_access(); - if inner.children + if !inner + .children .iter() - .find(|p| {pid == -1 || pid as usize == p.getpid()}) - .is_none() { + .any(|p| pid == -1 || pid as usize == p.getpid()) + { return -1; // ---- release current PCB } - let pair = inner.children - .iter() - .enumerate() - .find(|(_, p)| { - // ++++ temporarily access child PCB exclusively - p.inner_exclusive_access().is_zombie && (pid == -1 || pid as usize == p.getpid()) - // ++++ release child PCB - }); + let pair = inner.children.iter().enumerate().find(|(_, p)| { + // ++++ temporarily access child PCB exclusively + p.inner_exclusive_access().is_zombie && (pid == -1 || pid as usize == p.getpid()) + // ++++ release child PCB + }); if let Some((idx, _)) = pair { let child = inner.children.remove(idx); // confirm that child will be deallocated after being removed from children list @@ -112,3 +102,16 @@ pub fn sys_waitpid(pid: isize, exit_code_ptr: *mut i32) -> isize { } // ---- release current PCB automatically } + +pub fn sys_kill(pid: usize, signal: u32) -> isize { + if let Some(process) = pid2process(pid) { + if let Some(flag) = SignalFlags::from_bits(signal) { + process.inner_exclusive_access().signals |= flag; + 0 + } else { + -1 + } + } else { + -1 + } +} diff --git a/os/src/syscall/sync.rs b/os/src/syscall/sync.rs index 370af848..dd0e856a 100644 --- a/os/src/syscall/sync.rs +++ b/os/src/syscall/sync.rs @@ -1,6 +1,6 @@ -use crate::task::{current_task, current_process, block_current_and_run_next}; -use crate::sync::{MutexSpin, MutexBlocking, Semaphore}; -use crate::timer::{get_time_ms, add_timer}; +use crate::sync::{Condvar, Mutex, MutexBlocking, MutexSpin, Semaphore}; +use crate::task::{block_current_and_run_next, current_process, current_task}; +use crate::timer::{add_timer, get_time_ms}; use alloc::sync::Arc; pub fn sys_sleep(ms: usize) -> isize { @@ -13,21 +13,23 @@ pub fn sys_sleep(ms: usize) -> isize { pub fn sys_mutex_create(blocking: bool) -> isize { let process = current_process(); + let mutex: Option> = if !blocking { + Some(Arc::new(MutexSpin::new())) + } else { + Some(Arc::new(MutexBlocking::new())) + }; let mut process_inner = process.inner_exclusive_access(); if let Some(id) = process_inner .mutex_list .iter() .enumerate() .find(|(_, item)| item.is_none()) - .map(|(id, _)| id) { - process_inner.mutex_list[id] = if !blocking { - Some(Arc::new(MutexSpin::new())) - } else { - Some(Arc::new(MutexBlocking::new())) - }; + .map(|(id, _)| id) + { + process_inner.mutex_list[id] = mutex; id as isize } else { - process_inner.mutex_list.push(Some(Arc::new(MutexSpin::new()))); + process_inner.mutex_list.push(mutex); process_inner.mutex_list.len() as isize - 1 } } @@ -52,7 +54,7 @@ pub fn sys_mutex_unlock(mutex_id: usize) -> isize { 0 } -pub fn sys_semaphore_creare(res_count: usize) -> isize { +pub fn sys_semaphore_create(res_count: usize) -> isize { let process = current_process(); let mut process_inner = process.inner_exclusive_access(); let id = if let Some(id) = process_inner @@ -60,11 +62,14 @@ pub fn sys_semaphore_creare(res_count: usize) -> isize { .iter() .enumerate() .find(|(_, item)| item.is_none()) - .map(|(id, _)| id) { - process_inner.semaphore_list[id] = Some(Arc::new(Semaphore::new(res_count))); + .map(|(id, _)| id) + { + process_inner.semaphore_list[id] = Some(Arc::new(Semaphore::new(res_count))); id } else { - process_inner.semaphore_list.push(Some(Arc::new(Semaphore::new(res_count)))); + process_inner + .semaphore_list + .push(Some(Arc::new(Semaphore::new(res_count)))); process_inner.semaphore_list.len() - 1 }; id as isize @@ -87,3 +92,43 @@ pub fn sys_semaphore_down(sem_id: usize) -> isize { sem.down(); 0 } + +pub fn sys_condvar_create(_arg: usize) -> isize { + let process = current_process(); + let mut process_inner = process.inner_exclusive_access(); + let id = if let Some(id) = process_inner + .condvar_list + .iter() + .enumerate() + .find(|(_, item)| item.is_none()) + .map(|(id, _)| id) + { + process_inner.condvar_list[id] = Some(Arc::new(Condvar::new())); + id + } else { + process_inner + .condvar_list + .push(Some(Arc::new(Condvar::new()))); + process_inner.condvar_list.len() - 1 + }; + id as isize +} + +pub fn sys_condvar_signal(condvar_id: usize) -> isize { + let process = current_process(); + let process_inner = process.inner_exclusive_access(); + let condvar = Arc::clone(process_inner.condvar_list[condvar_id].as_ref().unwrap()); + drop(process_inner); + condvar.signal(); + 0 +} + +pub fn sys_condvar_wait(condvar_id: usize, mutex_id: usize) -> isize { + let process = current_process(); + let process_inner = process.inner_exclusive_access(); + let condvar = Arc::clone(process_inner.condvar_list[condvar_id].as_ref().unwrap()); + let mutex = Arc::clone(process_inner.mutex_list[mutex_id].as_ref().unwrap()); + drop(process_inner); + condvar.wait(mutex); + 0 +} diff --git a/os/src/syscall/thread.rs b/os/src/syscall/thread.rs index fa3b181a..3955d9de 100644 --- a/os/src/syscall/thread.rs +++ b/os/src/syscall/thread.rs @@ -1,5 +1,9 @@ +use crate::{ + mm::kernel_token, + task::{add_task, current_task, TaskControlBlock}, + trap::{trap_handler, TrapContext}, +}; use alloc::sync::Arc; -use crate::{mm::kernel_token, task::{TaskControlBlock, add_task, current_task}, trap::{TrapContext, trap_handler}}; pub fn sys_thread_create(entry: usize, arg: usize) -> isize { let task = current_task().unwrap(); @@ -7,7 +11,11 @@ pub fn sys_thread_create(entry: usize, arg: usize) -> isize { // create a new thread let new_task = Arc::new(TaskControlBlock::new( Arc::clone(&process), - task.inner_exclusive_access().res.as_ref().unwrap().ustack_base, + task.inner_exclusive_access() + .res + .as_ref() + .unwrap() + .ustack_base, true, )); // add new task to scheduler @@ -35,7 +43,13 @@ pub fn sys_thread_create(entry: usize, arg: usize) -> isize { } pub fn sys_gettid() -> isize { - current_task().unwrap().inner_exclusive_access().res.as_ref().unwrap().tid as isize + current_task() + .unwrap() + .inner_exclusive_access() + .res + .as_ref() + .unwrap() + .tid as isize } /// thread does not exist, return -1 diff --git a/os/src/task/context.rs b/os/src/task/context.rs index d25cc2c8..e4f59d8a 100644 --- a/os/src/task/context.rs +++ b/os/src/task/context.rs @@ -23,4 +23,3 @@ impl TaskContext { } } } - diff --git a/os/src/task/id.rs b/os/src/task/id.rs index f94488c8..178a09f6 100644 --- a/os/src/task/id.rs +++ b/os/src/task/id.rs @@ -1,9 +1,12 @@ -use alloc::{vec::Vec, sync::{Arc, Weak}}; -use lazy_static::*; -use crate::sync::UPSafeCell; -use crate::mm::{KERNEL_SPACE, MapPermission, PhysPageNum, VirtAddr}; -use crate::config::{KERNEL_STACK_SIZE, PAGE_SIZE, TRAMPOLINE, TRAP_CONTEXT_BASE, USER_STACK_SIZE}; use super::ProcessControlBlock; +use crate::config::{KERNEL_STACK_SIZE, PAGE_SIZE, TRAMPOLINE, TRAP_CONTEXT_BASE, USER_STACK_SIZE}; +use crate::mm::{MapPermission, PhysPageNum, VirtAddr, KERNEL_SPACE}; +use crate::sync::UPSafeCell; +use alloc::{ + sync::{Arc, Weak}, + vec::Vec, +}; +use lazy_static::*; pub struct RecycleAllocator { current: usize, @@ -28,21 +31,19 @@ impl RecycleAllocator { pub fn dealloc(&mut self, id: usize) { assert!(id < self.current); assert!( - self.recycled.iter().find(|i| **i == id).is_none(), - "id {} has been deallocated!", id + !self.recycled.iter().any(|i| *i == id), + "id {} has been deallocated!", + id ); self.recycled.push(id); } } lazy_static! { - static ref PID_ALLOCATOR: UPSafeCell = unsafe { - UPSafeCell::new(RecycleAllocator::new()) - }; - - static ref KSTACK_ALLOCATOR: UPSafeCell = unsafe { - UPSafeCell::new(RecycleAllocator::new()) - }; + static ref PID_ALLOCATOR: UPSafeCell = + unsafe { UPSafeCell::new(RecycleAllocator::new()) }; + static ref KSTACK_ALLOCATOR: UPSafeCell = + unsafe { UPSafeCell::new(RecycleAllocator::new()) }; } pub struct PidHandle(pub usize); @@ -69,13 +70,11 @@ pub struct KernelStack(pub usize); pub fn kstack_alloc() -> KernelStack { let kstack_id = KSTACK_ALLOCATOR.exclusive_access().alloc(); let (kstack_bottom, kstack_top) = kernel_stack_position(kstack_id); - KERNEL_SPACE - .exclusive_access() - .insert_framed_area( - kstack_bottom.into(), - kstack_top.into(), - MapPermission::R | MapPermission::W, - ); + KERNEL_SPACE.exclusive_access().insert_framed_area( + kstack_bottom.into(), + kstack_top.into(), + MapPermission::R | MapPermission::W, + ); KernelStack(kstack_id) } @@ -91,11 +90,15 @@ impl Drop for KernelStack { impl KernelStack { #[allow(unused)] - pub fn push_on_top(&self, value: T) -> *mut T where - T: Sized, { + pub fn push_on_top(&self, value: T) -> *mut T + where + T: Sized, + { let kernel_stack_top = self.get_top(); let ptr_mut = (kernel_stack_top - core::mem::size_of::()) as *mut T; - unsafe { *ptr_mut = value; } + unsafe { + *ptr_mut = value; + } ptr_mut } pub fn get_top(&self) -> usize { @@ -142,23 +145,19 @@ impl TaskUserRes { // alloc user stack let ustack_bottom = ustack_bottom_from_tid(self.ustack_base, self.tid); let ustack_top = ustack_bottom + USER_STACK_SIZE; - process_inner - .memory_set - .insert_framed_area( - ustack_bottom.into(), - ustack_top.into(), - MapPermission::R | MapPermission::W | MapPermission::U, - ); + process_inner.memory_set.insert_framed_area( + ustack_bottom.into(), + ustack_top.into(), + MapPermission::R | MapPermission::W | MapPermission::U, + ); // alloc trap_cx let trap_cx_bottom = trap_cx_bottom_from_tid(self.tid); let trap_cx_top = trap_cx_bottom + PAGE_SIZE; - process_inner - .memory_set - .insert_framed_area( - trap_cx_bottom.into(), - trap_cx_top.into(), - MapPermission::R | MapPermission::W, - ); + process_inner.memory_set.insert_framed_area( + trap_cx_bottom.into(), + trap_cx_top.into(), + MapPermission::R | MapPermission::W, + ); } fn dealloc_user_res(&self) { @@ -167,10 +166,14 @@ impl TaskUserRes { let mut process_inner = process.inner_exclusive_access(); // dealloc ustack manually let ustack_bottom_va: VirtAddr = ustack_bottom_from_tid(self.ustack_base, self.tid).into(); - process_inner.memory_set.remove_area_with_start_vpn(ustack_bottom_va.into()); + process_inner + .memory_set + .remove_area_with_start_vpn(ustack_bottom_va.into()); // dealloc trap_cx manually let trap_cx_bottom_va: VirtAddr = trap_cx_bottom_from_tid(self.tid).into(); - process_inner.memory_set.remove_area_with_start_vpn(trap_cx_bottom_va.into()); + process_inner + .memory_set + .remove_area_with_start_vpn(trap_cx_bottom_va.into()); } #[allow(unused)] @@ -197,12 +200,18 @@ impl TaskUserRes { let process = self.process.upgrade().unwrap(); let process_inner = process.inner_exclusive_access(); let trap_cx_bottom_va: VirtAddr = trap_cx_bottom_from_tid(self.tid).into(); - process_inner.memory_set.translate(trap_cx_bottom_va.into()).unwrap().ppn() + process_inner + .memory_set + .translate(trap_cx_bottom_va.into()) + .unwrap() + .ppn() } - pub fn ustack_base(&self) -> usize { self.ustack_base } + pub fn ustack_base(&self) -> usize { + self.ustack_base + } pub fn ustack_top(&self) -> usize { - ustack_bottom_from_tid(self.ustack_base, self.tid) + USER_STACK_SIZE + ustack_bottom_from_tid(self.ustack_base, self.tid) + USER_STACK_SIZE } } @@ -212,4 +221,3 @@ impl Drop for TaskUserRes { self.dealloc_user_res(); } } - diff --git a/os/src/task/manager.rs b/os/src/task/manager.rs index 82c2d1e4..5ed68ae7 100644 --- a/os/src/task/manager.rs +++ b/os/src/task/manager.rs @@ -1,6 +1,6 @@ +use super::{ProcessControlBlock, TaskControlBlock}; use crate::sync::UPSafeCell; -use super::TaskControlBlock; -use alloc::collections::VecDeque; +use alloc::collections::{BTreeMap, VecDeque}; use alloc::sync::Arc; use lazy_static::*; @@ -11,7 +11,9 @@ pub struct TaskManager { /// A simple FIFO scheduler. impl TaskManager { pub fn new() -> Self { - Self { ready_queue: VecDeque::new(), } + Self { + ready_queue: VecDeque::new(), + } } pub fn add(&mut self, task: Arc) { self.ready_queue.push_back(task); @@ -22,9 +24,10 @@ impl TaskManager { } lazy_static! { - pub static ref TASK_MANAGER: UPSafeCell = unsafe { - UPSafeCell::new(TaskManager::new()) - }; + pub static ref TASK_MANAGER: UPSafeCell = + unsafe { UPSafeCell::new(TaskManager::new()) }; + pub static ref PID2PCB: UPSafeCell>> = + unsafe { UPSafeCell::new(BTreeMap::new()) }; } pub fn add_task(task: Arc) { @@ -34,3 +37,19 @@ pub fn add_task(task: Arc) { pub fn fetch_task() -> Option> { TASK_MANAGER.exclusive_access().fetch() } + +pub fn pid2process(pid: usize) -> Option> { + let map = PID2PCB.exclusive_access(); + map.get(&pid).map(Arc::clone) +} + +pub fn insert_into_pid2process(pid: usize, process: Arc) { + PID2PCB.exclusive_access().insert(pid, process); +} + +pub fn remove_from_pid2process(pid: usize) { + let mut map = PID2PCB.exclusive_access(); + if map.remove(&pid).is_none() { + panic!("cannot find pid {} in pid2task!", pid); + } +} diff --git a/os/src/task/mod.rs b/os/src/task/mod.rs index c426d6f9..1bd7b2a7 100644 --- a/os/src/task/mod.rs +++ b/os/src/task/mod.rs @@ -1,38 +1,29 @@ mod context; -mod switch; -mod task; -mod manager; -mod processor; mod id; +mod manager; mod process; +mod processor; +mod signal; +mod switch; +#[allow(clippy::module_inception)] +mod task; use crate::fs::{open_file, OpenFlags}; -use switch::__switch; use alloc::sync::Arc; -use manager::fetch_task; use lazy_static::*; +use manager::fetch_task; use process::ProcessControlBlock; +use switch::__switch; pub use context::TaskContext; +pub use id::{kstack_alloc, pid_alloc, KernelStack, PidHandle}; +pub use manager::{add_task, pid2process, remove_from_pid2process}; pub use processor::{ - run_tasks, - current_task, - current_process, - current_user_token, - current_trap_cx_user_va, - current_trap_cx, - current_kstack_top, - take_current_task, - schedule, + current_kstack_top, current_process, current_task, current_trap_cx, current_trap_cx_user_va, + current_user_token, run_tasks, schedule, take_current_task, }; +pub use signal::SignalFlags; pub use task::{TaskControlBlock, TaskStatus}; -pub use manager::add_task; -pub use id::{ - PidHandle, - pid_alloc, - KernelStack, - kstack_alloc, -}; pub fn suspend_current_and_run_next() { // There must be an application running. @@ -76,6 +67,7 @@ pub fn exit_current_and_run_next(exit_code: i32) { // however, if this is the main thread of current process // the process should terminate at once if tid == 0 { + remove_from_pid2process(process.getpid()); let mut process_inner = process.inner_exclusive_access(); // mark this process as a zombie process process_inner.is_zombie = true; @@ -86,7 +78,7 @@ pub fn exit_current_and_run_next(exit_code: i32) { // move all child processes under init process let mut initproc_inner = INITPROC.inner_exclusive_access(); for child in process_inner.children.iter() { - child.inner_exclusive_access().parent = Some(Arc::downgrade(&INITPROC)); + child.inner_exclusive_access().parent = Some(Arc::downgrade(&INITPROC)); initproc_inner.children.push(child.clone()); } } @@ -103,6 +95,8 @@ pub fn exit_current_and_run_next(exit_code: i32) { process_inner.children.clear(); // deallocate other data in user space i.e. program code/data section process_inner.memory_set.recycle_data_pages(); + // drop file descriptors + process_inner.fd_table.clear(); } drop(process); // we do not have to save task context @@ -121,3 +115,15 @@ lazy_static! { pub fn add_initproc() { let _initproc = INITPROC.clone(); } + +pub fn check_signals_of_current() -> Option<(i32, &'static str)> { + let process = current_process(); + let process_inner = process.inner_exclusive_access(); + process_inner.signals.check_error() +} + +pub fn current_add_signal(signal: SignalFlags) { + let process = current_process(); + let mut process_inner = process.inner_exclusive_access(); + process_inner.signals |= signal; +} diff --git a/os/src/task/process.rs b/os/src/task/process.rs index af48f21a..ffff14fe 100644 --- a/os/src/task/process.rs +++ b/os/src/task/process.rs @@ -1,20 +1,17 @@ -use crate::mm::{ - MemorySet, - KERNEL_SPACE, - translated_refmut, -}; -use crate::trap::{TrapContext, trap_handler}; -use crate::sync::{UPSafeCell, Mutex, Semaphore}; -use core::cell::RefMut; use super::id::RecycleAllocator; +use super::manager::insert_into_pid2process; use super::TaskControlBlock; -use super::{PidHandle, pid_alloc}; -use super::add_task; -use alloc::sync::{Weak, Arc}; +use super::{add_task, SignalFlags}; +use super::{pid_alloc, PidHandle}; +use crate::fs::{File, Stdin, Stdout}; +use crate::mm::{translated_refmut, MemorySet, KERNEL_SPACE}; +use crate::sync::{Condvar, Mutex, Semaphore, UPSafeCell}; +use crate::trap::{trap_handler, TrapContext}; +use alloc::string::String; +use alloc::sync::{Arc, Weak}; use alloc::vec; use alloc::vec::Vec; -use alloc::string::String; -use crate::fs::{File, Stdin, Stdout}; +use core::cell::RefMut; pub struct ProcessControlBlock { // immutable @@ -30,10 +27,12 @@ pub struct ProcessControlBlockInner { pub children: Vec>, pub exit_code: i32, pub fd_table: Vec>>, + pub signals: SignalFlags, pub tasks: Vec>>, pub task_res_allocator: RecycleAllocator, pub mutex_list: Vec>>, pub semaphore_list: Vec>>, + pub condvar_list: Vec>>, } impl ProcessControlBlockInner { @@ -43,8 +42,7 @@ impl ProcessControlBlockInner { } pub fn alloc_fd(&mut self) -> usize { - if let Some(fd) = (0..self.fd_table.len()) - .find(|fd| self.fd_table[*fd].is_none()) { + if let Some(fd) = (0..self.fd_table.len()).find(|fd| self.fd_table[*fd].is_none()) { fd } else { self.fd_table.push(None); @@ -56,7 +54,7 @@ impl ProcessControlBlockInner { self.task_res_allocator.alloc() } - pub fn dealloc_tid(&mut self, tid: usize){ + pub fn dealloc_tid(&mut self, tid: usize) { self.task_res_allocator.dealloc(tid) } @@ -81,25 +79,29 @@ impl ProcessControlBlock { let pid_handle = pid_alloc(); let process = Arc::new(Self { pid: pid_handle, - inner: unsafe { UPSafeCell::new(ProcessControlBlockInner { - is_zombie: false, - memory_set, - parent: None, - 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)), - ], - tasks: Vec::new(), - task_res_allocator: RecycleAllocator::new(), - mutex_list: Vec::new(), - semaphore_list: Vec::new(), - })} + inner: unsafe { + UPSafeCell::new(ProcessControlBlockInner { + is_zombie: false, + memory_set, + parent: None, + 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)), + ], + signals: SignalFlags::empty(), + tasks: Vec::new(), + task_res_allocator: RecycleAllocator::new(), + mutex_list: Vec::new(), + semaphore_list: Vec::new(), + condvar_list: Vec::new(), + }) + }, }); // create a main thread, we should allocate ustack and trap_cx here let task = Arc::new(TaskControlBlock::new( @@ -124,6 +126,7 @@ impl ProcessControlBlock { let mut process_inner = process.inner_exclusive_access(); process_inner.tasks.push(Some(Arc::clone(&task))); drop(process_inner); + insert_into_pid2process(process.getpid(), Arc::clone(&process)); // add main thread to scheduler add_task(task); process @@ -152,7 +155,7 @@ impl ProcessControlBlock { .map(|arg| { translated_refmut( new_token, - (argv_base + arg * core::mem::size_of::()) as *mut usize + (argv_base + arg * core::mem::size_of::()) as *mut usize, ) }) .collect(); @@ -199,28 +202,38 @@ impl ProcessControlBlock { new_fd_table.push(None); } } - // create child process pcb + // create child process pcb let child = Arc::new(Self { pid, - inner: unsafe { UPSafeCell::new(ProcessControlBlockInner { - is_zombie: false, - memory_set, - parent: Some(Arc::downgrade(self)), - children: Vec::new(), - exit_code: 0, - fd_table: new_fd_table, - tasks: Vec::new(), - task_res_allocator: RecycleAllocator::new(), - mutex_list: Vec::new(), - semaphore_list: Vec::new(), - })} + inner: unsafe { + UPSafeCell::new(ProcessControlBlockInner { + is_zombie: false, + memory_set, + parent: Some(Arc::downgrade(self)), + children: Vec::new(), + exit_code: 0, + fd_table: new_fd_table, + signals: SignalFlags::empty(), + tasks: Vec::new(), + task_res_allocator: RecycleAllocator::new(), + mutex_list: Vec::new(), + semaphore_list: Vec::new(), + condvar_list: Vec::new(), + }) + }, }); // add child parent.children.push(Arc::clone(&child)); // create main thread of child process let task = Arc::new(TaskControlBlock::new( Arc::clone(&child), - parent.get_task(0).inner_exclusive_access().res.as_ref().unwrap().ustack_base(), + parent + .get_task(0) + .inner_exclusive_access() + .res + .as_ref() + .unwrap() + .ustack_base(), // here we do not allocate trap_cx or ustack again // but mention that we allocate a new kstack here false, @@ -234,6 +247,7 @@ impl ProcessControlBlock { let trap_cx = task_inner.get_trap_cx(); trap_cx.kernel_sp = task.kstack.get_top(); drop(task_inner); + insert_into_pid2process(child.getpid(), Arc::clone(&child)); // add this thread to scheduler add_task(task); child @@ -243,4 +257,3 @@ impl ProcessControlBlock { self.pid.0 } } - diff --git a/os/src/task/processor.rs b/os/src/task/processor.rs index cb83319a..3c1a22f6 100644 --- a/os/src/task/processor.rs +++ b/os/src/task/processor.rs @@ -1,10 +1,10 @@ -use super::{TaskContext, TaskControlBlock, ProcessControlBlock}; -use alloc::sync::Arc; -use lazy_static::*; -use super::{fetch_task, TaskStatus}; use super::__switch; -use crate::trap::TrapContext; +use super::{fetch_task, TaskStatus}; +use super::{ProcessControlBlock, TaskContext, TaskControlBlock}; use crate::sync::UPSafeCell; +use crate::trap::TrapContext; +use alloc::sync::Arc; +use lazy_static::*; pub struct Processor { current: Option>, @@ -25,14 +25,12 @@ impl Processor { self.current.take() } pub fn current(&self) -> Option> { - self.current.as_ref().map(|task| Arc::clone(task)) + self.current.as_ref().map(Arc::clone) } } lazy_static! { - pub static ref PROCESSOR: UPSafeCell = unsafe { - UPSafeCell::new(Processor::new()) - }; + pub static ref PROCESSOR: UPSafeCell = unsafe { UPSafeCell::new(Processor::new()) }; } pub fn run_tasks() { @@ -50,13 +48,10 @@ pub fn run_tasks() { // release processor manually drop(processor); unsafe { - __switch( - idle_task_cx_ptr, - next_task_cx_ptr, - ); + __switch(idle_task_cx_ptr, next_task_cx_ptr); } } else { - println!("no tasks available in run_tasks"); + println!("no tasks available in run_tasks"); } } } @@ -75,12 +70,14 @@ pub fn current_process() -> Arc { pub fn current_user_token() -> usize { let task = current_task().unwrap(); - let token = task.get_user_token(); - token + task.get_user_token() } pub fn current_trap_cx() -> &'static mut TrapContext { - current_task().unwrap().inner_exclusive_access().get_trap_cx() + current_task() + .unwrap() + .inner_exclusive_access() + .get_trap_cx() } pub fn current_trap_cx_user_va() -> usize { @@ -94,10 +91,7 @@ pub fn current_trap_cx_user_va() -> usize { } pub fn current_kstack_top() -> usize { - current_task() - .unwrap() - .kstack - .get_top() + current_task().unwrap().kstack.get_top() } pub fn schedule(switched_task_cx_ptr: *mut TaskContext) { @@ -105,9 +99,6 @@ pub fn schedule(switched_task_cx_ptr: *mut TaskContext) { let idle_task_cx_ptr = processor.get_idle_task_cx_ptr(); drop(processor); unsafe { - __switch( - switched_task_cx_ptr, - idle_task_cx_ptr, - ); + __switch(switched_task_cx_ptr, idle_task_cx_ptr); } } diff --git a/os/src/task/signal.rs b/os/src/task/signal.rs new file mode 100644 index 00000000..46f1ad9d --- /dev/null +++ b/os/src/task/signal.rs @@ -0,0 +1,29 @@ +use bitflags::*; + +bitflags! { + pub struct SignalFlags: u32 { + const SIGINT = 1 << 2; + const SIGILL = 1 << 4; + const SIGABRT = 1 << 6; + const SIGFPE = 1 << 8; + const SIGSEGV = 1 << 11; + } +} + +impl SignalFlags { + pub fn check_error(&self) -> Option<(i32, &'static str)> { + if self.contains(Self::SIGINT) { + Some((-2, "Killed, SIGINT=2")) + } else if self.contains(Self::SIGILL) { + Some((-4, "Illegal Instruction, SIGILL=4")) + } else if self.contains(Self::SIGABRT) { + Some((-6, "Aborted, SIGABRT=6")) + } else if self.contains(Self::SIGFPE) { + Some((-8, "Erroneous Arithmetic Operation, SIGFPE=8")) + } else if self.contains(Self::SIGSEGV) { + Some((-11, "Segmentation Fault, SIGSEGV=11")) + } else { + None + } + } +} diff --git a/os/src/task/switch.rs b/os/src/task/switch.rs index 59476813..59f8b1a0 100644 --- a/os/src/task/switch.rs +++ b/os/src/task/switch.rs @@ -1,12 +1,8 @@ +use super::TaskContext; use core::arch::global_asm; global_asm!(include_str!("switch.S")); -use super::TaskContext; - extern "C" { - pub fn __switch( - current_task_cx_ptr: *mut TaskContext, - next_task_cx_ptr: *const TaskContext - ); + pub fn __switch(current_task_cx_ptr: *mut TaskContext, next_task_cx_ptr: *const TaskContext); } diff --git a/os/src/task/task.rs b/os/src/task/task.rs index b7e10797..99900de3 100644 --- a/os/src/task/task.rs +++ b/os/src/task/task.rs @@ -1,8 +1,8 @@ -use alloc::sync::{Arc, Weak}; -use crate::{mm::PhysPageNum, sync::UPSafeCell}; -use crate::trap::TrapContext; use super::id::TaskUserRes; -use super::{KernelStack, ProcessControlBlock, TaskContext, kstack_alloc}; +use super::{kstack_alloc, KernelStack, ProcessControlBlock, TaskContext}; +use crate::trap::TrapContext; +use crate::{mm::PhysPageNum, sync::UPSafeCell}; +use alloc::sync::{Arc, Weak}; use core::cell::RefMut; pub struct TaskControlBlock { @@ -37,7 +37,7 @@ impl TaskControlBlockInner { pub fn get_trap_cx(&self) -> &'static mut TrapContext { self.trap_cx_ppn.get_mut() } - + #[allow(unused)] fn get_status(&self) -> TaskStatus { self.task_status @@ -48,7 +48,7 @@ impl TaskControlBlock { pub fn new( process: Arc, ustack_base: usize, - alloc_user_res: bool + alloc_user_res: bool, ) -> Self { let res = TaskUserRes::new(Arc::clone(&process), ustack_base, alloc_user_res); let trap_cx_ppn = res.trap_cx_ppn(); @@ -57,15 +57,15 @@ impl TaskControlBlock { Self { process: Arc::downgrade(&process), kstack, - inner: unsafe { UPSafeCell::new( - TaskControlBlockInner { + inner: unsafe { + UPSafeCell::new(TaskControlBlockInner { res: Some(res), trap_cx_ppn, task_cx: TaskContext::goto_trap_return(kstack_top), task_status: TaskStatus::Ready, exit_code: None, - } - )}, + }) + }, } } } diff --git a/os/src/timer.rs b/os/src/timer.rs index 70c5d72b..3baed0f7 100644 --- a/os/src/timer.rs +++ b/os/src/timer.rs @@ -1,13 +1,13 @@ use core::cmp::Ordering; -use riscv::register::time; -use crate::sbi::set_timer; use crate::config::CLOCK_FREQ; -use crate::task::{TaskControlBlock, add_task}; +use crate::sbi::set_timer; use crate::sync::UPSafeCell; +use crate::task::{add_task, TaskControlBlock}; use alloc::collections::BinaryHeap; use alloc::sync::Arc; use lazy_static::*; +use riscv::register::time; const TICKS_PER_SEC: usize = 100; const MSEC_PER_SEC: usize = 1000; @@ -39,28 +39,24 @@ impl PartialOrd for TimerCondVar { fn partial_cmp(&self, other: &Self) -> Option { let a = -(self.expire_ms as isize); let b = -(other.expire_ms as isize); - Some(a.cmp(&b)) + Some(a.cmp(&b)) } } impl Ord for TimerCondVar { fn cmp(&self, other: &Self) -> Ordering { - self.partial_cmp(other).unwrap() + self.partial_cmp(other).unwrap() } } lazy_static! { - static ref TIMERS: UPSafeCell> = unsafe { UPSafeCell::new( - BinaryHeap::::new() - )}; + static ref TIMERS: UPSafeCell> = + unsafe { UPSafeCell::new(BinaryHeap::::new()) }; } pub fn add_timer(expire_ms: usize, task: Arc) { let mut timers = TIMERS.exclusive_access(); - timers.push(TimerCondVar { - expire_ms, - task, - }); + timers.push(TimerCondVar { expire_ms, task }); } pub fn check_timer() { @@ -68,9 +64,10 @@ pub fn check_timer() { let mut timers = TIMERS.exclusive_access(); while let Some(timer) = timers.peek() { if timer.expire_ms <= current_ms { - add_task(Arc::clone(&timer.task)); - drop(timer); + add_task(Arc::clone(&timer.task)); timers.pop(); - } else { break; } + } else { + break; + } } } diff --git a/os/src/trap/context.rs b/os/src/trap/context.rs index 16f81415..011b7fb7 100644 --- a/os/src/trap/context.rs +++ b/os/src/trap/context.rs @@ -1,4 +1,4 @@ -use riscv::register::sstatus::{Sstatus, self, SPP}; +use riscv::register::sstatus::{self, Sstatus, SPP}; #[repr(C)] #[derive(Debug)] @@ -12,7 +12,9 @@ pub struct TrapContext { } impl TrapContext { - pub fn set_sp(&mut self, sp: usize) { self.x[2] = sp; } + pub fn set_sp(&mut self, sp: usize) { + self.x[2] = sp; + } pub fn app_init_context( entry: usize, sp: usize, diff --git a/os/src/trap/mod.rs b/os/src/trap/mod.rs index 964c9042..6397811a 100644 --- a/os/src/trap/mod.rs +++ b/os/src/trap/mod.rs @@ -1,28 +1,18 @@ mod context; +use crate::config::TRAMPOLINE; +use crate::syscall::syscall; +use crate::task::{ + check_signals_of_current, current_add_signal, current_trap_cx, current_trap_cx_user_va, + current_user_token, exit_current_and_run_next, suspend_current_and_run_next, SignalFlags, +}; +use crate::timer::{check_timer, set_next_trigger}; use core::arch::{asm, global_asm}; use riscv::register::{ mtvec::TrapMode, - stvec, - scause::{ - self, - Trap, - Exception, - Interrupt, - }, - stval, - sie, -}; -use crate::syscall::syscall; -use crate::task::{ - exit_current_and_run_next, - suspend_current_and_run_next, - current_user_token, - current_trap_cx, - current_trap_cx_user_va, + scause::{self, Exception, Interrupt, Trap}, + sie, stval, stvec, }; -use crate::timer::{set_next_trigger, check_timer}; -use crate::config::TRAMPOLINE; global_asm!(include_str!("trap.S")); @@ -43,7 +33,9 @@ fn set_user_trap_entry() { } pub fn enable_timer_interrupt() { - unsafe { sie::set_stimer(); } + unsafe { + sie::set_stimer(); + } } #[no_mangle] @@ -62,25 +54,24 @@ pub fn trap_handler() -> ! { cx = current_trap_cx(); cx.x[10] = result as usize; } - Trap::Exception(Exception::StoreFault) | - Trap::Exception(Exception::StorePageFault) | - Trap::Exception(Exception::InstructionFault) | - Trap::Exception(Exception::InstructionPageFault) | - Trap::Exception(Exception::LoadFault) | - Trap::Exception(Exception::LoadPageFault) => { + Trap::Exception(Exception::StoreFault) + | Trap::Exception(Exception::StorePageFault) + | Trap::Exception(Exception::InstructionFault) + | Trap::Exception(Exception::InstructionPageFault) + | Trap::Exception(Exception::LoadFault) + | Trap::Exception(Exception::LoadPageFault) => { + /* println!( - "[kernel] {:?} in application, bad addr = {:#x}, bad instruction = {:#x}, core dumped.", + "[kernel] {:?} in application, bad addr = {:#x}, bad instruction = {:#x}, kernel killed it.", scause.cause(), stval, current_trap_cx().sepc, ); - // page fault exit code - exit_current_and_run_next(-2); + */ + current_add_signal(SignalFlags::SIGSEGV); } Trap::Exception(Exception::IllegalInstruction) => { - println!("[kernel] IllegalInstruction in application, core dumped."); - // illegal instruction exit code - exit_current_and_run_next(-3); + current_add_signal(SignalFlags::SIGILL); } Trap::Interrupt(Interrupt::SupervisorTimer) => { set_next_trigger(); @@ -88,10 +79,18 @@ pub fn trap_handler() -> ! { suspend_current_and_run_next(); } _ => { - panic!("Unsupported trap {:?}, stval = {:#x}!", scause.cause(), stval); + panic!( + "Unsupported trap {:?}, stval = {:#x}!", + scause.cause(), + stval + ); } } - //println!("before trap_return"); + // check signals + if let Some((errno, msg)) = check_signals_of_current() { + println!("[kernel] {}", msg); + exit_current_and_run_next(errno); + } trap_return(); } diff --git a/user/Cargo.toml b/user/Cargo.toml index d50a0ba0..f522c9e9 100644 --- a/user/Cargo.toml +++ b/user/Cargo.toml @@ -8,4 +8,5 @@ edition = "2018" [dependencies] buddy_system_allocator = "0.6" -bitflags = "1.2.1" \ No newline at end of file +bitflags = "1.2.1" +riscv = { git = "https://github.com/rcore-os/riscv", features = ["inline-asm"] } diff --git a/user/src/bin/cat.rs b/user/src/bin/cat.rs index 988164d3..9cbed233 100644 --- a/user/src/bin/cat.rs +++ b/user/src/bin/cat.rs @@ -5,13 +5,7 @@ extern crate user_lib; extern crate alloc; -use user_lib::{ - open, - OpenFlags, - close, - read, -}; -use alloc::string::String; +use user_lib::{close, open, read, OpenFlags}; #[no_mangle] pub fn main(argc: usize, argv: &[&str]) -> i32 { @@ -21,14 +15,14 @@ pub fn main(argc: usize, argv: &[&str]) -> i32 { panic!("Error occured when opening file"); } let fd = fd as usize; - let mut buf = [0u8; 16]; - let mut s = String::new(); + let mut buf = [0u8; 256]; loop { let size = read(fd, &mut buf) as usize; - if size == 0 { break; } - s.push_str(core::str::from_utf8(&buf[..size]).unwrap()); + if size == 0 { + break; + } + print!("{}", core::str::from_utf8(&buf[..size]).unwrap()); } - println!("{}", s); close(fd); 0 -} \ No newline at end of file +} diff --git a/user/src/bin/cmdline_args.rs b/user/src/bin/cmdline_args.rs index b49ec332..9a227456 100644 --- a/user/src/bin/cmdline_args.rs +++ b/user/src/bin/cmdline_args.rs @@ -9,8 +9,8 @@ extern crate user_lib; #[no_mangle] pub fn main(argc: usize, argv: &[&str]) -> i32 { println!("argc = {}", argc); - for i in 0..argc { - println!("argv[{}] = {}", i, argv[i]); + for (i, arg) in argv.iter().enumerate() { + println!("argv[{}] = {}", i, arg); } 0 -} \ No newline at end of file +} diff --git a/user/src/bin/count_lines.rs b/user/src/bin/count_lines.rs new file mode 100644 index 00000000..276e12ed --- /dev/null +++ b/user/src/bin/count_lines.rs @@ -0,0 +1,30 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::read; + +#[no_mangle] +pub fn main(_argc: usize, _argv: &[&str]) -> i32 { + let mut buf = [0u8; 256]; + let mut lines = 0usize; + let mut total_size = 0usize; + loop { + let len = read(0, &mut buf) as usize; + if len == 0 { + break; + } + total_size += len; + let string = core::str::from_utf8(&buf[..len]).unwrap(); + lines += string + .chars() + .fold(0, |acc, c| acc + if c == '\n' { 1 } else { 0 }); + } + if total_size > 0 { + lines += 1; + } + println!("{}", lines); + 0 +} diff --git a/user/src/bin/exit.rs b/user/src/bin/exit.rs index 5bde550b..60510c90 100644 --- a/user/src/bin/exit.rs +++ b/user/src/bin/exit.rs @@ -3,7 +3,7 @@ #[macro_use] extern crate user_lib; -use user_lib::{fork, yield_, waitpid, exit, wait}; +use user_lib::{exit, fork, wait, waitpid, yield_}; const MAGIC: i32 = -0x10384; @@ -13,7 +13,9 @@ pub fn main() -> i32 { let pid = fork(); if pid == 0 { println!("I am the child."); - for _ in 0..7 { yield_(); } + for _ in 0..7 { + yield_(); + } exit(MAGIC); } else { println!("I am parent, fork a child pid {}", pid); @@ -26,4 +28,3 @@ pub fn main() -> i32 { println!("exit pass."); 0 } - diff --git a/user/src/bin/fantastic_text.rs b/user/src/bin/fantastic_text.rs index bb51db30..a3402ff6 100644 --- a/user/src/bin/fantastic_text.rs +++ b/user/src/bin/fantastic_text.rs @@ -41,4 +41,4 @@ pub fn main() -> i32 { println!("{}", color_text!(text, i)); } 0 -} \ No newline at end of file +} diff --git a/user/src/bin/filetest_simple.rs b/user/src/bin/filetest_simple.rs index 60fda6aa..3406d551 100644 --- a/user/src/bin/filetest_simple.rs +++ b/user/src/bin/filetest_simple.rs @@ -4,13 +4,7 @@ #[macro_use] extern crate user_lib; -use user_lib::{ - open, - close, - read, - write, - OpenFlags, -}; +use user_lib::{close, open, read, write, OpenFlags}; #[no_mangle] pub fn main() -> i32 { @@ -29,10 +23,7 @@ pub fn main() -> i32 { let read_len = read(fd, &mut buffer) as usize; close(fd); - assert_eq!( - test_str, - core::str::from_utf8(&buffer[..read_len]).unwrap(), - ); + assert_eq!(test_str, core::str::from_utf8(&buffer[..read_len]).unwrap(),); println!("file_test passed!"); 0 -} \ No newline at end of file +} diff --git a/user/src/bin/forktest.rs b/user/src/bin/forktest.rs index fea6967c..5374a56c 100644 --- a/user/src/bin/forktest.rs +++ b/user/src/bin/forktest.rs @@ -4,9 +4,9 @@ #[macro_use] extern crate user_lib; -use user_lib::{fork, wait, exit}; +use user_lib::{exit, fork, wait}; -const MAX_CHILD: usize = 40; +const MAX_CHILD: usize = 30; #[no_mangle] pub fn main() -> i32 { @@ -31,4 +31,4 @@ pub fn main() -> i32 { } println!("forktest pass."); 0 -} \ No newline at end of file +} diff --git a/user/src/bin/forktest2.rs b/user/src/bin/forktest2.rs index d08a4120..c91ce152 100644 --- a/user/src/bin/forktest2.rs +++ b/user/src/bin/forktest2.rs @@ -4,7 +4,7 @@ #[macro_use] extern crate user_lib; -use user_lib::{fork, wait, getpid, exit, sleep, get_time}; +use user_lib::{exit, fork, get_time, getpid, sleep, wait}; static NUM: usize = 30; @@ -14,7 +14,8 @@ pub fn main() -> i32 { let pid = fork(); if pid == 0 { let current_time = get_time(); - let sleep_length = (current_time as i32 as isize) * (current_time as i32 as isize) % 1000 + 1000; + let sleep_length = + (current_time as i32 as isize) * (current_time as i32 as isize) % 1000 + 1000; println!("pid {} sleep for {} ms", getpid(), sleep_length); sleep(sleep_length as usize); println!("pid {} OK!", getpid()); @@ -30,4 +31,4 @@ pub fn main() -> i32 { assert!(wait(&mut exit_code) < 0); println!("forktest2 test passed!"); 0 -} \ No newline at end of file +} diff --git a/user/src/bin/forktest_simple.rs b/user/src/bin/forktest_simple.rs index 821fba64..29a624b4 100644 --- a/user/src/bin/forktest_simple.rs +++ b/user/src/bin/forktest_simple.rs @@ -25,4 +25,4 @@ pub fn main() -> i32 { println!("child process pid = {}, exit code = {}", pid, exit_code); 0 } -} \ No newline at end of file +} diff --git a/user/src/bin/forktree.rs b/user/src/bin/forktree.rs index 2debf6c5..bfcfc4ca 100644 --- a/user/src/bin/forktree.rs +++ b/user/src/bin/forktree.rs @@ -4,7 +4,7 @@ #[macro_use] extern crate user_lib; -use user_lib::{sleep, getpid, fork, exit, yield_}; +use user_lib::{exit, fork, getpid, sleep, yield_}; const DEPTH: usize = 4; diff --git a/user/src/bin/hello_world.rs b/user/src/bin/hello_world.rs index de4a6a92..10d3f26c 100644 --- a/user/src/bin/hello_world.rs +++ b/user/src/bin/hello_world.rs @@ -8,4 +8,4 @@ extern crate user_lib; pub fn main() -> i32 { println!("Hello world from user mode program!"); 0 -} \ No newline at end of file +} diff --git a/user/src/bin/huge_write.rs b/user/src/bin/huge_write.rs index f9dafa17..e93f8b8e 100644 --- a/user/src/bin/huge_write.rs +++ b/user/src/bin/huge_write.rs @@ -4,33 +4,30 @@ #[macro_use] extern crate user_lib; -use user_lib::{ - OpenFlags, - open, - close, - write, - get_time, -}; +use user_lib::{close, get_time, open, write, OpenFlags}; #[no_mangle] pub fn main() -> i32 { let mut buffer = [0u8; 1024]; // 1KiB - for i in 0..buffer.len() { - buffer[i] = i as u8; + for (i, ch) in buffer.iter_mut().enumerate() { + *ch = i as u8; } - let f = open("testf", OpenFlags::CREATE | OpenFlags::WRONLY); + let f = open("testf\0", OpenFlags::CREATE | OpenFlags::WRONLY); if f < 0 { panic!("Open test file failed!"); } let f = f as usize; let start = get_time(); let size_mb = 1usize; - for _ in 0..1024*size_mb { + for _ in 0..1024 * size_mb { write(f, &buffer); } close(f); let time_ms = (get_time() - start) as usize; let speed_kbs = size_mb * 1000000 / time_ms; - println!("{}MiB written, time cost = {}ms, write speed = {}KiB/s", size_mb, time_ms, speed_kbs); + println!( + "{}MiB written, time cost = {}ms, write speed = {}KiB/s", + size_mb, time_ms, speed_kbs + ); 0 -} \ No newline at end of file +} diff --git a/user/src/bin/infloop.rs b/user/src/bin/infloop.rs new file mode 100644 index 00000000..1f248534 --- /dev/null +++ b/user/src/bin/infloop.rs @@ -0,0 +1,10 @@ +#![no_std] +#![no_main] +#![allow(clippy::empty_loop)] + +extern crate user_lib; + +#[no_mangle] +pub fn main(_argc: usize, _argv: &[&str]) -> ! { + loop {} +} diff --git a/user/src/bin/initproc.rs b/user/src/bin/initproc.rs index cf8840f7..d25aee14 100644 --- a/user/src/bin/initproc.rs +++ b/user/src/bin/initproc.rs @@ -1,20 +1,14 @@ #![no_std] #![no_main] -#[macro_use] extern crate user_lib; -use user_lib::{ - fork, - wait, - exec, - yield_, -}; +use user_lib::{exec, fork, wait, yield_}; #[no_mangle] fn main() -> i32 { if fork() == 0 { - exec("user_shell\0", &[0 as *const u8]); + exec("user_shell\0", &[core::ptr::null::()]); } else { loop { let mut exit_code: i32 = 0; @@ -23,11 +17,13 @@ fn main() -> i32 { yield_(); continue; } + /* println!( "[initproc] Released a zombie process, pid={}, exit_code={}", pid, exit_code, ); + */ } } 0 diff --git a/user/src/bin/matrix.rs b/user/src/bin/matrix.rs index 8ef2c044..9ebf48f4 100644 --- a/user/src/bin/matrix.rs +++ b/user/src/bin/matrix.rs @@ -1,12 +1,13 @@ #![no_std] #![no_main] +#![allow(clippy::needless_range_loop)] #[macro_use] extern crate user_lib; -use user_lib::{fork, wait, yield_, exit, getpid, get_time}; +use user_lib::{exit, fork, get_time, getpid, wait, yield_}; -static NUM: usize = 35; +static NUM: usize = 30; const N: usize = 10; static P: i32 = 10007; type Arr = [[i32; N]; N]; @@ -65,4 +66,4 @@ pub fn main() -> i32 { assert!(wait(&mut exit_code) < 0); println!("matrix passed."); 0 -} \ No newline at end of file +} diff --git a/user/src/bin/mpsc_sem.rs b/user/src/bin/mpsc_sem.rs index 71141e41..7b92b9b4 100644 --- a/user/src/bin/mpsc_sem.rs +++ b/user/src/bin/mpsc_sem.rs @@ -1,15 +1,16 @@ #![no_std] #![no_main] +#![allow(clippy::println_empty_string)] #[macro_use] extern crate user_lib; extern crate alloc; -use user_lib::{semaphore_create, semaphore_up, semaphore_down}; -use user_lib::{thread_create, waittid}; -use user_lib::exit; use alloc::vec::Vec; +use user_lib::exit; +use user_lib::{semaphore_create, semaphore_down, semaphore_up}; +use user_lib::{thread_create, waittid}; const SEM_MUTEX: usize = 0; const SEM_EMPTY: usize = 1; @@ -57,7 +58,10 @@ pub fn main() -> i32 { let ids: Vec<_> = (0..PRODUCER_COUNT).collect(); let mut threads = Vec::new(); for i in 0..PRODUCER_COUNT { - threads.push(thread_create(producer as usize, &ids.as_slice()[i] as *const _ as usize)); + threads.push(thread_create( + producer as usize, + &ids.as_slice()[i] as *const _ as usize, + )); } threads.push(thread_create(consumer as usize, 0)); // wait for all threads to complete diff --git a/user/src/bin/phil_din_mutex.rs b/user/src/bin/phil_din_mutex.rs index 97a4a8c1..8e7b5667 100644 --- a/user/src/bin/phil_din_mutex.rs +++ b/user/src/bin/phil_din_mutex.rs @@ -1,14 +1,15 @@ #![no_std] #![no_main] +#![allow(clippy::println_empty_string)] #[macro_use] extern crate user_lib; extern crate alloc; +use alloc::vec::Vec; +use user_lib::{exit, get_time, sleep}; use user_lib::{mutex_blocking_create, mutex_lock, mutex_unlock}; use user_lib::{thread_create, waittid}; -use user_lib::{sleep, exit, get_time}; -use alloc::vec::Vec; const N: usize = 5; const ROUND: usize = 4; @@ -38,16 +39,24 @@ fn philosopher_dining_problem(id: *const usize) { let max = left + right - min; for round in 0..ROUND { // thinking - unsafe { THINK[id][2 * round] = get_time_u(); } + unsafe { + THINK[id][2 * round] = get_time_u(); + } sleep(ARR[id][2 * round]); - unsafe { THINK[id][2 * round + 1] = get_time_u(); } + unsafe { + THINK[id][2 * round + 1] = get_time_u(); + } // wait for forks mutex_lock(min); mutex_lock(max); // eating - unsafe { EAT[id][2 * round] = get_time_u(); } + unsafe { + EAT[id][2 * round] = get_time_u(); + } sleep(ARR[id][2 * round + 1]); - unsafe { EAT[id][2 * round + 1] = get_time_u(); } + unsafe { + EAT[id][2 * round + 1] = get_time_u(); + } mutex_unlock(max); mutex_unlock(min); } @@ -61,7 +70,10 @@ pub fn main() -> i32 { let start = get_time_u(); for i in 0..N { assert_eq!(mutex_blocking_create(), i as isize); - v.push(thread_create(philosopher_dining_problem as usize, &ids.as_slice()[i] as *const _ as usize)); + v.push(thread_create( + philosopher_dining_problem as usize, + &ids.as_slice()[i] as *const _ as usize, + )); } for tid in v.iter() { waittid(*tid as usize); @@ -70,20 +82,20 @@ pub fn main() -> i32 { println!("time cost = {}", time_cost); println!("'-' -> THINKING; 'x' -> EATING; ' ' -> WAITING "); for id in (0..N).into_iter().chain(0..=0) { - print!("#{}:", id); - for j in 0..time_cost/GRAPH_SCALE { + print!("#{}:", id); + for j in 0..time_cost / GRAPH_SCALE { let current_time = j * GRAPH_SCALE + start; - if (0..ROUND).find(|round| unsafe { + if (0..ROUND).any(|round| unsafe { let start_thinking = THINK[id][2 * round]; let end_thinking = THINK[id][2 * round + 1]; start_thinking <= current_time && current_time <= end_thinking - }).is_some() { + }) { print!("-"); - } else if (0..ROUND).find(|round| unsafe { + } else if (0..ROUND).any(|round| unsafe { let start_eating = EAT[id][2 * round]; let end_eating = EAT[id][2 * round + 1]; start_eating <= current_time && current_time <= end_eating - }).is_some() { + }) { print!("x"); } else { print!(" "); diff --git a/user/src/bin/pipe_large_test.rs b/user/src/bin/pipe_large_test.rs index 121987be..e85d0a6f 100644 --- a/user/src/bin/pipe_large_test.rs +++ b/user/src/bin/pipe_large_test.rs @@ -6,8 +6,8 @@ extern crate user_lib; extern crate alloc; -use user_lib::{fork, close, pipe, read, write, wait, get_time}; use alloc::format; +use user_lib::{close, fork, get_time, pipe, read, wait, write}; const LENGTH: usize = 3000; #[no_mangle] @@ -40,11 +40,14 @@ pub fn main() -> i32 { // 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; + for ch in random_str.iter_mut() { + *ch = get_time() as u8; } // send it - assert_eq!(write(down_pipe_fd[1], &random_str) as usize, random_str.len()); + 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) @@ -57,13 +60,12 @@ pub fn main() -> i32 { // check assert_eq!( sum, - str::parse::( - core::str::from_utf8(&child_result[..result_len]).unwrap() - ).unwrap() + 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 index c151fbdd..5436c63f 100644 --- a/user/src/bin/pipetest.rs +++ b/user/src/bin/pipetest.rs @@ -4,7 +4,7 @@ #[macro_use] extern crate user_lib; -use user_lib::{fork, close, pipe, read, write, wait}; +use user_lib::{close, fork, pipe, read, wait, write}; static STR: &str = "Hello, world!"; @@ -41,4 +41,4 @@ pub fn main() -> i32 { println!("pipetest passed!"); 0 } -} \ No newline at end of file +} diff --git a/user/src/bin/priv_csr.rs b/user/src/bin/priv_csr.rs new file mode 100644 index 00000000..fbd678f7 --- /dev/null +++ b/user/src/bin/priv_csr.rs @@ -0,0 +1,17 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use riscv::register::sstatus::{self, SPP}; + +#[no_mangle] +fn main() -> i32 { + println!("Try to access privileged CSR in U Mode"); + println!("Kernel should kill this application!"); + unsafe { + sstatus::set_spp(SPP::User); + } + 0 +} diff --git a/user/src/bin/priv_inst.rs b/user/src/bin/priv_inst.rs new file mode 100644 index 00000000..04dac37e --- /dev/null +++ b/user/src/bin/priv_inst.rs @@ -0,0 +1,17 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use core::arch::asm; + +#[no_mangle] +fn main() -> i32 { + println!("Try to execute privileged instruction in U Mode"); + println!("Kernel should kill this application!"); + unsafe { + asm!("sret"); + } + 0 +} diff --git a/user/src/bin/race_adder.rs b/user/src/bin/race_adder.rs index bae009ec..c7b6747e 100644 --- a/user/src/bin/race_adder.rs +++ b/user/src/bin/race_adder.rs @@ -5,8 +5,8 @@ extern crate user_lib; extern crate alloc; -use user_lib::{exit, thread_create, waittid, get_time}; use alloc::vec::Vec; +use user_lib::{exit, get_time, thread_create, waittid}; static mut A: usize = 0; const PER_THREAD: usize = 1000; @@ -17,7 +17,9 @@ unsafe fn f() -> ! { for _ in 0..PER_THREAD { let a = &mut A as *mut usize; let cur = a.read_volatile(); - for _ in 0..500 { t = t * t % 10007; } + for _ in 0..500 { + t = t * t % 10007; + } a.write_volatile(cur + 1); } exit(t as i32) @@ -26,7 +28,7 @@ unsafe fn f() -> ! { #[no_mangle] pub fn main() -> i32 { let start = get_time(); - let mut v = Vec::new(); + let mut v = Vec::new(); for _ in 0..THREAD_COUNT { v.push(thread_create(f as usize, 0) as usize); } diff --git a/user/src/bin/race_adder_arg.rs b/user/src/bin/race_adder_arg.rs new file mode 100644 index 00000000..7c8b7074 --- /dev/null +++ b/user/src/bin/race_adder_arg.rs @@ -0,0 +1,53 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; +extern crate alloc; + +use crate::alloc::string::ToString; +use alloc::vec::Vec; +use user_lib::{exit, get_time, thread_create, waittid}; + +static mut A: usize = 0; +const PER_THREAD: usize = 1000; +const THREAD_COUNT: usize = 16; + +unsafe fn f(count: usize) -> ! { + let mut t = 2usize; + for _ in 0..PER_THREAD { + let a = &mut A as *mut usize; + let cur = a.read_volatile(); + for _ in 0..count { + t = t * t % 10007; + } + a.write_volatile(cur + 1); + } + exit(t as i32) +} + +#[no_mangle] +pub fn main(argc: usize, argv: &[&str]) -> i32 { + let count: usize; + if argc == 1 { + count = THREAD_COUNT; + } else if argc == 2 { + count = argv[1].to_string().parse::().unwrap(); + } else { + println!("ERROR in argv"); + exit(-1); + } + + let start = get_time(); + let mut v = Vec::new(); + for _ in 0..THREAD_COUNT { + v.push(thread_create(f as usize, count) as usize); + } + let mut time_cost = Vec::new(); + for tid in v.iter() { + time_cost.push(waittid(*tid)); + } + println!("time cost is {}ms", get_time() - start); + assert_eq!(unsafe { A }, PER_THREAD * THREAD_COUNT); + 0 +} diff --git a/user/src/bin/race_adder_atomic.rs b/user/src/bin/race_adder_atomic.rs index dfbe490e..2feaed0d 100644 --- a/user/src/bin/race_adder_atomic.rs +++ b/user/src/bin/race_adder_atomic.rs @@ -5,9 +5,9 @@ extern crate user_lib; extern crate alloc; -use user_lib::{exit, thread_create, waittid, get_time, yield_}; use alloc::vec::Vec; use core::sync::atomic::{AtomicBool, Ordering}; +use user_lib::{exit, get_time, thread_create, waittid, yield_}; static mut A: usize = 0; static OCCUPIED: AtomicBool = AtomicBool::new(false); @@ -17,12 +17,17 @@ const THREAD_COUNT: usize = 16; unsafe fn f() -> ! { let mut t = 2usize; for _ in 0..PER_THREAD { - while OCCUPIED.compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed).is_err() { + while OCCUPIED + .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed) + .is_err() + { yield_(); } let a = &mut A as *mut usize; let cur = a.read_volatile(); - for _ in 0..500 { t = t * t % 10007; } + for _ in 0..500 { + t = t * t % 10007; + } a.write_volatile(cur + 1); OCCUPIED.store(false, Ordering::Relaxed); } @@ -32,7 +37,7 @@ unsafe fn f() -> ! { #[no_mangle] pub fn main() -> i32 { let start = get_time(); - let mut v = Vec::new(); + let mut v = Vec::new(); for _ in 0..THREAD_COUNT { v.push(thread_create(f as usize, 0) as usize); } diff --git a/user/src/bin/race_adder_loop.rs b/user/src/bin/race_adder_loop.rs index 035772e2..0e4fe838 100644 --- a/user/src/bin/race_adder_loop.rs +++ b/user/src/bin/race_adder_loop.rs @@ -5,8 +5,8 @@ extern crate user_lib; extern crate alloc; -use user_lib::{exit, thread_create, waittid, get_time, yield_}; use alloc::vec::Vec; +use user_lib::{exit, get_time, thread_create, waittid, yield_}; static mut A: usize = 0; static mut OCCUPIED: bool = false; @@ -16,12 +16,16 @@ const THREAD_COUNT: usize = 16; unsafe fn f() -> ! { let mut t = 2usize; for _ in 0..PER_THREAD { - while OCCUPIED { yield_(); } + while OCCUPIED { + yield_(); + } OCCUPIED = true; // enter critical section let a = &mut A as *mut usize; let cur = a.read_volatile(); - for _ in 0..500 { t = t * t % 10007; } + for _ in 0..500 { + t = t * t % 10007; + } a.write_volatile(cur + 1); // exit critical section OCCUPIED = false; @@ -33,7 +37,7 @@ unsafe fn f() -> ! { #[no_mangle] pub fn main() -> i32 { let start = get_time(); - let mut v = Vec::new(); + let mut v = Vec::new(); for _ in 0..THREAD_COUNT { v.push(thread_create(f as usize, 0) as usize); } diff --git a/user/src/bin/race_adder_mutex_blocking.rs b/user/src/bin/race_adder_mutex_blocking.rs index 0424eba4..e5affc42 100644 --- a/user/src/bin/race_adder_mutex_blocking.rs +++ b/user/src/bin/race_adder_mutex_blocking.rs @@ -5,9 +5,9 @@ extern crate user_lib; extern crate alloc; -use user_lib::{exit, thread_create, waittid, get_time}; -use user_lib::{mutex_blocking_create, mutex_lock, mutex_unlock}; use alloc::vec::Vec; +use user_lib::{exit, get_time, thread_create, waittid}; +use user_lib::{mutex_blocking_create, mutex_lock, mutex_unlock}; static mut A: usize = 0; const PER_THREAD: usize = 1000; @@ -19,7 +19,9 @@ unsafe fn f() -> ! { mutex_lock(0); let a = &mut A as *mut usize; let cur = a.read_volatile(); - for _ in 0..500 { t = t * t % 10007; } + for _ in 0..500 { + t = t * t % 10007; + } a.write_volatile(cur + 1); mutex_unlock(0); } @@ -30,7 +32,7 @@ unsafe fn f() -> ! { pub fn main() -> i32 { let start = get_time(); assert_eq!(mutex_blocking_create(), 0); - let mut v = Vec::new(); + let mut v = Vec::new(); for _ in 0..THREAD_COUNT { v.push(thread_create(f as usize, 0) as usize); } diff --git a/user/src/bin/race_adder_mutex_spin.rs b/user/src/bin/race_adder_mutex_spin.rs index fb168666..ed3bcec9 100644 --- a/user/src/bin/race_adder_mutex_spin.rs +++ b/user/src/bin/race_adder_mutex_spin.rs @@ -5,9 +5,9 @@ extern crate user_lib; extern crate alloc; -use user_lib::{exit, thread_create, waittid, get_time}; -use user_lib::{mutex_create, mutex_lock, mutex_unlock}; use alloc::vec::Vec; +use user_lib::{exit, get_time, thread_create, waittid}; +use user_lib::{mutex_create, mutex_lock, mutex_unlock}; static mut A: usize = 0; const PER_THREAD: usize = 1000; @@ -19,7 +19,9 @@ unsafe fn f() -> ! { mutex_lock(0); let a = &mut A as *mut usize; let cur = a.read_volatile(); - for _ in 0..500 { t = t * t % 10007; } + for _ in 0..500 { + t = t * t % 10007; + } a.write_volatile(cur + 1); mutex_unlock(0); } @@ -30,7 +32,7 @@ unsafe fn f() -> ! { pub fn main() -> i32 { let start = get_time(); assert_eq!(mutex_create(), 0); - let mut v = Vec::new(); + let mut v = Vec::new(); for _ in 0..THREAD_COUNT { v.push(thread_create(f as usize, 0) as usize); } diff --git a/user/src/bin/run_pipe_test.rs b/user/src/bin/run_pipe_test.rs index 000b82d5..ea99b6a7 100644 --- a/user/src/bin/run_pipe_test.rs +++ b/user/src/bin/run_pipe_test.rs @@ -4,13 +4,13 @@ #[macro_use] extern crate user_lib; -use user_lib::{fork, exec, wait}; +use user_lib::{exec, fork, wait}; #[no_mangle] pub fn main() -> i32 { for i in 0..1000 { if fork() == 0 { - exec("pipe_large_test\0", &[0 as *const u8]); + exec("pipe_large_test\0", &[core::ptr::null::()]); } else { let mut _unused: i32 = 0; wait(&mut _unused); @@ -18,4 +18,4 @@ pub fn main() -> i32 { } } 0 -} \ No newline at end of file +} diff --git a/user/src/bin/sleep.rs b/user/src/bin/sleep.rs index bd1e2204..641a4f9d 100644 --- a/user/src/bin/sleep.rs +++ b/user/src/bin/sleep.rs @@ -4,10 +4,10 @@ #[macro_use] extern crate user_lib; -use user_lib::{sleep, exit, get_time, fork, waitpid}; +use user_lib::{exit, fork, get_time, sleep, waitpid}; fn sleepy() { - let time: usize = 1000; + let time: usize = 100; for i in 0..5 { sleep(time); println!("sleep {} x {} msecs.", i + 1, time); @@ -27,4 +27,4 @@ pub fn main() -> i32 { println!("use {} msecs.", get_time() - current_time); println!("sleep pass."); 0 -} \ No newline at end of file +} diff --git a/user/src/bin/sleep_simple.rs b/user/src/bin/sleep_simple.rs index 4c058f87..7015a3d4 100644 --- a/user/src/bin/sleep_simple.rs +++ b/user/src/bin/sleep_simple.rs @@ -13,7 +13,11 @@ pub fn main() -> i32 { println!("current time_msec = {}", start); sleep(100); let end = get_time(); - println!("time_msec = {} after sleeping 100 ticks, delta = {}ms!", end, end - start); + println!( + "time_msec = {} after sleeping 100 ticks, delta = {}ms!", + end, + end - start + ); println!("r_sleep passed!"); 0 -} \ No newline at end of file +} diff --git a/user/src/bin/stack_overflow.rs b/user/src/bin/stack_overflow.rs index e0ea471d..5d365f5d 100644 --- a/user/src/bin/stack_overflow.rs +++ b/user/src/bin/stack_overflow.rs @@ -5,7 +5,7 @@ extern crate user_lib; fn f(d: usize) { - println!("d = {}",d); + println!("d = {}", d); f(d + 1); } @@ -14,4 +14,4 @@ pub fn main() -> i32 { println!("It should trigger segmentation fault!"); f(0); 0 -} \ No newline at end of file +} diff --git a/user/src/bin/store_fault.rs b/user/src/bin/store_fault.rs new file mode 100644 index 00000000..f8023eb7 --- /dev/null +++ b/user/src/bin/store_fault.rs @@ -0,0 +1,15 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +#[no_mangle] +fn main() -> i32 { + println!("Into Test store_fault, we will insert an invalid store operation..."); + println!("Kernel should kill this application!"); + unsafe { + core::ptr::null_mut::().write_volatile(0); + } + 0 +} diff --git a/user/src/bin/sync_sem.rs b/user/src/bin/sync_sem.rs new file mode 100644 index 00000000..b8d1f79c --- /dev/null +++ b/user/src/bin/sync_sem.rs @@ -0,0 +1,45 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +extern crate alloc; + +use alloc::vec; +use user_lib::exit; +use user_lib::{semaphore_create, semaphore_down, semaphore_up}; +use user_lib::{sleep, thread_create, waittid}; + +const SEM_SYNC: usize = 0; + +unsafe fn first() -> ! { + sleep(10); + println!("First work and wakeup Second"); + semaphore_up(SEM_SYNC); + exit(0) +} + +unsafe fn second() -> ! { + println!("Second want to continue,but need to wait first"); + semaphore_down(SEM_SYNC); + println!("Second can work now"); + exit(0) +} + +#[no_mangle] +pub fn main() -> i32 { + // create semaphores + assert_eq!(semaphore_create(0) as usize, SEM_SYNC); + // create threads + let threads = vec![ + thread_create(first as usize, 0), + thread_create(second as usize, 0), + ]; + // wait for all threads to complete + for thread in threads.iter() { + waittid(*thread as usize); + } + println!("sync_sem passed!"); + 0 +} diff --git a/user/src/bin/test_condvar.rs b/user/src/bin/test_condvar.rs new file mode 100644 index 00000000..2db9d8a4 --- /dev/null +++ b/user/src/bin/test_condvar.rs @@ -0,0 +1,59 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +extern crate alloc; + +use alloc::vec; +use user_lib::exit; +use user_lib::{ + condvar_create, condvar_signal, condvar_wait, mutex_blocking_create, mutex_lock, mutex_unlock, +}; +use user_lib::{sleep, thread_create, waittid}; + +static mut A: usize = 0; + +const CONDVAR_ID: usize = 0; +const MUTEX_ID: usize = 0; + +unsafe fn first() -> ! { + sleep(10); + println!("First work, Change A --> 1 and wakeup Second"); + mutex_lock(MUTEX_ID); + A = 1; + condvar_signal(CONDVAR_ID); + mutex_unlock(MUTEX_ID); + exit(0) +} + +unsafe fn second() -> ! { + println!("Second want to continue,but need to wait A=1"); + mutex_lock(MUTEX_ID); + while A == 0 { + println!("Second: A is {}", A); + condvar_wait(CONDVAR_ID, MUTEX_ID); + } + mutex_unlock(MUTEX_ID); + println!("A is {}, Second can work now", A); + exit(0) +} + +#[no_mangle] +pub fn main() -> i32 { + // create condvar & mutex + assert_eq!(condvar_create() as usize, CONDVAR_ID); + assert_eq!(mutex_blocking_create() as usize, MUTEX_ID); + // create threads + let threads = vec![ + thread_create(first as usize, 0), + thread_create(second as usize, 0), + ]; + // wait for all threads to complete + for thread in threads.iter() { + waittid(*thread as usize); + } + println!("test_condvar passed!"); + 0 +} diff --git a/user/src/bin/threads.rs b/user/src/bin/threads.rs index 97ce43f0..3d374fe4 100644 --- a/user/src/bin/threads.rs +++ b/user/src/bin/threads.rs @@ -5,30 +5,37 @@ extern crate user_lib; extern crate alloc; -use user_lib::{thread_create, waittid, exit}; -use alloc::vec::Vec; +use alloc::vec; +use user_lib::{exit, thread_create, waittid}; pub fn thread_a() -> ! { - for _ in 0..1000 { print!("a"); } + for _ in 0..1000 { + print!("a"); + } exit(1) } pub fn thread_b() -> ! { - for _ in 0..1000 { print!("b"); } - exit(2) + for _ in 0..1000 { + print!("b"); + } + exit(2) } pub fn thread_c() -> ! { - for _ in 0..1000 { print!("c"); } + for _ in 0..1000 { + print!("c"); + } exit(3) } #[no_mangle] pub fn main() -> i32 { - let mut v = Vec::new(); - v.push(thread_create(thread_a as usize, 0)); - v.push(thread_create(thread_b as usize, 0)); - v.push(thread_create(thread_c as usize, 0)); + let v = vec![ + thread_create(thread_a as usize, 0), + thread_create(thread_b as usize, 0), + thread_create(thread_c as usize, 0), + ]; for tid in v.iter() { let exit_code = waittid(*tid as usize); println!("thread#{} exited with code {}", tid, exit_code); diff --git a/user/src/bin/threads_arg.rs b/user/src/bin/threads_arg.rs index a29b23dd..c5b26ed2 100644 --- a/user/src/bin/threads_arg.rs +++ b/user/src/bin/threads_arg.rs @@ -5,8 +5,8 @@ extern crate user_lib; extern crate alloc; -use user_lib::{thread_create, waittid, exit}; use alloc::vec::Vec; +use user_lib::{exit, thread_create, waittid}; struct Argument { pub ch: char, @@ -15,7 +15,9 @@ struct Argument { fn thread_print(arg: *const Argument) -> ! { let arg = unsafe { &*arg }; - for _ in 0..1000 { print!("{}", arg.ch); } + for _ in 0..1000 { + print!("{}", arg.ch); + } exit(arg.rc) } @@ -23,12 +25,15 @@ fn thread_print(arg: *const Argument) -> ! { pub fn main() -> i32 { let mut v = Vec::new(); let args = [ - Argument { ch: 'a', rc: 1, }, - Argument { ch: 'b', rc: 2, }, - Argument { ch: 'c', rc: 3, }, - ]; - for i in 0..3 { - v.push(thread_create(thread_print as usize, &args[i] as *const _ as usize)); + Argument { ch: 'a', rc: 1 }, + Argument { ch: 'b', rc: 2 }, + Argument { ch: 'c', rc: 3 }, + ]; + for arg in args.iter() { + v.push(thread_create( + thread_print as usize, + arg as *const _ as usize, + )); } for tid in v.iter() { let exit_code = waittid(*tid as usize); diff --git a/user/src/bin/until_timeout.rs b/user/src/bin/until_timeout.rs new file mode 100644 index 00000000..a0007cb5 --- /dev/null +++ b/user/src/bin/until_timeout.rs @@ -0,0 +1,46 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::{exec, fork, get_time, kill, waitpid, waitpid_nb, SignalFlags}; + +#[no_mangle] +pub fn main(argc: usize, argv: &[&str]) -> i32 { + assert_eq!(argc, 3, "argc must be 3!"); + let timeout_ms = argv[2] + .parse::() + .expect("Error when parsing timeout!"); + let pid = fork() as usize; + if pid == 0 { + if exec(argv[1], &[core::ptr::null::()]) != 0 { + println!("Error when executing '{}'", argv[1]); + return -4; + } + } else { + let start_time = get_time(); + let mut child_exited = false; + let mut exit_code: i32 = 0; + loop { + if get_time() - start_time > timeout_ms { + break; + } + if waitpid_nb(pid, &mut exit_code) as usize == pid { + child_exited = true; + println!( + "child exited in {}ms, exit_code = {}", + get_time() - start_time, + exit_code, + ); + } + } + if !child_exited { + println!("child has run for {}ms, kill it!", timeout_ms); + kill(pid, SignalFlags::SIGINT.bits()); + assert_eq!(waitpid(pid, &mut exit_code) as usize, pid); + println!("exit code of the child is {}", exit_code); + } + } + 0 +} diff --git a/user/src/bin/user_shell.rs b/user/src/bin/user_shell.rs index b2c33f2d..42882488 100644 --- a/user/src/bin/user_shell.rs +++ b/user/src/bin/user_shell.rs @@ -1,5 +1,6 @@ #![no_std] #![no_main] +#![allow(clippy::println_empty_string)] extern crate alloc; @@ -10,116 +11,191 @@ const LF: u8 = 0x0au8; const CR: u8 = 0x0du8; const DL: u8 = 0x7fu8; const BS: u8 = 0x08u8; +const LINE_START: &str = ">> "; use alloc::string::String; use alloc::vec::Vec; -use user_lib::{ - fork, - exec, - waitpid, - open, - OpenFlags, - close, - dup, -}; use user_lib::console::getchar; +use user_lib::{close, dup, exec, fork, open, pipe, waitpid, OpenFlags}; + +#[derive(Debug)] +struct ProcessArguments { + input: String, + output: String, + args_copy: Vec, + args_addr: Vec<*const u8>, +} + +impl ProcessArguments { + pub fn new(command: &str) -> Self { + let args: Vec<_> = command.split(' ').collect(); + let mut args_copy: Vec = args + .iter() + .filter(|&arg| !arg.is_empty()) + .map(|&arg| { + let mut string = String::new(); + string.push_str(arg); + string.push('\0'); + string + }) + .collect(); + + // redirect input + let mut input = String::new(); + if let Some((idx, _)) = args_copy + .iter() + .enumerate() + .find(|(_, arg)| arg.as_str() == "<\0") + { + input = args_copy[idx + 1].clone(); + args_copy.drain(idx..=idx + 1); + } + + // redirect output + let mut output = String::new(); + if let Some((idx, _)) = args_copy + .iter() + .enumerate() + .find(|(_, arg)| arg.as_str() == ">\0") + { + output = args_copy[idx + 1].clone(); + args_copy.drain(idx..=idx + 1); + } + + let mut args_addr: Vec<*const u8> = args_copy.iter().map(|arg| arg.as_ptr()).collect(); + args_addr.push(core::ptr::null::()); + + Self { + input, + output, + args_copy, + args_addr, + } + } +} #[no_mangle] pub fn main() -> i32 { println!("Rust user shell"); let mut line: String = String::new(); - print!(">> "); + print!("{}", LINE_START); loop { let c = getchar(); match c { LF | CR => { println!(""); if !line.is_empty() { - let args: Vec<_> = line.as_str().split(' ').collect(); - let mut args_copy: Vec = args - .iter() - .map(|&arg| { - let mut string = String::new(); - string.push_str(arg); - string - }) - .collect(); - - args_copy - .iter_mut() - .for_each(|string| { - string.push('\0'); - }); - - // redirect input - let mut input = String::new(); - if let Some((idx, _)) = args_copy - .iter() - .enumerate() - .find(|(_, arg)| arg.as_str() == "<\0") { - input = args_copy[idx + 1].clone(); - args_copy.drain(idx..=idx + 1); - } - - // redirect output - let mut output = String::new(); - if let Some((idx, _)) = args_copy - .iter() - .enumerate() - .find(|(_, arg)| arg.as_str() == ">\0") { - output = args_copy[idx + 1].clone(); - args_copy.drain(idx..=idx + 1); - } - - let mut args_addr: Vec<*const u8> = args_copy + let splited: Vec<_> = line.as_str().split('|').collect(); + let process_arguments_list: Vec<_> = splited .iter() - .map(|arg| arg.as_ptr()) + .map(|&cmd| ProcessArguments::new(cmd)) .collect(); - args_addr.push(0 as *const u8); - let pid = fork(); - if pid == 0 { - // input redirection - if !input.is_empty() { - let input_fd = open(input.as_str(), OpenFlags::RDONLY); - if input_fd == -1 { - println!("Error when opening file {}", input); - return -4; + let mut valid = true; + for (i, process_args) in process_arguments_list.iter().enumerate() { + if i == 0 { + if !process_args.output.is_empty() { + valid = false; + } + } else if i == process_arguments_list.len() - 1 { + if !process_args.input.is_empty() { + valid = false; + } + } else if !process_args.output.is_empty() || !process_args.input.is_empty() + { + valid = false; + } + } + if process_arguments_list.len() == 1 { + valid = true; + } + if !valid { + println!("Invalid command: Inputs/Outputs cannot be correctly binded!"); + } else { + // create pipes + let mut pipes_fd: Vec<[usize; 2]> = Vec::new(); + if !process_arguments_list.is_empty() { + for _ in 0..process_arguments_list.len() - 1 { + let mut pipe_fd = [0usize; 2]; + pipe(&mut pipe_fd); + pipes_fd.push(pipe_fd); } - let input_fd = input_fd as usize; - close(0); - assert_eq!(dup(input_fd), 0); - close(input_fd); } - // output redirection - if !output.is_empty() { - let output_fd = open( - output.as_str(), - OpenFlags::CREATE | OpenFlags::WRONLY - ); - if output_fd == -1 { - println!("Error when opening file {}", output); - return -4; + let mut children: Vec<_> = Vec::new(); + for (i, process_argument) in process_arguments_list.iter().enumerate() { + let pid = fork(); + if pid == 0 { + let input = &process_argument.input; + let output = &process_argument.output; + let args_copy = &process_argument.args_copy; + let args_addr = &process_argument.args_addr; + // redirect input + if !input.is_empty() { + let input_fd = open(input.as_str(), OpenFlags::RDONLY); + if input_fd == -1 { + println!("Error when opening file {}", input); + return -4; + } + let input_fd = input_fd as usize; + close(0); + assert_eq!(dup(input_fd), 0); + close(input_fd); + } + // redirect output + if !output.is_empty() { + let output_fd = open( + output.as_str(), + OpenFlags::CREATE | OpenFlags::WRONLY, + ); + if output_fd == -1 { + println!("Error when opening file {}", output); + return -4; + } + let output_fd = output_fd as usize; + close(1); + assert_eq!(dup(output_fd), 1); + close(output_fd); + } + // receive input from the previous process + if i > 0 { + close(0); + let read_end = pipes_fd.get(i - 1).unwrap()[0]; + assert_eq!(dup(read_end), 0); + } + // send output to the next process + if i < process_arguments_list.len() - 1 { + close(1); + let write_end = pipes_fd.get(i).unwrap()[1]; + assert_eq!(dup(write_end), 1); + } + // close all pipe ends inherited from the parent process + for pipe_fd in pipes_fd.iter() { + close(pipe_fd[0]); + close(pipe_fd[1]); + } + // execute new application + if exec(args_copy[0].as_str(), args_addr.as_slice()) == -1 { + println!("Error when executing!"); + return -4; + } + unreachable!(); + } else { + children.push(pid); } - let output_fd = output_fd as usize; - close(1); - assert_eq!(dup(output_fd), 1); - close(output_fd); } - // child process - if exec(args_copy[0].as_str(), args_addr.as_slice()) == -1 { - println!("Error when executing!"); - return -4; + for pipe_fd in pipes_fd.iter() { + close(pipe_fd[0]); + close(pipe_fd[1]); } - unreachable!(); - } else { let mut exit_code: i32 = 0; - let exit_pid = waitpid(pid as usize, &mut exit_code); - assert_eq!(pid, exit_pid); - println!("Shell: Process {} exited with code {}", pid, exit_code); + for pid in children.into_iter() { + let exit_pid = waitpid(pid as usize, &mut exit_code); + assert_eq!(pid, exit_pid); + //println!("Shell: Process {} exited with code {}", pid, exit_code); + } } line.clear(); } - print!(">> "); + print!("{}", LINE_START); } BS | DL => { if !line.is_empty() { @@ -135,4 +211,4 @@ pub fn main() -> i32 { } } } -} \ No newline at end of file +} diff --git a/user/src/bin/usertests.rs b/user/src/bin/usertests.rs index e8be6c45..4fd49a4f 100644 --- a/user/src/bin/usertests.rs +++ b/user/src/bin/usertests.rs @@ -26,15 +26,18 @@ pub fn main() -> i32 { println!("Usertests: Running {}", test); let pid = fork(); if pid == 0 { - exec(*test, &[0 as *const u8]); + exec(*test, &[core::ptr::null::()]); panic!("unreachable!"); } else { let mut exit_code: i32 = Default::default(); let wait_pid = waitpid(pid as usize, &mut exit_code); assert_eq!(pid, wait_pid); - println!("\x1b[32mUsertests: Test {} in Process {} exited with code {}\x1b[0m", test, pid, exit_code); + println!( + "\x1b[32mUsertests: Test {} in Process {} exited with code {}\x1b[0m", + test, pid, exit_code + ); } } println!("Usertests passed!"); 0 -} \ No newline at end of file +} diff --git a/user/src/bin/yield.rs b/user/src/bin/yield.rs index 55032e40..78b1468c 100644 --- a/user/src/bin/yield.rs +++ b/user/src/bin/yield.rs @@ -14,4 +14,4 @@ pub fn main() -> i32 { } println!("yield pass."); 0 -} \ No newline at end of file +} diff --git a/user/src/lang_items.rs b/user/src/lang_items.rs index b5b98e08..df0467c3 100644 --- a/user/src/lang_items.rs +++ b/user/src/lang_items.rs @@ -1,12 +1,18 @@ -use super::exit; +use super::{getpid, kill, SignalFlags}; #[panic_handler] fn panic_handler(panic_info: &core::panic::PanicInfo) -> ! { let err = panic_info.message().unwrap(); if let Some(location) = panic_info.location() { - println!("Panicked at {}:{}, {}", location.file(), location.line(), err); + println!( + "Panicked at {}:{}, {}", + location.file(), + location.line(), + err + ); } else { println!("Panicked: {}", err); } - exit(-1); -} \ No newline at end of file + kill(getpid() as usize, SignalFlags::SIGABRT.bits()); + unreachable!() +} diff --git a/user/src/lib.rs b/user/src/lib.rs index afde2ecc..60f39ffb 100644 --- a/user/src/lib.rs +++ b/user/src/lib.rs @@ -1,21 +1,20 @@ #![no_std] -#![feature(asm)] #![feature(linkage)] #![feature(panic_info_message)] #![feature(alloc_error_handler)] #[macro_use] pub mod console; -mod syscall; mod lang_items; +mod syscall; extern crate alloc; #[macro_use] extern crate bitflags; -use syscall::*; -use buddy_system_allocator::LockedHeap; use alloc::vec::Vec; +use buddy_system_allocator::LockedHeap; +use syscall::*; const USER_HEAP_SIZE: usize = 32768; @@ -38,16 +37,16 @@ pub extern "C" fn _start(argc: usize, argv: usize) -> ! { } let mut v: Vec<&'static str> = Vec::new(); for i in 0..argc { - let str_start = unsafe { - ((argv + i * core::mem::size_of::()) as *const usize).read_volatile() - }; - let len = (0usize..).find(|i| unsafe { - ((str_start + *i) as *const u8).read_volatile() == 0 - }).unwrap(); + let str_start = + unsafe { ((argv + i * core::mem::size_of::()) as *const usize).read_volatile() }; + let len = (0usize..) + .find(|i| unsafe { ((str_start + *i) as *const u8).read_volatile() == 0 }) + .unwrap(); v.push( core::str::from_utf8(unsafe { core::slice::from_raw_parts(str_start as *const u8, len) - }).unwrap() + }) + .unwrap(), ); } exit(main(argc, v.as_slice())); @@ -69,22 +68,48 @@ bitflags! { } } -pub fn dup(fd: usize) -> isize { sys_dup(fd) } -pub fn open(path: &str, flags: OpenFlags) -> isize { sys_open(path, flags.bits) } -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); } -pub fn yield_() -> isize { sys_yield() } -pub fn get_time() -> isize { sys_get_time() } -pub fn getpid() -> isize { sys_getpid() } -pub fn fork() -> isize { sys_fork() } -pub fn exec(path: &str, args: &[*const u8]) -> isize { sys_exec(path, args) } +pub fn dup(fd: usize) -> isize { + sys_dup(fd) +} +pub fn open(path: &str, flags: OpenFlags) -> isize { + sys_open(path, flags.bits) +} +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); +} +pub fn yield_() -> isize { + sys_yield() +} +pub fn get_time() -> isize { + sys_get_time() +} +pub fn getpid() -> isize { + sys_getpid() +} +pub fn fork() -> isize { + sys_fork() +} +pub fn exec(path: &str, args: &[*const u8]) -> isize { + sys_exec(path, args) +} pub fn wait(exit_code: &mut i32) -> isize { loop { match sys_waitpid(-1, exit_code as *mut _) { - -2 => { yield_(); } + -2 => { + yield_(); + } // -1 or a real pid exit_pid => return exit_pid, } @@ -94,31 +119,66 @@ pub fn wait(exit_code: &mut i32) -> isize { pub fn waitpid(pid: usize, exit_code: &mut i32) -> isize { loop { match sys_waitpid(pid as isize, exit_code as *mut _) { - -2 => { yield_(); } + -2 => { + yield_(); + } // -1 or a real pid exit_pid => return exit_pid, } } } + +pub fn waitpid_nb(pid: usize, exit_code: &mut i32) -> isize { + sys_waitpid(pid as isize, exit_code as *mut _) +} + +bitflags! { + pub struct SignalFlags: i32 { + const SIGINT = 1 << 2; + const SIGILL = 1 << 4; + const SIGABRT = 1 << 6; + const SIGFPE = 1 << 8; + const SIGSEGV = 1 << 11; + } +} + +pub fn kill(pid: usize, signal: i32) -> isize { + sys_kill(pid, signal) +} + pub fn sleep(sleep_ms: usize) { sys_sleep(sleep_ms); } -pub fn thread_create(entry: usize, arg: usize) -> isize { sys_thread_create(entry, arg) } -pub fn gettid() -> isize { sys_gettid() } +pub fn thread_create(entry: usize, arg: usize) -> isize { + sys_thread_create(entry, arg) +} +pub fn gettid() -> isize { + sys_gettid() +} pub fn waittid(tid: usize) -> isize { loop { match sys_waittid(tid) { - -2 => { yield_(); } + -2 => { + yield_(); + } exit_code => return exit_code, } } } -pub fn mutex_create() -> isize { sys_mutex_create(false) } -pub fn mutex_blocking_create() -> isize { sys_mutex_create(true) } -pub fn mutex_lock(mutex_id: usize) { sys_mutex_lock(mutex_id); } -pub fn mutex_unlock(mutex_id: usize) { sys_mutex_unlock(mutex_id); } +pub fn mutex_create() -> isize { + sys_mutex_create(false) +} +pub fn mutex_blocking_create() -> isize { + sys_mutex_create(true) +} +pub fn mutex_lock(mutex_id: usize) { + sys_mutex_lock(mutex_id); +} +pub fn mutex_unlock(mutex_id: usize) { + sys_mutex_unlock(mutex_id); +} pub fn semaphore_create(res_count: usize) -> isize { sys_semaphore_create(res_count) } @@ -128,4 +188,12 @@ pub fn semaphore_up(sem_id: usize) { pub fn semaphore_down(sem_id: usize) { sys_semaphore_down(sem_id); } - +pub fn condvar_create() -> isize { + sys_condvar_create(0) +} +pub fn condvar_signal(condvar_id: usize) { + sys_condvar_signal(condvar_id); +} +pub fn condvar_wait(condvar_id: usize, mutex_id: usize) { + sys_condvar_wait(condvar_id, mutex_id); +} diff --git a/user/src/syscall.rs b/user/src/syscall.rs index ddd0e1b7..b4bb67a0 100644 --- a/user/src/syscall.rs +++ b/user/src/syscall.rs @@ -7,6 +7,7 @@ const SYSCALL_WRITE: usize = 64; const SYSCALL_EXIT: usize = 93; const SYSCALL_SLEEP: usize = 101; const SYSCALL_YIELD: usize = 124; +const SYSCALL_KILL: usize = 129; const SYSCALL_GET_TIME: usize = 169; const SYSCALL_GETPID: usize = 172; const SYSCALL_FORK: usize = 220; @@ -21,6 +22,9 @@ const SYSCALL_MUTEX_UNLOCK: usize = 1012; const SYSCALL_SEMAPHORE_CREATE: usize = 1020; const SYSCALL_SEMAPHORE_UP: usize = 1021; const SYSCALL_SEMAPHORE_DOWN: usize = 1022; +const SYSCALL_CONDVAR_CREATE: usize = 1030; +const SYSCALL_CONDVAR_SIGNAL: usize = 1031; +const SYSCALL_CONDVAR_WAIT: usize = 1032; fn syscall(id: usize, args: [usize; 3]) -> isize { let mut ret: isize; @@ -53,7 +57,10 @@ pub fn sys_pipe(pipe: &mut [usize]) -> 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()], + ) } pub fn sys_write(fd: usize, buffer: &[u8]) -> isize { @@ -73,6 +80,10 @@ pub fn sys_yield() -> isize { syscall(SYSCALL_YIELD, [0, 0, 0]) } +pub fn sys_kill(pid: usize, signal: i32) -> isize { + syscall(SYSCALL_KILL, [pid, signal as usize, 0]) +} + pub fn sys_get_time() -> isize { syscall(SYSCALL_GET_TIME, [0, 0, 0]) } @@ -86,7 +97,10 @@ pub fn sys_fork() -> isize { } pub fn sys_exec(path: &str, args: &[*const u8]) -> isize { - syscall(SYSCALL_EXEC, [path.as_ptr() as usize, args.as_ptr() as usize, 0]) + syscall( + SYSCALL_EXEC, + [path.as_ptr() as usize, args.as_ptr() as usize, 0], + ) } pub fn sys_waitpid(pid: isize, exit_code: *mut i32) -> isize { @@ -128,3 +142,15 @@ pub fn sys_semaphore_up(sem_id: usize) -> isize { pub fn sys_semaphore_down(sem_id: usize) -> isize { syscall(SYSCALL_SEMAPHORE_DOWN, [sem_id, 0, 0]) } + +pub fn sys_condvar_create(_arg: usize) -> isize { + syscall(SYSCALL_CONDVAR_CREATE, [_arg, 0, 0]) +} + +pub fn sys_condvar_signal(condvar_id: usize) -> isize { + syscall(SYSCALL_CONDVAR_SIGNAL, [condvar_id, 0, 0]) +} + +pub fn sys_condvar_wait(condvar_id: usize, mutex_id: usize) -> isize { + syscall(SYSCALL_CONDVAR_WAIT, [condvar_id, mutex_id, 0]) +}