Merge recent updates from ch8

This commit is contained in:
Yifan Wu 2022-01-26 01:53:39 -08:00
commit e1ae9b6236
99 changed files with 1959 additions and 1437 deletions

View file

@ -8,4 +8,5 @@ edition = "2018"
[dependencies]
buddy_system_allocator = "0.6"
bitflags = "1.2.1"
bitflags = "1.2.1"
riscv = { git = "https://github.com/rcore-os/riscv", features = ["inline-asm"] }

View file

@ -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
}
}

View file

@ -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
}
}

View file

@ -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
}

View file

@ -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
}

View file

@ -41,4 +41,4 @@ pub fn main() -> i32 {
println!("{}", color_text!(text, i));
}
0
}
}

View file

@ -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
}
}

View file

@ -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
}
}

View file

@ -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
}
}

View file

@ -25,4 +25,4 @@ pub fn main() -> i32 {
println!("child process pid = {}, exit code = {}", pid, exit_code);
0
}
}
}

View file

@ -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;

View file

@ -8,4 +8,4 @@ extern crate user_lib;
pub fn main() -> i32 {
println!("Hello world from user mode program!");
0
}
}

View file

@ -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
}
}

10
user/src/bin/infloop.rs Normal file
View file

@ -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 {}
}

View file

@ -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::<u8>()]);
} 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

View file

@ -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
}
}

View file

@ -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

View file

@ -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!(" ");

View file

@ -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::<usize>(
core::str::from_utf8(&child_result[..result_len]).unwrap()
).unwrap()
str::parse::<usize>(core::str::from_utf8(&child_result[..result_len]).unwrap())
.unwrap()
);
let mut _unused: i32 = 0;
wait(&mut _unused);
println!("pipe_large_test passed!");
0
}
}
}

View file

@ -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
}
}
}

17
user/src/bin/priv_csr.rs Normal file
View file

@ -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
}

17
user/src/bin/priv_inst.rs Normal file
View file

@ -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
}

View file

@ -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);
}

View file

@ -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::<usize>().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
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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::<u8>()]);
} else {
let mut _unused: i32 = 0;
wait(&mut _unused);
@ -18,4 +18,4 @@ pub fn main() -> i32 {
}
}
0
}
}

View file

@ -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
}
}

View file

@ -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
}
}

View file

@ -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
}
}

View file

@ -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::<u8>().write_volatile(0);
}
0
}

45
user/src/bin/sync_sem.rs Normal file
View file

@ -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
}

View file

@ -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
}

View file

@ -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);

View file

@ -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);

View file

@ -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::<isize>()
.expect("Error when parsing timeout!");
let pid = fork() as usize;
if pid == 0 {
if exec(argv[1], &[core::ptr::null::<u8>()]) != 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
}

View file

@ -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<String>,
args_addr: Vec<*const u8>,
}
impl ProcessArguments {
pub fn new(command: &str) -> Self {
let args: Vec<_> = command.split(' ').collect();
let mut args_copy: Vec<String> = 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::<u8>());
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<String> = 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;
}
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;
} else if i == process_arguments_list.len() - 1 {
if !process_args.input.is_empty() {
valid = false;
}
let output_fd = output_fd as usize;
close(1);
assert_eq!(dup(output_fd), 1);
close(output_fd);
} else if !process_args.output.is_empty() || !process_args.input.is_empty()
{
valid = false;
}
// child process
if exec(args_copy[0].as_str(), args_addr.as_slice()) == -1 {
println!("Error when executing!");
return -4;
}
unreachable!();
}
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 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);
}
}
for pipe_fd in pipes_fd.iter() {
close(pipe_fd[0]);
close(pipe_fd[1]);
}
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 {
}
}
}
}
}

View file

@ -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::<u8>()]);
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
}
}

View file

@ -14,4 +14,4 @@ pub fn main() -> i32 {
}
println!("yield pass.");
0
}
}

View file

@ -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);
}
kill(getpid() as usize, SignalFlags::SIGABRT.bits());
unreachable!()
}

View file

@ -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::<usize>()) 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::<usize>()) 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);
}

View file

@ -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])
}