diff --git a/Makefile b/Makefile deleted file mode 100644 index 9146246..0000000 --- a/Makefile +++ /dev/null @@ -1,198 +0,0 @@ -DOCKER_NAME ?= rust-os-camp-2022 -DIR := workplace -.PHONY: docker build_docker - -test: test3 test4 test5 test6 test7 test8 - -lab1: test3 - -lab2: test4 - -lab3: test5 - -lab4: test6 test7 - -lab5: test8 - -setup: - rm -rf ${DIR} - mkdir ${DIR} - cp -r easy-fs ${DIR} - cp -r easy-fs-fuse ${DIR} - cp -r ci-user ${DIR} - cp -r bootloader ${DIR} - cp -r reports ${DIR} - cp rust-toolchain.toml ${DIR} -# export PATH=${PATH}:${HOME}/qemu-7.0.0:${HOME}/qemu-7.0.0/riscv64-softmmu - -test1: setup - cp -r os1 ${DIR}/os - cd ${DIR}/ci-user && make test CHAPTER=1 - - -test2: setup - cp -r os2 ${DIR}/os - cd ${DIR}/ci-user && make test CHAPTER=2 - -test3: setup - cp -r os3 ${DIR}/os - cd ${DIR}/ci-user && make test CHAPTER=3 - -test4: setup - cp -r os4 ${DIR}/os - cd ${DIR}/ci-user && make test CHAPTER=4 - -test5: setup - cp -r os5 ${DIR}/os - cd ${DIR}/ci-user && make test CHAPTER=5 - -test6: setup - cp -r os6 ${DIR}/os - cd ${DIR}/ci-user && make test CHAPTER=6 - -test7: setup - cp -r os7 ${DIR}/os - cd ${DIR}/ci-user && make test CHAPTER=7 - -test8: setup - cp -r os8 ${DIR}/os - cd ${DIR}/ci-user && make test CHAPTER=8 - -clean: - rm -rf ${DIR} - -docker: - docker run --rm -it -v ${PWD}:/mnt -w /mnt ${DOCKER_NAME} bash - -build_docker: - docker build -t ${DOCKER_NAME} . - -setupclassroom_test1: - mkdir -p .github/classroom/ - mkdir -p .github/workflows/ - touch .github/.keep - cp scripts/autograding-test1.json .github/classroom/autograding.json - cp scripts/classroom.yml .github/workflows/classroom.yml - git add .github/classroom/autograding.json - git add .github/workflows/classroom.yml - git add .github/.keep - git commit -m"update classroom.yml .keep autograding.json for classroom CI test" - git push - -setupclassroom_test2: - mkdir -p .github/classroom/ - mkdir -p .github/workflows/ - touch .github/.keep - cp scripts/autograding-test2.json .github/classroom/autograding.json - cp scripts/classroom.yml .github/workflows/classroom.yml - git add .github/classroom/autograding.json - git add .github/workflows/classroom.yml - git add .github/.keep - git commit -m"update classroom.yml .keep autograding.json for classroom CI test" - git push - -setupclassroom_test3: - mkdir -p .github/classroom/ - mkdir -p .github/workflows/ - touch .github/.keep - cp scripts/autograding-test3.json .github/classroom/autograding.json - cp scripts/classroom.yml .github/workflows/classroom.yml - git add .github/classroom/autograding.json - git add .github/workflows/classroom.yml - git add .github/.keep - git commit -m"update classroom.yml .keep autograding.json for classroom CI test" - git push - -setupclassroom_test4: - mkdir -p .github/classroom/ - mkdir -p .github/workflows/ - touch .github/.keep - cp scripts/autograding-test4.json .github/classroom/autograding.json - cp scripts/classroom.yml .github/workflows/classroom.yml - git add .github/classroom/autograding.json - git add .github/workflows/classroom.yml - git add .github/.keep - git commit -m"update classroom.yml .keep autograding.json for classroom CI test" - git push - -setupclassroom_test5: - mkdir -p .github/classroom/ - mkdir -p .github/workflows/ - touch .github/.keep - cp scripts/autograding-test5.json .github/classroom/autograding.json - cp scripts/classroom.yml .github/workflows/classroom.yml - git add .github/classroom/autograding.json - git add .github/workflows/classroom.yml - git add .github/.keep - git commit -m"update classroom.yml .keep autograding.json for classroom CI test" - git push - -setupclassroom_test6: - mkdir -p .github/classroom/ - mkdir -p .github/workflows/ - touch .github/.keep - cp scripts/autograding-test6.json .github/classroom/autograding.json - cp scripts/classroom.yml .github/workflows/classroom.yml - git add .github/classroom/autograding.json - git add .github/workflows/classroom.yml - git add .github/.keep - git commit -m"update classroom.yml .keep autograding.json for classroom CI test" - git push - -setupclassroom_test7: - mkdir -p .github/classroom/ - mkdir -p .github/workflows/ - touch .github/.keep - cp scripts/autograding-test7.json .github/classroom/autograding.json - cp scripts/classroom.yml .github/workflows/classroom.yml - git add .github/classroom/autograding.json - git add .github/workflows/classroom.yml - git add .github/.keep - git commit -m"update classroom.yml .keep autograding.json for classroom CI test" - git push - -setupclassroom_test8: - mkdir -p .github/classroom/ - mkdir -p .github/workflows/ - touch .github/.keep - cp scripts/autograding-test8.json .github/classroom/autograding.json - cp scripts/classroom.yml .github/workflows/classroom.yml - git add .github/classroom/autograding.json - git add .github/workflows/classroom.yml - git add .github/.keep - git commit -m"update classroom.yml .keep autograding.json for classroom CI test" - git push - -# for local ubuntu with zsh shell SHELL, need root for sudo -ubuntu_local_setenv: - sudo apt-get update - sudo apt install autoconf automake autotools-dev curl libmpc-dev libmpfr-dev libgmp-dev \ - gawk build-essential bison flex texinfo gperf libtool patchutils bc \ - zlib1g-dev libexpat-dev pkg-config libglib2.0-dev libpixman-1-dev git tmux python3 ninja-build zsh -y - cd ${HOME} && wget https://download.qemu.org/qemu-7.0.0.tar.xz - cd ${HOME} && tar xvJf qemu-7.0.0.tar.xz - cd ${HOME}/qemu-7.0.0 && ./configure --target-list=riscv64-softmmu,riscv64-linux-user - cd ${HOME}/qemu-7.0.0 && make -j$(nproc) - cd ${HOME}/qemu-7.0.0 && sudo make install - qemu-system-riscv64 --version - qemu-riscv64 --version - curl https://sh.rustup.rs -sSf | sh -s -- -y - source ${HOME}/.cargo/env - rustc --version - -# for github codespaces ubuntu with zsh SHELL, need root for sudo -codespaces_setenv: - sudo apt-get update - sudo apt install autoconf automake autotools-dev curl libmpc-dev libmpfr-dev libgmp-dev \ - gawk build-essential bison flex texinfo gperf libtool patchutils bc \ - zlib1g-dev libexpat-dev pkg-config libglib2.0-dev libpixman-1-dev git tmux python3 ninja-build zsh -y - cd .. && wget https://download.qemu.org/qemu-7.0.0.tar.xz - cd .. && tar xvJf qemu-7.0.0.tar.xz - cd ../qemu-7.0.0 && ./configure --target-list=riscv64-softmmu,riscv64-linux-user - cd ../qemu-7.0.0 && make -j$(nproc) - cd ../qemu-7.0.0 && sudo make install - qemu-system-riscv64 --version - qemu-riscv64 --version - curl https://sh.rustup.rs -sSf | sh -s -- -y - /bin/zsh && source /home/codespace/.cargo/env - rustc --version diff --git a/rust-toolchain.toml b/rust-toolchain.toml deleted file mode 100644 index fb29f84..0000000 --- a/rust-toolchain.toml +++ /dev/null @@ -1,5 +0,0 @@ -[toolchain] -profile = "minimal" -channel = "nightly-2022-09-16" -components = ["rust-src", "llvm-tools-preview", "rustfmt", "clippy"] -targets = ["riscv64gc-unknown-none-elf"] diff --git a/user/.cargo/config b/user/.cargo/config deleted file mode 100644 index e5ded8a..0000000 --- a/user/.cargo/config +++ /dev/null @@ -1,7 +0,0 @@ -[build] -target = "riscv64gc-unknown-none-elf" - -[target.riscv64gc-unknown-none-elf] -rustflags = [ - "-Clink-args=-Tsrc/linker.ld", -] diff --git a/user/.gitignore b/user/.gitignore deleted file mode 100644 index b5004eb..0000000 --- a/user/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -target/* -.vscode/ -build/ -.idea/ \ No newline at end of file diff --git a/user/Cargo.toml b/user/Cargo.toml deleted file mode 100644 index bdd5019..0000000 --- a/user/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "user_lib" -version = "0.1.0" -authors = ["Yifan Wu "] -edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -buddy_system_allocator = "0.6" -bitflags = "1.2.1" -spin = "0.9" -lock_api = "=0.4.6" -lazy_static = { version = "1.4.0", features = ["spin_no_std"] } - -[profile.release] -opt-level = "z" # Optimize for size. -strip = true # Automatically strip symbols from the binary. -lto = true diff --git a/user/Makefile b/user/Makefile deleted file mode 100644 index 1c87fe9..0000000 --- a/user/Makefile +++ /dev/null @@ -1,64 +0,0 @@ -TARGET := riscv64gc-unknown-none-elf -MODE := release -APP_DIR := src/bin -TARGET_DIR := target/$(TARGET)/$(MODE) -BUILD_DIR := build -OBJDUMP := rust-objdump --arch-name=riscv64 -OBJCOPY := rust-objcopy --binary-architecture=riscv64 -PY := python3 - -BASE ?= 0 -CHAPTER ?= 0 -TEST ?= $(CHAPTER) - -ifeq ($(TEST), 0) # No test, deprecated, previously used in v3 - APPS := $(filter-out $(wildcard $(APP_DIR)/ch*.rs), $(wildcard $(APP_DIR)/*.rs)) -else ifeq ($(TEST), 1) # All test - APPS := $(wildcard $(APP_DIR)/ch*.rs) -else - TESTS := $(shell seq $(BASE) $(TEST)) - ifeq ($(BASE), 0) # Normal tests only - APPS := $(foreach T, $(TESTS), $(wildcard $(APP_DIR)/ch$(T)_*.rs)) - else ifeq ($(BASE), 1) # Basic tests only - APPS := $(foreach T, $(TESTS), $(wildcard $(APP_DIR)/ch$(T)b_*.rs)) - else # Basic and normal - APPS := $(foreach T, $(TESTS), $(wildcard $(APP_DIR)/ch$(T)*.rs)) - endif -endif - -ELFS := $(patsubst $(APP_DIR)/%.rs, $(TARGET_DIR)/%, $(APPS)) - -binary: - @echo $(ELFS) - @if [ ${CHAPTER} -gt 3 ]; then \ - cargo build --release ;\ - else \ - CHAPTER=$(CHAPTER) python3 build.py ;\ - fi - @$(foreach elf, $(ELFS), \ - $(OBJCOPY) $(elf) --strip-all -O binary $(patsubst $(TARGET_DIR)/%, $(TARGET_DIR)/%.bin, $(elf)); \ - cp $(elf) $(patsubst $(TARGET_DIR)/%, $(TARGET_DIR)/%.elf, $(elf));) - -disasm: - @$(foreach elf, $(ELFS), \ - $(OBJDUMP) $(elf) -S > $(patsubst $(TARGET_DIR)/%, $(TARGET_DIR)/%.asm, $(elf));) - @$(foreach t, $(ELFS), cp $(t).asm $(BUILD_DIR)/asm/;) - -pre: - @mkdir -p $(BUILD_DIR)/bin/ - @mkdir -p $(BUILD_DIR)/elf/ - @mkdir -p $(BUILD_DIR)/app/ - @mkdir -p $(BUILD_DIR)/asm/ - @$(foreach t, $(APPS), cp $(t) $(BUILD_DIR)/app/;) - -build: clean pre binary - @$(foreach t, $(ELFS), cp $(t).bin $(BUILD_DIR)/bin/;) - @$(foreach t, $(ELFS), cp $(t).elf $(BUILD_DIR)/elf/;) - -clean: - @cargo clean - @rm -rf $(BUILD_DIR) - -all: build - -.PHONY: elf binary build clean all \ No newline at end of file diff --git a/user/build.py b/user/build.py deleted file mode 100644 index de0cb66..0000000 --- a/user/build.py +++ /dev/null @@ -1,23 +0,0 @@ -import os - -base_address = 0x80400000 -step = 0x20000 -linker = "src/linker.ld" - -app_id = 0 -apps = os.listdir("build/app") -apps.sort() -chapter = os.getenv("CHAPTER") - -for app in apps: - app = app[: app.find(".")] - os.system( - "cargo rustc --bin %s --release -- -Clink-args=-Ttext=%x" - % (app, base_address + step * app_id) - ) - print( - "[build.py] application %s start with address %s" - % (app, hex(base_address + step * app_id)) - ) - if chapter == '3': - app_id = app_id + 1 diff --git a/user/src/bin/ch2b_bad_address.rs b/user/src/bin/ch2b_bad_address.rs deleted file mode 100644 index bb6dfeb..0000000 --- a/user/src/bin/ch2b_bad_address.rs +++ /dev/null @@ -1,16 +0,0 @@ -#![no_std] -#![no_main] - -extern crate user_lib; - -/// 由于 rustsbi 的问题,该程序无法正确退出 -/// > rustsbi 0.2.0-alpha.1 已经修复,可以正常退出 - -#[no_mangle] -pub fn main() -> isize { - unsafe { - #[allow(clippy::zero_ptr)] - (0x0 as *mut u8).write_volatile(0); - } - panic!("FAIL: T.T\n"); -} \ No newline at end of file diff --git a/user/src/bin/ch2b_bad_instructions.rs b/user/src/bin/ch2b_bad_instructions.rs deleted file mode 100644 index f60791e..0000000 --- a/user/src/bin/ch2b_bad_instructions.rs +++ /dev/null @@ -1,15 +0,0 @@ -#![no_std] -#![no_main] - -extern crate user_lib; - -/// 由于 rustsbi 的问题,该程序无法正确退出 -/// > rustsbi 0.2.0-alpha.1 已经修复,可以正常退出 - -#[no_mangle] -pub fn main() -> ! { - unsafe { - core::arch::asm!("sret"); - } - panic!("FAIL: T.T\n"); -} \ No newline at end of file diff --git a/user/src/bin/ch2b_bad_register.rs b/user/src/bin/ch2b_bad_register.rs deleted file mode 100644 index 0bed325..0000000 --- a/user/src/bin/ch2b_bad_register.rs +++ /dev/null @@ -1,16 +0,0 @@ -#![no_std] -#![no_main] - -extern crate user_lib; - -/// 由于 rustsbi 的问题,该程序无法正确退出 -/// > rustsbi 0.2.0-alpha.1 已经修复,可以正常退出 - -#[no_mangle] -pub fn main() -> ! { - let mut sstatus: usize; - unsafe { - core::arch::asm!("csrr {}, sstatus", out(reg) sstatus); - } - panic!("(-_-) I get sstatus:{:x}\nFAIL: T.T\n", sstatus); -} diff --git a/user/src/bin/ch2b_hello_world.rs b/user/src/bin/ch2b_hello_world.rs deleted file mode 100644 index 327dec7..0000000 --- a/user/src/bin/ch2b_hello_world.rs +++ /dev/null @@ -1,14 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -/// 正确输出: -/// Hello world from user mode program! - -#[no_mangle] -fn main() -> i32 { - println!("Hello, world from user mode program!"); - 0 -} \ No newline at end of file diff --git a/user/src/bin/ch2b_power_3.rs b/user/src/bin/ch2b_power_3.rs deleted file mode 100644 index e0ec5f3..0000000 --- a/user/src/bin/ch2b_power_3.rs +++ /dev/null @@ -1,28 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -const LEN: usize = 100; - -#[no_mangle] -fn main() -> i32 { - let p = 3u64; - let m = 998244353u64; - let iter: usize = 200000; - let mut s = [0u64; LEN]; - let mut cur = 0usize; - s[cur] = 1; - for i in 1..=iter { - let next = if cur + 1 == LEN { 0 } else { cur + 1 }; - s[next] = s[cur] * p % m; - cur = next; - if i % 10000 == 0 { - println!("power_3 [{}/{}]", i, iter); - } - } - println!("{}^{} = {}(MOD {})", p, iter, s[cur], m); - println!("Test power_3 OK!"); - 0 -} \ No newline at end of file diff --git a/user/src/bin/ch2b_power_5.rs b/user/src/bin/ch2b_power_5.rs deleted file mode 100644 index e47761b..0000000 --- a/user/src/bin/ch2b_power_5.rs +++ /dev/null @@ -1,28 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -const LEN: usize = 100; - -#[no_mangle] -fn main() -> i32 { - let p = 5u64; - let m = 998244353u64; - let iter: usize = 140000; - let mut s = [0u64; LEN]; - let mut cur = 0usize; - s[cur] = 1; - for i in 1..=iter { - let next = if cur + 1 == LEN { 0 } else { cur + 1 }; - s[next] = s[cur] * p % m; - cur = next; - if i % 10000 == 0 { - println!("power_5 [{}/{}]", i, iter); - } - } - println!("{}^{} = {}(MOD {})", p, iter, s[cur], m); - println!("Test power_5 OK!"); - 0 -} diff --git a/user/src/bin/ch2b_power_7.rs b/user/src/bin/ch2b_power_7.rs deleted file mode 100644 index a97d2f5..0000000 --- a/user/src/bin/ch2b_power_7.rs +++ /dev/null @@ -1,28 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -const LEN: usize = 100; - -#[no_mangle] -fn main() -> i32 { - let p = 7u64; - let m = 998244353u64; - let iter: usize = 160000; - let mut s = [0u64; LEN]; - let mut cur = 0usize; - s[cur] = 1; - for i in 1..=iter { - let next = if cur + 1 == LEN { 0 } else { cur + 1 }; - s[next] = s[cur] * p % m; - cur = next; - if i % 10000 == 0 { - println!("power_7 [{}/{}]", i, iter); - } - } - println!("{}^{} = {}(MOD {})", p, iter, s[cur], m); - println!("Test power_7 OK!"); - 0 -} diff --git a/user/src/bin/ch3_taskinfo.rs b/user/src/bin/ch3_taskinfo.rs deleted file mode 100644 index 7f55f15..0000000 --- a/user/src/bin/ch3_taskinfo.rs +++ /dev/null @@ -1,46 +0,0 @@ -#![no_std] -#![no_main] - -extern crate user_lib; - -use user_lib::{ - get_time, println, sleep, task_info, TaskInfo, TaskStatus, SYSCALL_EXIT, SYSCALL_GETTIMEOFDAY, - SYSCALL_TASK_INFO, SYSCALL_WRITE, SYSCALL_YIELD, -}; - -#[no_mangle] -pub fn main() -> usize { - let t1 = get_time() as usize; - let info = TaskInfo::new(); - get_time(); - sleep(500); - let t2 = get_time() as usize; - // 注意本次 task info 调用也计入 - assert_eq!(0, task_info(&info)); - let t3 = get_time() as usize; - assert!(3 <= info.syscall_times[SYSCALL_GETTIMEOFDAY]); - assert_eq!(1, info.syscall_times[SYSCALL_TASK_INFO]); - assert_eq!(0, info.syscall_times[SYSCALL_WRITE]); - assert!(0 < info.syscall_times[SYSCALL_YIELD]); - assert_eq!(0, info.syscall_times[SYSCALL_EXIT]); - assert!(t2 - t1 <= info.time + 1); - assert!(info.time < t3 - t1 + 100); - assert!(info.status == TaskStatus::Running); - - // 想想为什么 write 调用是两次 - println!("string from task info test\n"); - let t4 = get_time() as usize; - assert_eq!(0, task_info(&info)); - let t5 = get_time() as usize; - assert!(5 <= info.syscall_times[SYSCALL_GETTIMEOFDAY]); - assert_eq!(2, info.syscall_times[SYSCALL_TASK_INFO]); - assert_eq!(2, info.syscall_times[SYSCALL_WRITE]); - assert!(0 < info.syscall_times[SYSCALL_YIELD]); - assert_eq!(0, info.syscall_times[SYSCALL_EXIT]); - assert!(t4 - t1 <= info.time + 1); - assert!(info.time < t5 - t1 + 100); - assert!(info.status == TaskStatus::Running); - - println!("Test task info OK!"); - 0 -} diff --git a/user/src/bin/ch3b_sleep.rs b/user/src/bin/ch3b_sleep.rs deleted file mode 100644 index 1312f6c..0000000 --- a/user/src/bin/ch3b_sleep.rs +++ /dev/null @@ -1,24 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -use user_lib::{get_time, yield_}; - -/// 正确输出:(无报错信息) -/// get_time OK! {...} -/// Test sleep OK! - -#[no_mangle] -fn main() -> i32 { - let current_time = get_time(); - assert!(current_time > 0); - println!("get_time OK! {}", current_time); - let wait_for = current_time + 3000; - while get_time() < wait_for { - yield_(); - } - println!("Test sleep OK!"); - 0 -} diff --git a/user/src/bin/ch3b_sleep1.rs b/user/src/bin/ch3b_sleep1.rs deleted file mode 100644 index da0cae3..0000000 --- a/user/src/bin/ch3b_sleep1.rs +++ /dev/null @@ -1,22 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -use user_lib::{get_time, sleep}; - -#[no_mangle] -pub fn main() -> i32 { - let start = get_time(); - println!("current time_msec = {}", start); - sleep(100); - let end = get_time(); - println!( - "time_msec = {} after sleeping 100 ticks, delta = {}ms!", - end, - end - start - ); - println!("Test sleep1 passed!"); - 0 -} diff --git a/user/src/bin/ch3b_yield0.rs b/user/src/bin/ch3b_yield0.rs deleted file mode 100644 index 1e09edd..0000000 --- a/user/src/bin/ch3b_yield0.rs +++ /dev/null @@ -1,30 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -use user_lib::yield_; - -const WIDTH: usize = 10; -const HEIGHT: usize = 5; - -/* -理想结果:三个程序交替输出 ABC -*/ - -#[no_mangle] -fn main() -> i32 { - for i in 0..HEIGHT { - let buf = ['A' as u8; WIDTH]; - println!( - "{} [{}/{}]", - core::str::from_utf8(&buf).unwrap(), - i + 1, - HEIGHT - ); - yield_(); - } - println!("Test write A OK!"); - 0 -} diff --git a/user/src/bin/ch3b_yield1.rs b/user/src/bin/ch3b_yield1.rs deleted file mode 100644 index ebfc13f..0000000 --- a/user/src/bin/ch3b_yield1.rs +++ /dev/null @@ -1,30 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -use user_lib::yield_; - -const WIDTH: usize = 10; -const HEIGHT: usize = 5; - -/* -理想结果:三个程序交替输出 ABC -*/ - -#[no_mangle] -fn main() -> i32 { - for i in 0..HEIGHT { - let buf = ['B' as u8; WIDTH]; - println!( - "{} [{}/{}]", - core::str::from_utf8(&buf).unwrap(), - i + 1, - HEIGHT - ); - yield_(); - } - println!("Test write B OK!"); - 0 -} diff --git a/user/src/bin/ch3b_yield2.rs b/user/src/bin/ch3b_yield2.rs deleted file mode 100644 index acbaac3..0000000 --- a/user/src/bin/ch3b_yield2.rs +++ /dev/null @@ -1,30 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -use user_lib::yield_; - -/* -理想结果:三个程序交替输出 ABC -*/ - -const WIDTH: usize = 10; -const HEIGHT: usize = 5; - -#[no_mangle] -fn main() -> i32 { - for i in 0..HEIGHT { - let buf = ['C' as u8; WIDTH]; - println!( - "{} [{}/{}]", - core::str::from_utf8(&buf).unwrap(), - i + 1, - HEIGHT - ); - yield_(); - } - println!("Test write C OK!"); - 0 -} diff --git a/user/src/bin/ch4_mmap0.rs b/user/src/bin/ch4_mmap0.rs deleted file mode 100644 index 5247eec..0000000 --- a/user/src/bin/ch4_mmap0.rs +++ /dev/null @@ -1,33 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -use user_lib::mmap; - -/* -理想结果:输出 Test 04_1 OK! -*/ - -#[no_mangle] -fn main() -> i32 { - let start: usize = 0x10000000; - let len: usize = 4096; - let prot: usize = 3; - assert_eq!(0, mmap(start, len, prot)); - for i in start..(start + len) { - let addr: *mut u8 = i as *mut u8; - unsafe { - *addr = i as u8; - } - } - for i in start..(start + len) { - let addr: *mut u8 = i as *mut u8; - unsafe { - assert_eq!(*addr, i as u8); - } - } - println!("Test 04_1 OK!"); - 0 -} diff --git a/user/src/bin/ch4_mmap1.rs b/user/src/bin/ch4_mmap1.rs deleted file mode 100644 index 63d6411..0000000 --- a/user/src/bin/ch4_mmap1.rs +++ /dev/null @@ -1,25 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -use user_lib::mmap; - -/* -理想结果:程序触发访存异常,被杀死。不输出 error 就算过。 -*/ - -#[no_mangle] -fn main() -> i32 { - let start: usize = 0x10000000; - let len: usize = 4096; - let prot: usize = 1; - assert_eq!(0, mmap(start, len, prot)); - let addr: *mut u8 = start as *mut u8; - unsafe { - *addr = start as u8; - } - println!("Should cause error, Test 04_2 fail!"); - 0 -} diff --git a/user/src/bin/ch4_mmap2.rs b/user/src/bin/ch4_mmap2.rs deleted file mode 100644 index 2489fa6..0000000 --- a/user/src/bin/ch4_mmap2.rs +++ /dev/null @@ -1,26 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -use user_lib::mmap; - -/* -理想结果:程序触发访存异常,被杀死。不输出 error 就算过。 -*/ - -#[no_mangle] -fn main() -> i32 { - let start: usize = 0x10000000; - let len: usize = 4096; - let prot: usize = 2; - assert_eq!(0, mmap(start, len, prot)); - let addr: *mut u8 = start as *mut u8; - unsafe { - // *addr = start as u8; // can't write, R == 0 && W == 1 is illegal in riscv - assert!(*addr != 0); - } - println!("Should cause error, Test 04_2 fail!"); - 0 -} diff --git a/user/src/bin/ch4_mmap3.rs b/user/src/bin/ch4_mmap3.rs deleted file mode 100644 index d9d04b6..0000000 --- a/user/src/bin/ch4_mmap3.rs +++ /dev/null @@ -1,25 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -use user_lib::mmap; - -/* -理想结果:对于错误的 mmap 返回 -1,最终输出 Test 04_4 test OK! -*/ - -#[no_mangle] -fn main() -> i32 { - let start: usize = 0x10000000; - let len: usize = 4096; - let prot: usize = 3; - assert_eq!(0, mmap(start, len, prot)); - assert_eq!(mmap(start - len, len + 1, prot), -1); - assert_eq!(mmap(start + len + 1, len, prot), -1); - assert_eq!(mmap(start + len, len, 0), -1); - assert_eq!(mmap(start + len, len, prot | 8), -1); - println!("Test 04_4 test OK!"); - 0 -} diff --git a/user/src/bin/ch4_unmap.rs b/user/src/bin/ch4_unmap.rs deleted file mode 100644 index b64f862..0000000 --- a/user/src/bin/ch4_unmap.rs +++ /dev/null @@ -1,36 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -use user_lib::{mmap, munmap}; - -/* -理想结果:输出 Test 04_5 ummap OK! -*/ - -#[no_mangle] -fn main() -> i32 { - let start: usize = 0x10000000; - let len: usize = 4096; - let prot: usize = 3; - assert_eq!(0, mmap(start, len, prot)); - assert_eq!(mmap(start + len, len * 2, prot), 0); - assert_eq!(munmap(start, len), 0); - assert_eq!(mmap(start - len, len + 1, prot), 0); - for i in (start - len)..(start + len * 3) { - let addr: *mut u8 = i as *mut u8; - unsafe { - *addr = i as u8; - } - } - for i in (start - len)..(start + len * 3) { - let addr: *mut u8 = i as *mut u8; - unsafe { - assert_eq!(*addr, i as u8); - } - } - println!("Test 04_5 ummap OK!"); - 0 -} diff --git a/user/src/bin/ch4_unmap2.rs b/user/src/bin/ch4_unmap2.rs deleted file mode 100644 index 85ddb75..0000000 --- a/user/src/bin/ch4_unmap2.rs +++ /dev/null @@ -1,23 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -use user_lib::{mmap, munmap}; - -/* -理想结果:输出 Test 04_6 ummap2 OK! -*/ - -#[no_mangle] -fn main() -> i32 { - let start: usize = 0x10000000; - let len: usize = 4096; - let prot: usize = 3; - assert_eq!(0, mmap(start, len, prot)); - assert_eq!(munmap(start, len + 1), -1); - assert_eq!(munmap(start + 1, len - 1), -1); - println!("Test 04_6 ummap2 OK!"); - 0 -} diff --git a/user/src/bin/ch5_exit0.rs b/user/src/bin/ch5_exit0.rs deleted file mode 100644 index 3bae851..0000000 --- a/user/src/bin/ch5_exit0.rs +++ /dev/null @@ -1,17 +0,0 @@ -#![no_std] -#![no_main] - -extern crate user_lib; -use user_lib::exit; - -/* -辅助测例,正常退出,不输出 FAIL 即可。 -*/ - -#[allow(unreachable_code)] -#[no_mangle] -pub fn main() -> i32 { - exit(66778); - panic!("FAIL: T.T\n"); - 0 -} diff --git a/user/src/bin/ch5_exit1.rs b/user/src/bin/ch5_exit1.rs deleted file mode 100644 index 47c09cb..0000000 --- a/user/src/bin/ch5_exit1.rs +++ /dev/null @@ -1,17 +0,0 @@ -#![no_std] -#![no_main] - -extern crate user_lib; -use user_lib::exit; - -/* -辅助测例,正常退出,不输出 FAIL 即可。 -*/ - -#[allow(unreachable_code)] -#[no_mangle] -pub fn main() -> i32 { - exit(-233); - panic!("FAIL: T.T\n"); - 0 -} diff --git a/user/src/bin/ch5_getpid.rs b/user/src/bin/ch5_getpid.rs deleted file mode 100644 index 66ee732..0000000 --- a/user/src/bin/ch5_getpid.rs +++ /dev/null @@ -1,18 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -use user_lib::getpid; - -/* -辅助测例 打印子进程 pid -*/ - -#[no_mangle] -pub fn main() -> i32 { - let pid = getpid(); - println!("Test getpid OK! pid = {}", pid); - 0 -} diff --git a/user/src/bin/ch5_setprio.rs b/user/src/bin/ch5_setprio.rs deleted file mode 100644 index 6aa1064..0000000 --- a/user/src/bin/ch5_setprio.rs +++ /dev/null @@ -1,20 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -use user_lib::set_priority; - -/// 正确输出:(无报错信息) -/// Test set_priority OK! - -#[no_mangle] -pub fn main() -> i32 { - assert_eq!(set_priority(10), 10); - assert_eq!(set_priority(isize::MAX), isize::MAX); - assert_eq!(set_priority(0), -1); - assert_eq!(set_priority(1), -1); - assert_eq!(set_priority(-10), -1); - println!("Test set_priority OK!"); - 0 -} diff --git a/user/src/bin/ch5_spawn0.rs b/user/src/bin/ch5_spawn0.rs deleted file mode 100644 index c01e9b4..0000000 --- a/user/src/bin/ch5_spawn0.rs +++ /dev/null @@ -1,29 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -use user_lib::{spawn, wait}; -const MAX_CHILD: usize = 40; - -/* -理想结果:生成 MAX_CHILD 个 getpid 的子进程,全部结束后,输出 Test spawn0 OK! -*/ - -#[no_mangle] -pub fn main() -> i32 { - for _ in 0..MAX_CHILD { - let cpid = spawn("ch5_getpid\0"); - assert!(cpid >= 0, "child pid invalid"); - println!("new child {}", cpid); - } - let mut exit_code: i32 = 0; - for _ in 0..MAX_CHILD { - assert!(wait(&mut exit_code) > 0, "wait stopped early"); - assert_eq!(exit_code, 0, "error exit code {}", exit_code); - } - assert!(wait(&mut exit_code) <= 0, "wait got too many"); - println!("Test spawn0 OK!"); - 0 -} diff --git a/user/src/bin/ch5_spawn1.rs b/user/src/bin/ch5_spawn1.rs deleted file mode 100644 index b6dbc38..0000000 --- a/user/src/bin/ch5_spawn1.rs +++ /dev/null @@ -1,35 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -use user_lib::{spawn, wait, waitpid}; - -/// 程序行为:先后产生 3 个有特定返回值的程序,检查 waitpid 能够获取正确返回值。 - -/// 理想输出: -/// new child i -/// Test wait OK! -/// Test waitpid OK! - -#[no_mangle] -pub fn main() -> i32 { - let cpid = spawn("ch5_exit0\0"); - assert!(cpid >= 0, "child pid invalid"); - println!("new child {}", cpid); - let mut exit_code: i32 = 0; - let exit_pid = wait(&mut exit_code); - assert_eq!(exit_pid, cpid, "error exit pid"); - assert_eq!(exit_code, 66778, "error exit code"); - println!("Test wait OK!"); - let (cpid0, cpid1) = (spawn("ch5_exit0\0"), spawn("ch5_exit1\0")); - let exit_pid = waitpid(cpid1 as usize, &mut exit_code); - assert_eq!(exit_pid, cpid1, "error exit pid"); - assert_eq!(exit_code, -233, "error exit code"); - let exit_pid = wait(&mut exit_code); - assert_eq!(exit_pid, cpid0, "error exit pid"); - assert_eq!(exit_code, 66778, "error exit code"); - println!("Test waitpid OK!"); - 0 -} diff --git a/user/src/bin/ch5_stride.rs b/user/src/bin/ch5_stride.rs deleted file mode 100644 index ca44875..0000000 --- a/user/src/bin/ch5_stride.rs +++ /dev/null @@ -1,33 +0,0 @@ -#![no_std] -#![no_main] - -extern crate user_lib; - -static TESTS: &[&str] = &[ - "ch5_stride0\0", - "ch5_stride1\0", - "ch5_stride2\0", - "ch5_stride3\0", - "ch5_stride4\0", - "ch5_stride5\0", -]; - - -use user_lib::{spawn, waitpid, set_priority}; - -#[no_mangle] -pub fn main() -> i32 { - let mut pid = [0; 6]; - let mut i = 0; - for test in TESTS { - pid[i] = spawn(*test); - i += 1; - } - set_priority(4); - for i in 0..6{ - let mut xstate: i32 = Default::default(); - let wait_pid = waitpid(pid[i] as usize, &mut xstate); - assert_eq!(pid[i], wait_pid); - } - 0 -} diff --git a/user/src/bin/ch5_stride0.rs b/user/src/bin/ch5_stride0.rs deleted file mode 100644 index 718e28a..0000000 --- a/user/src/bin/ch5_stride0.rs +++ /dev/null @@ -1,43 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -use user_lib::{get_time, set_priority}; - -/* -理想结果:6个进程退出时,输出 count 基本正比于 priority -*/ - -fn spin_delay() { - let mut j = true; - for _ in 0..10 { - j = !j; - } -} - -// to get enough accuracy, MAX_TIME (the running time of each process) should > 1000 mseconds. -const MAX_TIME: isize = 4000; -pub fn count_during(prio: isize) -> isize { - let start_time = get_time(); - let mut acc = 0; - set_priority(prio); - loop { - spin_delay(); - acc += 1; - if acc % 400 == 0 { - let time = get_time() - start_time; - if time > MAX_TIME { - return acc; - } - } - } -} - -#[no_mangle] -pub fn main() -> usize { - let prio = 5; - let count = count_during(prio); - println!("priority = {}, exitcode = {}, ratio = {}", prio, count, count/prio); - 0 -} diff --git a/user/src/bin/ch5_stride1.rs b/user/src/bin/ch5_stride1.rs deleted file mode 100644 index 9c00caf..0000000 --- a/user/src/bin/ch5_stride1.rs +++ /dev/null @@ -1,39 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -use user_lib::{get_time, set_priority}; - -fn spin_delay() { - let mut j = true; - for _ in 0..10 { - j = !j; - } -} - -// to get enough accuracy, MAX_TIME (the running time of each process) should > 1000 mseconds. -const MAX_TIME: isize = 4000; -fn count_during(prio: isize) -> isize { - let start_time = get_time(); - let mut acc = 0; - set_priority(prio); - loop { - spin_delay(); - acc += 1; - if acc % 400 == 0 { - let time = get_time() - start_time; - if time > MAX_TIME { - return acc; - } - } - } -} - -#[no_mangle] -pub fn main() -> usize { - let prio = 6; - let count = count_during(prio); - println!("priority = {}, exitcode = {}, ratio = {}", prio, count, count/prio); - 0 -} \ No newline at end of file diff --git a/user/src/bin/ch5_stride2.rs b/user/src/bin/ch5_stride2.rs deleted file mode 100644 index ac35682..0000000 --- a/user/src/bin/ch5_stride2.rs +++ /dev/null @@ -1,39 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -use user_lib::{get_time, set_priority}; - -fn spin_delay() { - let mut j = true; - for _ in 0..10 { - j = !j; - } -} - -// to get enough accuracy, MAX_TIME (the running time of each process) should > 1000 mseconds. -const MAX_TIME: isize = 4000; -fn count_during(prio: isize) -> isize { - let start_time = get_time(); - let mut acc = 0; - set_priority(prio); - loop { - spin_delay(); - acc += 1; - if acc % 400 == 0 { - let time = get_time() - start_time; - if time > MAX_TIME { - return acc; - } - } - } -} - -#[no_mangle] -pub fn main() -> usize { - let prio = 7; - let count = count_during(prio); - println!("priority = {}, exitcode = {}, ratio = {}", prio, count, count/prio); - 0 -} \ No newline at end of file diff --git a/user/src/bin/ch5_stride3.rs b/user/src/bin/ch5_stride3.rs deleted file mode 100644 index 87b9851..0000000 --- a/user/src/bin/ch5_stride3.rs +++ /dev/null @@ -1,39 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -use user_lib::{get_time, set_priority}; - -fn spin_delay() { - let mut j = true; - for _ in 0..10 { - j = !j; - } -} - -// to get enough accuracy, MAX_TIME (the running time of each process) should > 1000 mseconds. -const MAX_TIME: isize = 4000; -fn count_during(prio: isize) -> isize { - let start_time = get_time(); - let mut acc = 0; - set_priority(prio); - loop { - spin_delay(); - acc += 1; - if acc % 400 == 0 { - let time = get_time() - start_time; - if time > MAX_TIME { - return acc; - } - } - } -} - -#[no_mangle] -pub fn main() -> usize { - let prio = 8; - let count = count_during(prio); - println!("priority = {}, exitcode = {}, ratio = {}", prio, count, count/prio); - 0 -} diff --git a/user/src/bin/ch5_stride4.rs b/user/src/bin/ch5_stride4.rs deleted file mode 100644 index cf01c03..0000000 --- a/user/src/bin/ch5_stride4.rs +++ /dev/null @@ -1,39 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -use user_lib::{get_time, set_priority}; - -fn spin_delay() { - let mut j = true; - for _ in 0..10 { - j = !j; - } -} - -// to get enough accuracy, MAX_TIME (the running time of each process) should > 1000 mseconds. -const MAX_TIME: isize = 4000; -fn count_during(prio: isize) -> isize { - let start_time = get_time(); - let mut acc = 0; - set_priority(prio); - loop { - spin_delay(); - acc += 1; - if acc % 400 == 0 { - let time = get_time() - start_time; - if time > MAX_TIME { - return acc; - } - } - } -} - -#[no_mangle] -pub fn main() -> usize { - let prio = 9; - let count = count_during(prio); - println!("priority = {}, exitcode = {}, ratio = {}", prio, count, count/prio); - 0 -} \ No newline at end of file diff --git a/user/src/bin/ch5_stride5.rs b/user/src/bin/ch5_stride5.rs deleted file mode 100644 index aba1363..0000000 --- a/user/src/bin/ch5_stride5.rs +++ /dev/null @@ -1,39 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -use user_lib::{get_time, set_priority}; - -fn spin_delay() { - let mut j = true; - for _ in 0..10 { - j = !j; - } -} - -// to get enough accuracy, MAX_TIME (the running time of each process) should > 1000 mseconds. -const MAX_TIME: isize = 4000; -fn count_during(prio: isize) -> isize { - let start_time = get_time(); - let mut acc = 0; - set_priority(prio); - loop { - spin_delay(); - acc += 1; - if acc % 400 == 0 { - let time = get_time() - start_time; - if time > MAX_TIME { - return acc; - } - } - } -} - -#[no_mangle] -pub fn main() -> usize { - let prio = 10; - let count = count_during(prio); - println!("priority = {}, exitcode = {}, ratio = {}", prio, count, count/prio); - 0 -} \ No newline at end of file diff --git a/user/src/bin/ch5_usertest.rs b/user/src/bin/ch5_usertest.rs deleted file mode 100644 index 1ee95be..0000000 --- a/user/src/bin/ch5_usertest.rs +++ /dev/null @@ -1,61 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -static TESTS: &[&str] = &[ - "ch2b_hello_world\0", - "ch2b_power_3\0", - "ch2b_power_5\0", - "ch2b_power_7\0", - "ch3b_yield0\0", - "ch3b_yield1\0", - "ch3b_yield2\0", - "ch3b_sleep\0", - "ch3b_sleep1\0", - "ch4_mmap0\0", - "ch4_mmap1\0", - "ch4_mmap2\0", - "ch4_mmap3\0", - "ch4_unmap\0", - "ch4_unmap2\0", - "ch5_spawn0\0", - "ch5_spawn1\0", - "ch5_setprio\0", - // "ch5_stride\0", -]; -static STEST: &str = "ch5_stride\0"; - -use user_lib::{spawn, waitpid}; - -/// 辅助测例,运行所有其他测例。 - -#[no_mangle] -pub fn main() -> i32 { - let mut pid = [0; 20]; - for (i, &test) in TESTS.iter().enumerate() { - println!("Usertests: Running {}", test); - pid[i] = spawn(test); - } - let mut xstate: i32 = Default::default(); - for (i, &test) in TESTS.iter().enumerate() { - let wait_pid = waitpid(pid[i] as usize, &mut xstate); - assert_eq!(pid[i], wait_pid); - println!( - "\x1b[32mUsertests: Test {} in Process {} exited with code {}\x1b[0m", - test, pid[i], xstate - ); - } - println!("Usertests: Running {}", STEST); - let spid = spawn(STEST); - xstate = Default::default(); - let wait_pid = waitpid(spid as usize, &mut xstate); - assert_eq!(spid, wait_pid); - println!( - "\x1b[32mUsertests: Test {} in Process {} exited with code {}\x1b[0m", - STEST, spid, xstate - ); - println!("ch5 Usertests passed!"); - 0 -} diff --git a/user/src/bin/ch5b_exit.rs b/user/src/bin/ch5b_exit.rs deleted file mode 100644 index 60510c9..0000000 --- a/user/src/bin/ch5b_exit.rs +++ /dev/null @@ -1,30 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -use user_lib::{exit, fork, wait, waitpid, yield_}; - -const MAGIC: i32 = -0x10384; - -#[no_mangle] -pub fn main() -> i32 { - println!("I am the parent. Forking the child..."); - let pid = fork(); - if pid == 0 { - println!("I am the child."); - for _ in 0..7 { - yield_(); - } - exit(MAGIC); - } else { - println!("I am parent, fork a child pid {}", pid); - } - println!("I am the parent, waiting now.."); - let mut xstate: i32 = 0; - assert!(waitpid(pid as usize, &mut xstate) == pid && xstate == MAGIC); - assert!(waitpid(pid as usize, &mut xstate) < 0 && wait(&mut xstate) <= 0); - println!("waitpid {} ok.", pid); - println!("exit pass."); - 0 -} diff --git a/user/src/bin/ch5b_forktest.rs b/user/src/bin/ch5b_forktest.rs deleted file mode 100644 index 22b53a9..0000000 --- a/user/src/bin/ch5b_forktest.rs +++ /dev/null @@ -1,34 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -use user_lib::{exit, fork, wait}; - -const MAX_CHILD: usize = 40; - -#[no_mangle] -pub fn main() -> i32 { - for i in 0..MAX_CHILD { - let pid = fork(); - if pid == 0 { - println!("I am child {}", i); - exit(0); - } else { - println!("forked child pid = {}", pid); - } - assert!(pid > 0); - } - let mut exit_code: i32 = 0; - for _ in 0..MAX_CHILD { - if wait(&mut exit_code) <= 0 { - panic!("wait stopped early"); - } - } - if wait(&mut exit_code) > 0 { - panic!("wait got too many"); - } - println!("forktest pass."); - 0 -} diff --git a/user/src/bin/ch5b_forktest2.rs b/user/src/bin/ch5b_forktest2.rs deleted file mode 100644 index c91ce15..0000000 --- a/user/src/bin/ch5b_forktest2.rs +++ /dev/null @@ -1,34 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -use user_lib::{exit, fork, get_time, getpid, sleep, wait}; - -static NUM: usize = 30; - -#[no_mangle] -pub fn main() -> i32 { - for _ in 0..NUM { - 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; - println!("pid {} sleep for {} ms", getpid(), sleep_length); - sleep(sleep_length as usize); - println!("pid {} OK!", getpid()); - exit(0); - } - } - - let mut exit_code: i32 = 0; - for _ in 0..NUM { - assert!(wait(&mut exit_code) > 0); - assert_eq!(exit_code, 0); - } - assert!(wait(&mut exit_code) < 0); - println!("forktest2 test passed!"); - 0 -} diff --git a/user/src/bin/ch5b_forktest_simple.rs b/user/src/bin/ch5b_forktest_simple.rs deleted file mode 100644 index 29a624b..0000000 --- a/user/src/bin/ch5b_forktest_simple.rs +++ /dev/null @@ -1,28 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -use user_lib::{fork, getpid, wait}; - -#[no_mangle] -pub fn main() -> i32 { - assert_eq!(wait(&mut 0i32), -1); - println!("sys_wait without child process test passed!"); - println!("parent start, pid = {}!", getpid()); - let pid = fork(); - if pid == 0 { - // child process - println!("hello child process!"); - 100 - } else { - // parent process - let mut exit_code: i32 = 0; - println!("ready waiting on parent process!"); - assert_eq!(pid, wait(&mut exit_code)); - assert_eq!(exit_code, 100); - println!("child process pid = {}, exit code = {}", pid, exit_code); - 0 - } -} diff --git a/user/src/bin/ch5b_forktree.rs b/user/src/bin/ch5b_forktree.rs deleted file mode 100644 index bfcfc4c..0000000 --- a/user/src/bin/ch5b_forktree.rs +++ /dev/null @@ -1,37 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -use user_lib::{exit, fork, getpid, sleep, yield_}; - -const DEPTH: usize = 4; - -fn fork_child(cur: &str, branch: char) { - let mut next = [0u8; DEPTH + 1]; - let l = cur.len(); - if l >= DEPTH { - return; - } - next[..l].copy_from_slice(cur.as_bytes()); - next[l] = branch as u8; - if fork() == 0 { - fork_tree(core::str::from_utf8(&next[..l + 1]).unwrap()); - yield_(); - exit(0); - } -} - -fn fork_tree(cur: &str) { - println!("pid{}: {}", getpid(), cur); - fork_child(cur, '0'); - fork_child(cur, '1'); -} - -#[no_mangle] -pub fn main() -> i32 { - fork_tree(""); - sleep(3000); - 0 -} diff --git a/user/src/bin/ch5b_initproc.rs b/user/src/bin/ch5b_initproc.rs deleted file mode 100644 index 7fe93d8..0000000 --- a/user/src/bin/ch5b_initproc.rs +++ /dev/null @@ -1,28 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -use user_lib::{exec, fork, wait, yield_}; - -#[no_mangle] -fn main() -> i32 { - if fork() == 0 { - exec("ch5b_user_shell\0", &[0 as *const u8]); - } else { - loop { - let mut exit_code: i32 = 0; - let pid = wait(&mut exit_code); - if pid == -1 { - yield_(); - continue; - } - println!( - "[initproc] Released a zombie process, pid={}, exit_code={}", - pid, exit_code, - ); - } - } - 0 -} diff --git a/user/src/bin/ch5b_user_shell.rs b/user/src/bin/ch5b_user_shell.rs deleted file mode 100644 index ea7ae52..0000000 --- a/user/src/bin/ch5b_user_shell.rs +++ /dev/null @@ -1,66 +0,0 @@ -#![no_std] -#![no_main] - -extern crate alloc; - -#[macro_use] -extern crate user_lib; - -const LF: u8 = 0x0au8; -const CR: u8 = 0x0du8; -const DL: u8 = 0x7fu8; -const BS: u8 = 0x08u8; - -use alloc::string::String; -use user_lib::console::getchar; -use user_lib::{exec, flush, fork, waitpid}; - -#[no_mangle] -pub fn main() -> i32 { - println!("Rust user shell"); - let mut line: String = String::new(); - print!(">> "); - flush(); - loop { - let c = getchar(); - match c { - LF | CR => { - print!("\n"); - if !line.is_empty() { - line.push('\0'); - let pid = fork(); - if pid == 0 { - // child process - if exec(line.as_str(), &[0 as *const u8]) == -1 { - println!("Error when executing!"); - return -4; - } - 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); - } - line.clear(); - } - print!(">> "); - flush(); - } - BS | DL => { - if !line.is_empty() { - print!("{}", BS as char); - print!(" "); - print!("{}", BS as char); - flush(); - line.pop(); - } - } - _ => { - print!("{}", c as char); - flush(); - line.push(c as char); - } - } - } -} diff --git a/user/src/bin/ch6_file0.rs b/user/src/bin/ch6_file0.rs deleted file mode 100644 index 0b61fc9..0000000 --- a/user/src/bin/ch6_file0.rs +++ /dev/null @@ -1,31 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -use user_lib::{close, open, read, write, OpenFlags}; - -/// 测试文件基本读写,输出 Test file0 OK! 就算正确。 - -#[no_mangle] -pub fn main() -> i32 { - let test_str = "Hello, world!"; - let fname = "fname\0"; - let fd = open(fname, OpenFlags::CREATE | OpenFlags::WRONLY); - assert!(fd > 0); - let fd = fd as usize; - write(fd, test_str.as_bytes()); - close(fd); - - let fd = open(fname, OpenFlags::RDONLY); - assert!(fd > 0); - let fd = fd as usize; - let mut buffer = [0u8; 100]; - let read_len = read(fd, &mut buffer) as usize; - close(fd); - - assert_eq!(test_str, core::str::from_utf8(&buffer[..read_len]).unwrap(),); - println!("Test file0 OK!"); - 0 -} diff --git a/user/src/bin/ch6_file1.rs b/user/src/bin/ch6_file1.rs deleted file mode 100644 index 6565121..0000000 --- a/user/src/bin/ch6_file1.rs +++ /dev/null @@ -1,26 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -use user_lib::{close, fstat, open, OpenFlags, Stat, StatMode}; - -/// 测试 fstat,输出 Test fstat OK! 就算正确。 - -#[no_mangle] -pub fn main() -> i32 { - let fname = "fname1\0"; - let fd = open(fname, OpenFlags::CREATE | OpenFlags::WRONLY); - assert!(fd > 0); - let fd = fd as usize; - let stat: Stat = Stat::new(); - let ret = fstat(fd, &stat); - assert_eq!(ret, 0); - assert_eq!(stat.mode, StatMode::FILE); - assert_eq!(stat.nlink, 1); - close(fd); - // unlink(fname); - // It's recommended to rebuild the disk image. This program will not clean the file "fname1". - println!("Test fstat OK!"); - 0 -} diff --git a/user/src/bin/ch6_file2.rs b/user/src/bin/ch6_file2.rs deleted file mode 100644 index c646314..0000000 --- a/user/src/bin/ch6_file2.rs +++ /dev/null @@ -1,46 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -use user_lib::{close, fstat, link, open, read, unlink, write, OpenFlags, Stat}; - -/// 测试 link/unlink,输出 Test link OK! 就算正确。 - -#[no_mangle] -pub fn main() -> i32 { - let test_str = "Hello, world!"; - let fname = "fname2\0"; - let (lname0, lname1, lname2) = ("linkname0\0", "linkname1\0", "linkname2\0"); - let fd = open(fname, OpenFlags::CREATE | OpenFlags::WRONLY) as usize; - link(fname, lname0); - let stat = Stat::new(); - fstat(fd, &stat); - assert_eq!(stat.nlink, 2); - link(fname, lname1); - link(fname, lname2); - fstat(fd, &stat); - assert_eq!(stat.nlink, 4); - write(fd, test_str.as_bytes()); - close(fd); - - unlink(fname); - let fd = open(lname0, OpenFlags::RDONLY) as usize; - let stat2 = Stat::new(); - let mut buf = [0u8; 100]; - let read_len = read(fd, &mut buf) as usize; - assert_eq!(test_str, core::str::from_utf8(&buf[..read_len]).unwrap(),); - fstat(fd, &stat2); - assert_eq!(stat2.dev, stat.dev); - assert_eq!(stat2.ino, stat.ino); - assert_eq!(stat2.nlink, 3); - unlink(lname1); - unlink(lname2); - fstat(fd, &stat2); - assert_eq!(stat2.nlink, 1); - close(fd); - unlink(lname0); - // It's Ok if you don't delete the inode and data blocks. - println!("Test link OK!"); - 0 -} diff --git a/user/src/bin/ch6_file3.rs b/user/src/bin/ch6_file3.rs deleted file mode 100644 index 2c21a4a..0000000 --- a/user/src/bin/ch6_file3.rs +++ /dev/null @@ -1,31 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -use user_lib::{close, open, unlink, write, OpenFlags}; - -/// 测试大量 open/unlink,输出 Test mass open/unlink OK! 就算正确。 - -#[no_mangle] -pub fn main() -> i32 { - let test_str = "some random long long long long long long long long string".repeat(50); - let fname = "fname3\0"; - for i in 0..10 { - let fd = open(fname, OpenFlags::CREATE | OpenFlags::WRONLY); - if fd == -1 { - panic!("failed to crate file"); - } - let fd = fd as usize; - for _ in 0..50 { - write(fd, test_str.as_bytes()); - } - close(fd); - assert_eq!(unlink(fname), 0); - let fd = open(fname, OpenFlags::RDONLY); - assert!(fd < 0); - println!("test iteration {}", i) - } - println!("Test mass open/unlink OK!"); - 0 -} diff --git a/user/src/bin/ch6_usertest.rs b/user/src/bin/ch6_usertest.rs deleted file mode 100644 index e9bcb51..0000000 --- a/user/src/bin/ch6_usertest.rs +++ /dev/null @@ -1,51 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -static TESTS: &[&str] = &[ - "ch2b_hello_world\0", - "ch2b_power_3\0", - "ch2b_power_5\0", - "ch2b_power_7\0", - "ch3b_yield0\0", - "ch3b_yield1\0", - "ch3b_yield2\0", - "ch3b_sleep\0", - "ch3b_sleep1\0", - "ch4_mmap0\0", - "ch4_mmap1\0", - "ch4_mmap2\0", - "ch4_mmap3\0", - "ch4_unmap\0", - "ch4_unmap2\0", - "ch5b_forktest2\0", - "ch5_spawn0\0", - "ch5_spawn1\0", - "ch6_file0\0", - "ch6_file1\0", - "ch6_file2\0", - "ch6_file3\0", -]; - -use user_lib::{spawn, waitpid}; - -/// 辅助测例,运行所有其他测例。 - -#[no_mangle] -pub fn main() -> i32 { - for test in TESTS { - println!("Usertests: Running {}", test); - let pid = spawn(*test); - let mut xstate: i32 = Default::default(); - let wait_pid = waitpid(pid as usize, &mut xstate); - assert_eq!(pid, wait_pid); - println!( - "\x1b[32mUsertests: Test {} in Process {} exited with code {}\x1b[0m", - test, pid, xstate - ); - } - println!("ch6 Usertests passed!"); - 0 -} diff --git a/user/src/bin/ch6b_cat.rs b/user/src/bin/ch6b_cat.rs deleted file mode 100644 index f9b43e2..0000000 --- a/user/src/bin/ch6b_cat.rs +++ /dev/null @@ -1,33 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -extern crate alloc; - -use user_lib::{ - open, - OpenFlags, - close, - read, -}; -use alloc::string::String; - -#[no_mangle] -pub fn main() -> i32 { - let fd = open("filea\0", OpenFlags::RDONLY); - if fd == -1 { - panic!("Error occured when opening file"); - } - let fd = fd as usize; - let mut buf = [0u8; 16]; - let mut s = String::new(); - loop { - let size = read(fd, &mut buf) as usize; - if size == 0 { break; } - s.push_str(core::str::from_utf8(&buf[..size]).unwrap()); - } - println!("{}", s); - close(fd); - 0 -} diff --git a/user/src/bin/ch6b_filetest_simple.rs b/user/src/bin/ch6b_filetest_simple.rs deleted file mode 100644 index 60fda6a..0000000 --- a/user/src/bin/ch6b_filetest_simple.rs +++ /dev/null @@ -1,38 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -use user_lib::{ - open, - close, - read, - write, - OpenFlags, -}; - -#[no_mangle] -pub fn main() -> i32 { - let test_str = "Hello, world!"; - let filea = "filea\0"; - let fd = open(filea, OpenFlags::CREATE | OpenFlags::WRONLY); - assert!(fd > 0); - let fd = fd as usize; - write(fd, test_str.as_bytes()); - close(fd); - - let fd = open(filea, OpenFlags::RDONLY); - assert!(fd > 0); - let fd = fd as usize; - let mut buffer = [0u8; 100]; - let read_len = read(fd, &mut buffer) as usize; - close(fd); - - 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/ch6b_initproc.rs b/user/src/bin/ch6b_initproc.rs deleted file mode 100644 index 008cd79..0000000 --- a/user/src/bin/ch6b_initproc.rs +++ /dev/null @@ -1,28 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -use user_lib::{exec, fork, wait, yield_}; - -#[no_mangle] -fn main() -> i32 { - if fork() == 0 { - exec("ch6b_user_shell\0", &[0 as *const u8]); - } else { - loop { - let mut exit_code: i32 = 0; - let pid = wait(&mut exit_code); - if pid == -1 { - yield_(); - continue; - } - println!( - "[initproc] Released a zombie process, pid={}, exit_code={}", - pid, exit_code, - ); - } - } - 0 -} diff --git a/user/src/bin/ch6b_user_shell.rs b/user/src/bin/ch6b_user_shell.rs deleted file mode 100644 index ea7ae52..0000000 --- a/user/src/bin/ch6b_user_shell.rs +++ /dev/null @@ -1,66 +0,0 @@ -#![no_std] -#![no_main] - -extern crate alloc; - -#[macro_use] -extern crate user_lib; - -const LF: u8 = 0x0au8; -const CR: u8 = 0x0du8; -const DL: u8 = 0x7fu8; -const BS: u8 = 0x08u8; - -use alloc::string::String; -use user_lib::console::getchar; -use user_lib::{exec, flush, fork, waitpid}; - -#[no_mangle] -pub fn main() -> i32 { - println!("Rust user shell"); - let mut line: String = String::new(); - print!(">> "); - flush(); - loop { - let c = getchar(); - match c { - LF | CR => { - print!("\n"); - if !line.is_empty() { - line.push('\0'); - let pid = fork(); - if pid == 0 { - // child process - if exec(line.as_str(), &[0 as *const u8]) == -1 { - println!("Error when executing!"); - return -4; - } - 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); - } - line.clear(); - } - print!(">> "); - flush(); - } - BS | DL => { - if !line.is_empty() { - print!("{}", BS as char); - print!(" "); - print!("{}", BS as char); - flush(); - line.pop(); - } - } - _ => { - print!("{}", c as char); - flush(); - line.push(c as char); - } - } - } -} diff --git a/user/src/bin/ch7_usertest.rs b/user/src/bin/ch7_usertest.rs deleted file mode 100644 index dae1b98..0000000 --- a/user/src/bin/ch7_usertest.rs +++ /dev/null @@ -1,29 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -static TESTS: &[&str] = &[ -]; - -use user_lib::{spawn, waitpid}; - -/// 辅助测例,运行所有其他测例。 - -#[no_mangle] -pub fn main() -> i32 { - for test in TESTS { - println!("Usertests: Running {}", test); - let pid = spawn(*test); - let mut xstate: i32 = Default::default(); - let wait_pid = waitpid(pid as usize, &mut xstate); - assert_eq!(pid, wait_pid); - println!( - "\x1b[32mUsertests: Test {} in Process {} exited with code {}\x1b[0m", - test, pid, xstate - ); - } - println!("ch7 Usertests passed!"); - 0 -} diff --git a/user/src/bin/ch7b_cat.rs b/user/src/bin/ch7b_cat.rs deleted file mode 100644 index 84fb8a6..0000000 --- a/user/src/bin/ch7b_cat.rs +++ /dev/null @@ -1,34 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -extern crate alloc; - -use user_lib::{ - open, - OpenFlags, - close, - read, -}; -use alloc::string::String; - -#[no_mangle] -pub fn main(argc: usize, argv: &[&str]) -> i32 { - assert!(argc == 2); - let fd = open(argv[1], OpenFlags::RDONLY); - if fd == -1 { - panic!("Error occured when opening file"); - } - let fd = fd as usize; - let mut buf = [0u8; 16]; - let mut s = String::new(); - loop { - let size = read(fd, &mut buf) as usize; - if size == 0 { break; } - s.push_str(core::str::from_utf8(&buf[..size]).unwrap()); - } - println!("{}", s); - close(fd); - 0 -} diff --git a/user/src/bin/ch7b_initproc.rs b/user/src/bin/ch7b_initproc.rs deleted file mode 100644 index f9a887d..0000000 --- a/user/src/bin/ch7b_initproc.rs +++ /dev/null @@ -1,28 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -use user_lib::{exec, fork, wait, yield_}; - -#[no_mangle] -fn main() -> i32 { - if fork() == 0 { - exec("ch7b_user_shell\0", &[0 as *const u8]); - } else { - loop { - let mut exit_code: i32 = 0; - let pid = wait(&mut exit_code); - if pid == -1 { - yield_(); - continue; - } - println!( - "[initproc] Released a zombie process, pid={}, exit_code={}", - pid, exit_code, - ); - } - } - 0 -} diff --git a/user/src/bin/ch7b_pipe_large_test.rs b/user/src/bin/ch7b_pipe_large_test.rs deleted file mode 100644 index eeac104..0000000 --- a/user/src/bin/ch7b_pipe_large_test.rs +++ /dev/null @@ -1,71 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -extern crate alloc; - -use alloc::format; -use user_lib::{close, fork, get_time, pipe, read, wait, write}; - -const LENGTH: usize = 3000; -#[no_mangle] -pub fn main() -> i32 { - // create pipes - // parent write to child - let mut down_pipe_fd = [0usize; 2]; - // child write to parent - let mut up_pipe_fd = [0usize; 2]; - pipe(&mut down_pipe_fd); - pipe(&mut up_pipe_fd); - let mut random_str = [0u8; LENGTH]; - if fork() == 0 { - // close write end of down pipe - close(down_pipe_fd[1]); - // close read end of up pipe - close(up_pipe_fd[0]); - assert_eq!(read(down_pipe_fd[0], &mut random_str) as usize, LENGTH); - close(down_pipe_fd[0]); - let sum: usize = random_str.iter().map(|v| *v as usize).sum::(); - println!("sum = {}(child)", sum); - let sum_str = format!("{}", sum); - write(up_pipe_fd[1], sum_str.as_bytes()); - close(up_pipe_fd[1]); - println!("Child process exited!"); - 0 - } else { - // close read end of down pipe - close(down_pipe_fd[0]); - // close write end of up pipe - close(up_pipe_fd[1]); - // generate a long random string - for ch in random_str.iter_mut().take(LENGTH) { - *ch = get_time() as u8; - } - // send it - assert_eq!( - write(down_pipe_fd[1], &random_str) as usize, - random_str.len() - ); - // close write end of down pipe - close(down_pipe_fd[1]); - // calculate sum(parent) - let sum: usize = random_str.iter().map(|v| *v as usize).sum::(); - println!("sum = {}(parent)", sum); - // recv sum(child) - let mut child_result = [0u8; 32]; - let result_len = read(up_pipe_fd[0], &mut child_result) as usize; - close(up_pipe_fd[0]); - // check - assert_eq!( - sum, - str::parse::(core::str::from_utf8(&child_result[..result_len]).unwrap()) - .unwrap() - ); - let mut _unused: i32 = 0; - wait(&mut _unused); - println!("pipe_large_test passed!"); - 0 - } -} diff --git a/user/src/bin/ch7b_pipetest.rs b/user/src/bin/ch7b_pipetest.rs deleted file mode 100644 index 5436c63..0000000 --- a/user/src/bin/ch7b_pipetest.rs +++ /dev/null @@ -1,44 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -use user_lib::{close, fork, pipe, read, wait, write}; - -static STR: &str = "Hello, world!"; - -#[no_mangle] -pub fn main() -> i32 { - // create pipe - let mut pipe_fd = [0usize; 2]; - pipe(&mut pipe_fd); - // read end - assert_eq!(pipe_fd[0], 3); - // write end - assert_eq!(pipe_fd[1], 4); - if fork() == 0 { - // child process, read from parent - // close write_end - close(pipe_fd[1]); - let mut buffer = [0u8; 32]; - let len_read = read(pipe_fd[0], &mut buffer) as usize; - // close read_end - close(pipe_fd[0]); - assert_eq!(core::str::from_utf8(&buffer[..len_read]).unwrap(), STR); - println!("Read OK, child process exited!"); - 0 - } else { - // parent process, write to child - // close read end - close(pipe_fd[0]); - assert_eq!(write(pipe_fd[1], STR.as_bytes()), STR.len() as isize); - // close write end - close(pipe_fd[1]); - let mut child_exit_code: i32 = 0; - wait(&mut child_exit_code); - assert_eq!(child_exit_code, 0); - println!("pipetest passed!"); - 0 - } -} diff --git a/user/src/bin/ch7b_run_pipe_test.rs b/user/src/bin/ch7b_run_pipe_test.rs deleted file mode 100644 index 08dfbc1..0000000 --- a/user/src/bin/ch7b_run_pipe_test.rs +++ /dev/null @@ -1,21 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -use user_lib::{exec, fork, wait}; - -#[no_mangle] -pub fn main() -> i32 { - for i in 0..1000 { - if fork() == 0 { - exec("ch7b_pipe_large_test\0", &[0 as *const u8]); - } else { - let mut _unused: i32 = 0; - wait(&mut _unused); - println!("Iter {} OK.", i); - } - } - 0 -} diff --git a/user/src/bin/ch7b_user_shell.rs b/user/src/bin/ch7b_user_shell.rs deleted file mode 100644 index 23dbb1e..0000000 --- a/user/src/bin/ch7b_user_shell.rs +++ /dev/null @@ -1,130 +0,0 @@ -#![no_std] -#![no_main] - -extern crate alloc; - -#[macro_use] -extern crate user_lib; - -const LF: u8 = 0x0au8; -const CR: u8 = 0x0du8; -const DL: u8 = 0x7fu8; -const BS: u8 = 0x08u8; - -use alloc::string::String; -use alloc::vec::Vec; -use user_lib::console::getchar; -use user_lib::{close, dup, exec, flush, fork, open, waitpid, OpenFlags}; - -#[no_mangle] -pub fn main() -> i32 { - println!("Rust user shell"); - let mut line: String = String::new(); - print!(">> "); - flush(); - 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.iter().map(|arg| arg.as_ptr()).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 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 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; - } - 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); - } - line.clear(); - } - print!(">> "); - flush(); - } - BS | DL => { - if !line.is_empty() { - print!("{}", BS as char); - print!(" "); - print!("{}", BS as char); - flush(); - line.pop(); - } - } - _ => { - print!("{}", c as char); - flush(); - line.push(c as char); - } - } - } -} diff --git a/user/src/bin/ch7b_yield.rs b/user/src/bin/ch7b_yield.rs deleted file mode 100644 index 55032e4..0000000 --- a/user/src/bin/ch7b_yield.rs +++ /dev/null @@ -1,17 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -use user_lib::{getpid, yield_}; - -#[no_mangle] -pub fn main() -> i32 { - println!("Hello, I am process {}.", getpid()); - for i in 0..5 { - yield_(); - println!("Back in process {}, iteration {}.", getpid(), i); - } - println!("yield pass."); - 0 -} \ No newline at end of file diff --git a/user/src/bin/ch8_deadlock_mutex1.rs b/user/src/bin/ch8_deadlock_mutex1.rs deleted file mode 100644 index 15a0f2d..0000000 --- a/user/src/bin/ch8_deadlock_mutex1.rs +++ /dev/null @@ -1,22 +0,0 @@ -#![no_std] -#![no_main] -#![allow(clippy::println_empty_string)] - -#[macro_use] -extern crate user_lib; -extern crate alloc; - -use user_lib::{enable_deadlock_detect, mutex_blocking_create, mutex_lock, mutex_unlock}; - -// 理想结果:检测到死锁 - -#[no_mangle] -pub fn main() -> i32 { - enable_deadlock_detect(true); - let mid = mutex_blocking_create() as usize; - assert_eq!(mutex_lock(mid), 0); - assert_eq!(mutex_lock(mid), -0xdead); - mutex_unlock(mid); - println!("deadlock test mutex 1 OK!"); - 0 -} diff --git a/user/src/bin/ch8_deadlock_sem1.rs b/user/src/bin/ch8_deadlock_sem1.rs deleted file mode 100644 index 21b1f95..0000000 --- a/user/src/bin/ch8_deadlock_sem1.rs +++ /dev/null @@ -1,102 +0,0 @@ -#![no_std] -#![no_main] -#![allow(clippy::println_empty_string)] - -#[macro_use] -extern crate user_lib; -extern crate alloc; - -use user_lib::{ - enable_deadlock_detect, exit, semaphore_create, semaphore_down, semaphore_up, sleep, -}; -use user_lib::{gettid, thread_create, waittid}; - -// sem 0: used to sync child thread with main -// sem 1-3: representing some kind of resource - -// 理想结果:检测到死锁,至少有一个子线程返回值不为 0 - -const SEM_BARRIER: usize = 0; -const THREAD_N: usize = 3; -const RES_TYPE: usize = 3; -const RES_NUM: [usize; RES_TYPE] = [1, 2, 1]; -const REQUEST: [Option; THREAD_N] = [Some(1), Some(3), Some(2)]; - -fn try_sem_down(sem_id: usize) { - if semaphore_down(sem_id) == -0xdead { - sem_dealloc(gettid() as usize); - println!("Deadlock detected. Test 08_sem1 failed!"); - exit(-1); - } -} - -fn sem_alloc(tid: usize) { - match tid { - 1 => assert_eq!(semaphore_down(2), 0), - 2 => { - assert_eq!(semaphore_down(1), 0); - assert_eq!(semaphore_down(2), 0); - } - 3 => assert_eq!(semaphore_down(3), 0), - _ => exit(1), - } - semaphore_down(SEM_BARRIER); -} - -fn sem_dealloc(tid: usize) { - semaphore_up(SEM_BARRIER); - match tid { - 1 => semaphore_up(2), - 2 => { - semaphore_up(1); - semaphore_up(2); - } - 3 => semaphore_up(3), - _ => exit(1), - } -} - -fn deadlock_test() { - let tid = gettid() as usize; - println!("thread {} running", tid); - sem_alloc(tid); - if let Some(sem_id) = REQUEST[tid - 1] { - try_sem_down(sem_id); - semaphore_up(sem_id); - } - sem_dealloc(tid); - println!("thread {} exited", tid); - exit(0); -} - -#[no_mangle] -pub fn main() -> i32 { - enable_deadlock_detect(true); - assert_eq!(semaphore_create(THREAD_N) as usize, SEM_BARRIER); - for _ in 0..THREAD_N { - semaphore_down(SEM_BARRIER); - } - - for n in RES_NUM { - semaphore_create(n); - } - let mut tids = [0; THREAD_N]; - - for i in 0..THREAD_N { - tids[i] = thread_create(deadlock_test as usize, 0) as usize; - } - - sleep(500); - for _ in 0..THREAD_N { - semaphore_up(SEM_BARRIER); - } - let mut failed = 0; - for tid in tids { - if waittid(tid) != 0 { - failed += 1; - } - } - assert!(failed > 0); - println!("deadlock test semaphore 1 OK!"); - 0 -} diff --git a/user/src/bin/ch8_deadlock_sem2.rs b/user/src/bin/ch8_deadlock_sem2.rs deleted file mode 100644 index ff653ea..0000000 --- a/user/src/bin/ch8_deadlock_sem2.rs +++ /dev/null @@ -1,76 +0,0 @@ -#![no_std] -#![no_main] -#![allow(clippy::println_empty_string)] - -#[macro_use] -extern crate user_lib; -extern crate alloc; - -use user_lib::{ - enable_deadlock_detect, exit, semaphore_create, semaphore_down, semaphore_up, sleep, -}; -use user_lib::{gettid, thread_create, waittid}; - -// sem 0: used to sync child thread with main -// sem 1-3: representing some kind of resource - -// 理想结果:未检测到死锁,子线程返回值均为 0 - -const THREAD_N: usize = 4; -const RES_TYPE: usize = 2; -const RES_NUM: [usize; RES_TYPE] = [2, 2]; -const ALLOC: [usize; THREAD_N] = [2, 1, 1, 2]; -const REQUEST: [Option; THREAD_N] = [Some(1), None, Some(2), None]; - -fn try_sem_down(sem_id: usize) { - if semaphore_down(sem_id) == -0xdead { - semaphore_up(ALLOC[(gettid() - 1) as usize]); - exit(-1); - } -} - -fn deadlock_test() { - let id = (gettid() - 1) as usize; - assert_eq!(semaphore_down(ALLOC[id]), 0); - semaphore_down(0); - if let Some(sem_id) = REQUEST[id] { - try_sem_down(sem_id); - semaphore_up(sem_id); - } - semaphore_up(ALLOC[id]); - exit(0); -} - -#[no_mangle] -pub fn main() -> i32 { - enable_deadlock_detect(true); - semaphore_create(THREAD_N); - for _ in 0..THREAD_N { - semaphore_down(0); - } - - for n in RES_NUM { - semaphore_create(n); - } - let mut tids = [0; THREAD_N]; - - for i in 0..THREAD_N { - tids[i] = thread_create(deadlock_test as usize, 0) as usize; - } - - sleep(1000); - for _ in 0..THREAD_N { - semaphore_up(0); - } - - let mut failed = 0; - for tid in tids { - if waittid(tid) != 0 { - failed += 1; - } - } - - assert_eq!(failed, 0); - println!("deadlock test semaphore 2 OK!"); - 0 -} diff --git a/user/src/bin/ch8_usertest.rs b/user/src/bin/ch8_usertest.rs deleted file mode 100644 index 79ec4af..0000000 --- a/user/src/bin/ch8_usertest.rs +++ /dev/null @@ -1,60 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -const TESTS: &[&str] = &[ - "ch2b_hello_world\0", - "ch2b_power_3\0", - "ch2b_power_5\0", - "ch2b_power_7\0", - "ch3b_sleep\0", - "ch3b_sleep1\0", - "ch3b_yield0\0", - "ch3b_yield1\0", - "ch3b_yield2\0", - "ch5b_forktest2\0", - "ch6b_filetest_simple\0", - "ch7b_pipetest\0", - "ch8_deadlock_mutex1\0", - "ch8_deadlock_sem1\0", - "ch8_deadlock_sem2\0", - "ch8b_mpsc_sem\0", - "ch8b_phil_din_mutex\0", - "ch8b_race_adder_mutex_spin\0", - "ch8b_sync_sem\0", - "ch8b_test_condvar\0", - "ch8b_threads\0", - "ch8b_threads_arg\0", -]; - -const TEST_NUM: usize = TESTS.len(); - -use user_lib::{exec, fork, waitpid}; - -#[no_mangle] -pub fn main() -> i32 { - let mut pids = [0; TEST_NUM]; - for (i, &test) in TESTS.iter().enumerate() { - println!("Usertests: Running {}", test); - let pid = fork(); - if pid == 0 { - exec(&*test, &[core::ptr::null::()]); - panic!("unreachable!"); - } else { - pids[i] = pid; - } - } - let mut xstate: i32 = Default::default(); - for (i, &test) in TESTS.iter().enumerate() { - let wait_pid = waitpid(pids[i] as usize, &mut xstate); - assert_eq!(pids[i], wait_pid); - println!( - "\x1b[32mUsertests: Test {} in Process {} exited with code {}\x1b[0m", - test, pids[i], xstate - ); - } - println!("ch8 Usertests passed!"); - 0 -} diff --git a/user/src/bin/ch8b_initproc.rs b/user/src/bin/ch8b_initproc.rs deleted file mode 100644 index 1e4011d..0000000 --- a/user/src/bin/ch8b_initproc.rs +++ /dev/null @@ -1,28 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -use user_lib::{exec, fork, wait, yield_}; - -#[no_mangle] -fn main() -> i32 { - if fork() == 0 { - exec("ch7b_user_shell\0", &[core::ptr::null::()]); - } else { - loop { - let mut exit_code: i32 = 0; - let pid = wait(&mut exit_code); - if pid == -1 { - yield_(); - continue; - } - println!( - "[initproc] Released a zombie process, pid={}, exit_code={}", - pid, exit_code, - ); - } - } - 0 -} diff --git a/user/src/bin/ch8b_mpsc_sem.rs b/user/src/bin/ch8b_mpsc_sem.rs deleted file mode 100644 index 7b92b9b..0000000 --- a/user/src/bin/ch8b_mpsc_sem.rs +++ /dev/null @@ -1,73 +0,0 @@ -#![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; -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; -const SEM_EXISTED: usize = 2; -const BUFFER_SIZE: usize = 8; -static mut BUFFER: [usize; BUFFER_SIZE] = [0; BUFFER_SIZE]; -static mut FRONT: usize = 0; -static mut TAIL: usize = 0; -const PRODUCER_COUNT: usize = 4; -const NUMBER_PER_PRODUCER: usize = 100; - -unsafe fn producer(id: *const usize) -> ! { - let id = *id; - for _ in 0..NUMBER_PER_PRODUCER { - semaphore_down(SEM_EMPTY); - semaphore_down(SEM_MUTEX); - BUFFER[FRONT] = id; - FRONT = (FRONT + 1) % BUFFER_SIZE; - semaphore_up(SEM_MUTEX); - semaphore_up(SEM_EXISTED); - } - exit(0) -} - -unsafe fn consumer() -> ! { - for _ in 0..PRODUCER_COUNT * NUMBER_PER_PRODUCER { - semaphore_down(SEM_EXISTED); - semaphore_down(SEM_MUTEX); - print!("{} ", BUFFER[TAIL]); - TAIL = (TAIL + 1) % BUFFER_SIZE; - semaphore_up(SEM_MUTEX); - semaphore_up(SEM_EMPTY); - } - println!(""); - exit(0) -} - -#[no_mangle] -pub fn main() -> i32 { - // create semaphores - assert_eq!(semaphore_create(1) as usize, SEM_MUTEX); - assert_eq!(semaphore_create(BUFFER_SIZE) as usize, SEM_EMPTY); - assert_eq!(semaphore_create(0) as usize, SEM_EXISTED); - // create threads - 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(consumer as usize, 0)); - // wait for all threads to complete - for thread in threads.iter() { - waittid(*thread as usize); - } - println!("mpsc_sem passed!"); - 0 -} diff --git a/user/src/bin/ch8b_phil_din_mutex.rs b/user/src/bin/ch8b_phil_din_mutex.rs deleted file mode 100644 index 7c0765b..0000000 --- a/user/src/bin/ch8b_phil_din_mutex.rs +++ /dev/null @@ -1,109 +0,0 @@ -#![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_blocking}; -use user_lib::{mutex_blocking_create, mutex_lock, mutex_unlock}; -use user_lib::{thread_create, waittid}; - -const N: usize = 5; -const ROUND: usize = 4; -// A round: think -> wait for forks -> eat -const GRAPH_SCALE: usize = 10; - -fn get_time_u() -> usize { - get_time() as usize -} - -// Time unit: ms -const ARR: [[usize; ROUND * 2]; N] = [ - [70, 80, 100, 40, 50, 60, 20, 40], - [30, 60, 20, 70, 100, 10, 30, 60], - [50, 20, 90, 20, 40, 60, 120, 40], - [50, 100, 60, 50, 80, 60, 20, 90], - [60, 10, 60, 60, 20, 50, 60, 20], -]; -static mut THINK: [[usize; ROUND * 2]; N] = [[0; ROUND * 2]; N]; -static mut EAT: [[usize; ROUND * 2]; N] = [[0; ROUND * 2]; N]; - -fn philosopher_dining_problem(id: *const usize) { - let id = unsafe { *id }; - let left = id; - let right = if id == N - 1 { 0 } else { id + 1 }; - let min = if left < right { left } else { right }; - let max = left + right - min; - for round in 0..ROUND { - // thinking - unsafe { - THINK[id][2 * round] = get_time_u(); - } - sleep_blocking(ARR[id][2 * round]); - 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(); - } - sleep_blocking(ARR[id][2 * round + 1]); - unsafe { - EAT[id][2 * round + 1] = get_time_u(); - } - mutex_unlock(max); - mutex_unlock(min); - } - exit(0) -} - -#[no_mangle] -pub fn main() -> i32 { - println!("Here comes {} philosophers!", N); - let mut v = Vec::new(); - let ids: Vec<_> = (0..N).collect(); - 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, - )); - } - for tid in v.iter() { - waittid(*tid as usize); - } - let time_cost = get_time_u() - start; - 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 { - let current_time = j * GRAPH_SCALE + start; - 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 - }) { - print!("-"); - } 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 - }) { - print!("x"); - } else { - print!(" "); - }; - } - println!(""); - } - println!("philosopher dining problem with mutex test passed!"); - 0 -} diff --git a/user/src/bin/ch8b_race_adder.rs b/user/src/bin/ch8b_race_adder.rs deleted file mode 100644 index 139e137..0000000 --- a/user/src/bin/ch8b_race_adder.rs +++ /dev/null @@ -1,43 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -extern crate alloc; - -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() -> ! { - let mut t = 2usize; - 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; - } - a.write_volatile(cur + 1); - } - exit(t as i32) -} - -#[no_mangle] -pub fn main() -> i32 { - let start = get_time(); - let mut v = Vec::new(); - for _ in 0..THREAD_COUNT { - v.push(thread_create(f as usize, 0) 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); - println!("race adder test passed!"); - 0 -} diff --git a/user/src/bin/ch8b_race_adder_atomic.rs b/user/src/bin/ch8b_race_adder_atomic.rs deleted file mode 100644 index c00fe6a..0000000 --- a/user/src/bin/ch8b_race_adder_atomic.rs +++ /dev/null @@ -1,52 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -extern crate alloc; - -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); -const PER_THREAD: usize = 1000; -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() - { - yield_(); - } - let a = &mut A as *mut usize; - let cur = a.read_volatile(); - for _ in 0..500 { - t = t * t % 10007; - } - a.write_volatile(cur + 1); - OCCUPIED.store(false, Ordering::Relaxed); - } - exit(t as i32) -} - -#[no_mangle] -pub fn main() -> i32 { - let start = get_time(); - let mut v = Vec::new(); - for _ in 0..THREAD_COUNT { - v.push(thread_create(f as usize, 0) 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); - println!("race adder using atomic test passed!"); - 0 -} diff --git a/user/src/bin/ch8b_race_adder_loop.rs b/user/src/bin/ch8b_race_adder_loop.rs deleted file mode 100644 index 11a0324..0000000 --- a/user/src/bin/ch8b_race_adder_loop.rs +++ /dev/null @@ -1,52 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -extern crate alloc; - -use alloc::vec::Vec; -use user_lib::{exit, get_time, thread_create, waittid, yield_}; - -static mut A: usize = 0; -static mut OCCUPIED: bool = false; -const PER_THREAD: usize = 1000; -const THREAD_COUNT: usize = 16; - -unsafe fn f() -> ! { - let mut t = 2usize; - for _ in 0..PER_THREAD { - 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; - } - a.write_volatile(cur + 1); - // exit critical section - OCCUPIED = false; - } - - exit(t as i32) -} - -#[no_mangle] -pub fn main() -> i32 { - let start = get_time(); - let mut v = Vec::new(); - for _ in 0..THREAD_COUNT { - v.push(thread_create(f as usize, 0) 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); - println!("race adder using loop test passed!"); - 0 -} diff --git a/user/src/bin/ch8b_race_adder_mutex_spin.rs b/user/src/bin/ch8b_race_adder_mutex_spin.rs deleted file mode 100644 index d2df338..0000000 --- a/user/src/bin/ch8b_race_adder_mutex_spin.rs +++ /dev/null @@ -1,47 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -extern crate alloc; - -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; -const THREAD_COUNT: usize = 16; - -unsafe fn f() -> ! { - let mut t = 2usize; - for _ in 0..PER_THREAD { - mutex_lock(0); - let a = &mut A as *mut usize; - let cur = a.read_volatile(); - for _ in 0..500 { - t = t * t % 10007; - } - a.write_volatile(cur + 1); - mutex_unlock(0); - } - exit(t as i32) -} - -#[no_mangle] -pub fn main() -> i32 { - let start = get_time(); - assert_eq!(mutex_create(), 0); - let mut v = Vec::new(); - for _ in 0..THREAD_COUNT { - v.push(thread_create(f as usize, 0) 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); - println!("race adder using spin mutex test passed!"); - 0 -} diff --git a/user/src/bin/ch8b_stackful_coroutine.rs b/user/src/bin/ch8b_stackful_coroutine.rs deleted file mode 100644 index 2341547..0000000 --- a/user/src/bin/ch8b_stackful_coroutine.rs +++ /dev/null @@ -1,346 +0,0 @@ -// we porting below codes to Rcore Tutorial v3 -// https://cfsamson.gitbook.io/green-threads-explained-in-200-lines-of-rust/ -// https://github.com/cfsamson/example-greenthreads -#![no_std] -#![no_main] -#![feature(naked_functions)] - -extern crate alloc; -#[macro_use] -extern crate user_lib; - -use alloc::vec; -use alloc::vec::Vec; -use core::arch::asm; - -use user_lib::exit; - -// In our simple example we set most constraints here. -const DEFAULT_STACK_SIZE: usize = 4096; //128 got SEGFAULT, 256(1024, 4096) got right results. -const MAX_TASKS: usize = 5; -static mut RUNTIME: usize = 0; - -pub struct Runtime { - tasks: Vec, - current: usize, -} - -#[derive(PartialEq, Eq, Debug)] -enum State { - Available, - Running, - Ready, -} - -struct Task { - id: usize, - stack: Vec, - ctx: TaskContext, - state: State, -} - -#[derive(Debug, Default)] -#[repr(C)] // not strictly needed but Rust ABI is not guaranteed to be stable -pub struct TaskContext { - // 15 u64 - x1: u64, //ra: return addres - x2: u64, //sp - x8: u64, //s0,fp - x9: u64, //s1 - x18: u64, //x18-27: s2-11 - x19: u64, - x20: u64, - x21: u64, - x22: u64, - x23: u64, - x24: u64, - x25: u64, - x26: u64, - x27: u64, - nx1: u64, //new return addres -} - -impl Task { - fn new(id: usize) -> Self { - // We initialize each task here and allocate the stack. This is not neccesary, - // we can allocate memory for it later, but it keeps complexity down and lets us focus on more interesting parts - // to do it here. The important part is that once allocated it MUST NOT move in memory. - Task { - id, - stack: vec![0_u8; DEFAULT_STACK_SIZE], - ctx: TaskContext::default(), - state: State::Available, - } - } -} - -impl Runtime { - pub fn new() -> Self { - // This will be our base task, which will be initialized in the `running` state - let base_task = Task { - id: 0, - stack: vec![0_u8; DEFAULT_STACK_SIZE], - ctx: TaskContext::default(), - state: State::Running, - }; - - // We initialize the rest of our tasks. - let mut tasks = vec![base_task]; - let mut available_tasks: Vec = (1..MAX_TASKS).map(|i| Task::new(i)).collect(); - tasks.append(&mut available_tasks); - - Runtime { tasks, current: 0 } - } - - /// This is cheating a bit, but we need a pointer to our Runtime stored so we can call yield on it even if - /// we don't have a reference to it. - pub fn init(&self) { - unsafe { - let r_ptr: *const Runtime = self; - RUNTIME = r_ptr as usize; - } - } - - /// This is where we start running our runtime. If it is our base task, we call yield until - /// it returns false (which means that there are no tasks scheduled) and we are done. - pub fn run(&mut self) { - while self.t_yield() {} - println!("All tasks finished!"); - } - - /// This is our return function. The only place we use this is in our `guard` function. - /// If the current task is not our base task we set its state to Available. It means - /// we're finished with it. Then we yield which will schedule a new task to be run. - fn t_return(&mut self) { - if self.current != 0 { - self.tasks[self.current].state = State::Available; - self.t_yield(); - } - } - - /// This is the heart of our runtime. Here we go through all tasks and see if anyone is in the `Ready` state. - /// If no task is `Ready` we're all done. This is an extremely simple scheduler using only a round-robin algorithm. - /// - /// If we find a task that's ready to be run we change the state of the current task from `Running` to `Ready`. - /// Then we call switch which will save the current context (the old context) and load the new context - /// into the CPU which then resumes based on the context it was just passed. - /// - /// NOITCE: if we comment below `#[inline(never)]`, we can not get the corrent running result - #[inline(never)] - fn t_yield(&mut self) -> bool { - let mut pos = self.current; - while self.tasks[pos].state != State::Ready { - pos += 1; - if pos == self.tasks.len() { - pos = 0; - } - if pos == self.current { - return false; - } - } - - if self.tasks[self.current].state != State::Available { - self.tasks[self.current].state = State::Ready; - } - - self.tasks[pos].state = State::Running; - let old_pos = self.current; - self.current = pos; - - unsafe { - switch(&mut self.tasks[old_pos].ctx, &self.tasks[pos].ctx); - } - - // NOTE: this might look strange and it is. Normally we would just mark this as `unreachable!()` but our compiler - // is too smart for it's own good so it optimized our code away on release builds. Curiously this happens on windows - // and not on linux. This is a common problem in tests so Rust has a `black_box` function in the `test` crate that - // will "pretend" to use a value we give it to prevent the compiler from eliminating code. I'll just do this instead, - // this code will never be run anyways and if it did it would always be `true`. - self.tasks.len() > 0 - } - - /// While `yield` is the logically interesting function I think this the technically most interesting. - /// - /// When we spawn a new task we first check if there are any available tasks (tasks in `Parked` state). - /// If we run out of tasks we panic in this scenario but there are several (better) ways to handle that. - /// We keep things simple for now. - /// - /// When we find an available task we get the stack length and a pointer to our u8 bytearray. - /// - /// The next part we have to use some unsafe functions. First we write an address to our `guard` function - /// that will be called if the function we provide returns. Then we set the address to the function we - /// pass inn. - /// - /// Third, we set the value of `sp` which is the stack pointer to the address of our provided function so we start - /// executing that first when we are scheuled to run. - /// - /// Lastly we set the state as `Ready` which means we have work to do and is ready to do it. - pub fn spawn(&mut self, f: fn()) { - let available = self - .tasks - .iter_mut() - .find(|t| t.state == State::Available) - .expect("no available task."); - - let size = available.stack.len(); - unsafe { - let s_ptr = available.stack.as_mut_ptr().offset(size as isize); - - // make sure our stack itself is 8 byte aligned - it will always - // offset to a lower memory address. Since we know we're at the "high" - // memory address of our allocated space, we know that offsetting to - // a lower one will be a valid address (given that we actually allocated) - // enough space to actually get an aligned pointer in the first place). - let s_ptr = (s_ptr as usize & !7) as *mut u8; - - available.ctx.x1 = guard as u64; //ctx.x1 is old return address - available.ctx.nx1 = f as u64; //ctx.nx2 is new return address - available.ctx.x2 = s_ptr.offset(-32) as u64; //cxt.x2 is sp - } - available.state = State::Ready; - } -} - -/// This is our guard function that we place on top of the stack. All this function does is set the -/// state of our current task and then `yield` which will then schedule a new task to be run. -fn guard() { - unsafe { - let rt_ptr = RUNTIME as *mut Runtime; - (*rt_ptr).t_return(); - }; -} - -/// We know that Runtime is alive the length of the program and that we only access from one core -/// (so no datarace). We yield execution of the current task by dereferencing a pointer to our -/// Runtime and then calling `t_yield` -pub fn yield_task() { - unsafe { - let rt_ptr = RUNTIME as *mut Runtime; - (*rt_ptr).t_yield(); - }; -} - -/// So here is our inline Assembly. As you remember from our first example this is just a bit more elaborate where we first -/// read out the values of all the registers we need and then sets all the register values to the register values we -/// saved when we suspended exceution on the "new" task. -/// -/// This is essentially all we need to do to save and resume execution. -/// -/// Some details about inline assembly. -/// -/// The assembly commands in the string literal is called the assemblt template. It is preceeded by -/// zero or up to four segments indicated by ":": -/// -/// - First ":" we have our output parameters, this parameters that this function will return. -/// - Second ":" we have the input parameters which is our contexts. We only read from the "new" context -/// but we modify the "old" context saving our registers there (see volatile option below) -/// - Third ":" This our clobber list, this is information to the compiler that these registers can't be used freely -/// - Fourth ":" This is options we can pass inn, Rust has 3: "alignstack", "volatile" and "intel" -/// -/// For this to work on windows we need to use "alignstack" where the compiler adds the neccesary padding to -/// make sure our stack is aligned. Since we modify one of our inputs, our assembly has "side effects" -/// therefore we should use the `volatile` option. I **think** this is actually set for us by default -/// when there are no output parameters given (my own assumption after going through the source code) -/// for the `asm` macro, but we should make it explicit anyway. -/// -/// One last important part (it will not work without this) is the #[naked] attribute. Basically this lets us have full -/// control over the stack layout since normal functions has a prologue-and epilogue added by the -/// compiler that will cause trouble for us. We avoid this by marking the funtion as "Naked". -/// For this to work on `release` builds we also need to use the `#[inline(never)] attribute or else -/// the compiler decides to inline this function (curiously this currently only happens on Windows). -/// If the function is inlined we get a curious runtime error where it fails when switching back -/// to as saved context and in general our assembly will not work as expected. -/// -/// see: https://github.com/rust-lang/rfcs/blob/master/text/1201-naked-fns.md -/// see: https://doc.rust-lang.org/nightly/reference/inline-assembly.html -/// see: https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html -#[naked] -#[no_mangle] -unsafe fn switch(old: *mut TaskContext, new: *const TaskContext) { - // a0: _old, a1: _new - asm!( - " - sd x1, 0x00(a0) - sd x2, 0x08(a0) - sd x8, 0x10(a0) - sd x9, 0x18(a0) - sd x18, 0x20(a0) - sd x19, 0x28(a0) - sd x20, 0x30(a0) - sd x21, 0x38(a0) - sd x22, 0x40(a0) - sd x23, 0x48(a0) - sd x24, 0x50(a0) - sd x25, 0x58(a0) - sd x26, 0x60(a0) - sd x27, 0x68(a0) - sd x1, 0x70(a0) - - ld x1, 0x00(a1) - ld x2, 0x08(a1) - ld x8, 0x10(a1) - ld x9, 0x18(a1) - ld x18, 0x20(a1) - ld x19, 0x28(a1) - ld x20, 0x30(a1) - ld x21, 0x38(a1) - ld x22, 0x40(a1) - ld x23, 0x48(a1) - ld x24, 0x50(a1) - ld x25, 0x58(a1) - ld x26, 0x60(a1) - ld x27, 0x68(a1) - ld t0, 0x70(a1) - - jr t0 - ", - options(noreturn) - ); -} - -#[no_mangle] -pub fn main() { - println!("stackful_coroutine begin..."); - println!("TASK 0(Runtime) STARTING"); - let mut runtime = Runtime::new(); - runtime.init(); - runtime.spawn(|| { - println!("TASK 1 STARTING"); - let id = 1; - for i in 0..4 { - println!("task: {} counter: {}", id, i); - yield_task(); - } - println!("TASK 1 FINISHED"); - }); - runtime.spawn(|| { - println!("TASK 2 STARTING"); - let id = 2; - for i in 0..8 { - println!("task: {} counter: {}", id, i); - yield_task(); - } - println!("TASK 2 FINISHED"); - }); - runtime.spawn(|| { - println!("TASK 3 STARTING"); - let id = 3; - for i in 0..12 { - println!("task: {} counter: {}", id, i); - yield_task(); - } - println!("TASK 3 FINISHED"); - }); - runtime.spawn(|| { - println!("TASK 4 STARTING"); - let id = 4; - for i in 0..16 { - println!("task: {} counter: {}", id, i); - yield_task(); - } - println!("TASK 4 FINISHED"); - }); - runtime.run(); - println!("stackful_coroutine PASSED"); - exit(0); -} diff --git a/user/src/bin/ch8b_stackless_coroutine.rs b/user/src/bin/ch8b_stackless_coroutine.rs deleted file mode 100644 index 43aeb2d..0000000 --- a/user/src/bin/ch8b_stackless_coroutine.rs +++ /dev/null @@ -1,129 +0,0 @@ -// https://blog.aloni.org/posts/a-stack-less-rust-coroutine-100-loc/ -// https://github.com/chyyuu/example-coroutine-and-thread/tree/stackless-coroutine-x86 -#![no_std] -#![no_main] - -use core::future::Future; -use core::pin::Pin; -use core::task::{Context, Poll}; -use core::task::{RawWaker, RawWakerVTable, Waker}; - -extern crate alloc; -use alloc::collections::VecDeque; - -use alloc::boxed::Box; - -#[macro_use] -extern crate user_lib; - -enum State { - Halted, - Running, -} - -struct Task { - state: State, -} - -impl Task { - fn waiter<'a>(&'a mut self) -> Waiter<'a> { - Waiter { task: self } - } -} - -struct Waiter<'a> { - task: &'a mut Task, -} - -impl<'a> Future for Waiter<'a> { - type Output = (); - - fn poll(mut self: Pin<&mut Self>, _cx: &mut Context) -> Poll { - match self.task.state { - State::Halted => { - self.task.state = State::Running; - Poll::Ready(()) - } - State::Running => { - self.task.state = State::Halted; - Poll::Pending - } - } - } -} - -struct Executor { - tasks: VecDeque>>>, -} - -impl Executor { - fn new() -> Self { - Executor { - tasks: VecDeque::new(), - } - } - - fn push(&mut self, closure: C) - where - F: Future + 'static, - C: FnOnce(Task) -> F, - { - let task = Task { - state: State::Running, - }; - self.tasks.push_back(Box::pin(closure(task))); - } - - fn run(&mut self) { - let waker = create_waker(); - let mut context = Context::from_waker(&waker); - - while let Some(mut task) = self.tasks.pop_front() { - match task.as_mut().poll(&mut context) { - Poll::Pending => { - self.tasks.push_back(task); - } - Poll::Ready(()) => {} - } - } - } -} - -pub fn create_waker() -> Waker { - // Safety: The waker points to a vtable with functions that do nothing. Doing - // nothing is memory-safe. - unsafe { Waker::from_raw(RAW_WAKER) } -} - -const RAW_WAKER: RawWaker = RawWaker::new(core::ptr::null(), &VTABLE); -const VTABLE: RawWakerVTable = RawWakerVTable::new(clone, wake, wake_by_ref, drop); - -unsafe fn clone(_: *const ()) -> RawWaker { - RAW_WAKER -} -unsafe fn wake(_: *const ()) {} -unsafe fn wake_by_ref(_: *const ()) {} -unsafe fn drop(_: *const ()) {} - -#[no_mangle] -pub fn main() -> i32 { - println!("stackless coroutine Begin.."); - let mut exec = Executor::new(); - println!(" Create futures"); - for instance in 1..=3 { - exec.push(move |mut task| async move { - println!(" Task {}: begin state", instance); - task.waiter().await; - println!(" Task {}: next state", instance); - task.waiter().await; - println!(" Task {}: end state", instance); - }); - } - - println!(" Running"); - exec.run(); - println!(" Done"); - println!("stackless coroutine PASSED"); - - 0 -} diff --git a/user/src/bin/ch8b_sync_sem.rs b/user/src/bin/ch8b_sync_sem.rs deleted file mode 100644 index 3c6c575..0000000 --- a/user/src/bin/ch8b_sync_sem.rs +++ /dev/null @@ -1,45 +0,0 @@ -#![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_blocking, thread_create, waittid}; - -const SEM_SYNC: usize = 0; - -unsafe fn first() -> ! { - sleep_blocking(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/ch8b_test_condvar.rs b/user/src/bin/ch8b_test_condvar.rs deleted file mode 100644 index 26029eb..0000000 --- a/user/src/bin/ch8b_test_condvar.rs +++ /dev/null @@ -1,59 +0,0 @@ -#![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_blocking, thread_create, waittid}; - -static mut A: usize = 0; - -const CONDVAR_ID: usize = 0; -const MUTEX_ID: usize = 0; - -unsafe fn first() -> ! { - sleep_blocking(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/ch8b_threads.rs b/user/src/bin/ch8b_threads.rs deleted file mode 100644 index 0db8292..0000000 --- a/user/src/bin/ch8b_threads.rs +++ /dev/null @@ -1,62 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -extern crate alloc; - -use alloc::vec; -use user_lib::{exit, thread_create, waittid}; - -pub fn thread_a() -> ! { - let mut t = 2i32; - for _ in 0..1000 { - print!("a"); - for __ in 0..5000 { - t = t * t % 10007; - } - } - println!("{}", t); - exit(1) -} - -pub fn thread_b() -> ! { - let mut t = 2i32; - for _ in 0..1000 { - print!("b"); - for __ in 0..5000 { - t = t * t % 10007; - } - } - println!("{}", t); - exit(2) -} - -pub fn thread_c() -> ! { - let mut t = 2i32; - for _ in 0..1000 { - print!("c"); - for __ in 0..5000 { - t = t * t % 10007; - } - } - println!("{}", t); - exit(3) -} - -#[no_mangle] -pub fn main() -> i32 { - 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); - assert_eq!(*tid, exit_code); - } - println!("main thread exited."); - println!("threads test passed!"); - 0 -} diff --git a/user/src/bin/ch8b_threads_arg.rs b/user/src/bin/ch8b_threads_arg.rs deleted file mode 100644 index 2c0de19..0000000 --- a/user/src/bin/ch8b_threads_arg.rs +++ /dev/null @@ -1,45 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; -extern crate alloc; - -use alloc::vec::Vec; -use user_lib::{exit, thread_create, waittid}; - -struct Argument { - pub ch: char, - pub rc: i32, -} - -fn thread_print(arg: *const Argument) -> ! { - let arg = unsafe { &*arg }; - for _ in 0..1000 { - print!("{}", arg.ch); - } - exit(arg.rc) -} - -#[no_mangle] -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 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); - println!("thread#{} exited with code {}", tid, exit_code); - } - println!("main thread exited."); - println!("threads with arg test passed!"); - 0 -} diff --git a/user/src/bin/ch8b_user_shell.rs b/user/src/bin/ch8b_user_shell.rs deleted file mode 100644 index 4288248..0000000 --- a/user/src/bin/ch8b_user_shell.rs +++ /dev/null @@ -1,214 +0,0 @@ -#![no_std] -#![no_main] -#![allow(clippy::println_empty_string)] - -extern crate alloc; - -#[macro_use] -extern crate user_lib; - -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::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!("{}", LINE_START); - loop { - let c = getchar(); - match c { - LF | CR => { - println!(""); - if !line.is_empty() { - let splited: Vec<_> = line.as_str().split('|').collect(); - let process_arguments_list: Vec<_> = splited - .iter() - .map(|&cmd| ProcessArguments::new(cmd)) - .collect(); - 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 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; - 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!("{}", LINE_START); - } - BS | DL => { - if !line.is_empty() { - print!("{}", BS as char); - print!(" "); - print!("{}", BS as char); - line.pop(); - } - } - _ => { - print!("{}", c as char); - line.push(c as char); - } - } - } -} diff --git a/user/src/console.rs b/user/src/console.rs deleted file mode 100644 index 6d6d1f3..0000000 --- a/user/src/console.rs +++ /dev/null @@ -1,75 +0,0 @@ -use alloc::collections::vec_deque::VecDeque; -use alloc::sync::Arc; -use core::fmt::{self, Write}; -use spin::mutex::Mutex; - -pub const STDIN: usize = 0; -pub const STDOUT: usize = 1; - -const CONSOLE_BUFFER_SIZE: usize = 256 * 10; - -use super::{read, write}; -use lazy_static::*; - -struct ConsoleBuffer(VecDeque); - -lazy_static! { - static ref CONSOLE_BUFFER: Arc> = { - let buffer = VecDeque::::with_capacity(CONSOLE_BUFFER_SIZE); - Arc::new(Mutex::new(ConsoleBuffer(buffer))) - }; -} - -impl ConsoleBuffer { - fn flush(&mut self) -> isize { - let s: &[u8] = self.0.make_contiguous(); - let ret = write(STDOUT, s); - self.0.clear(); - ret - } -} - -impl Write for ConsoleBuffer { - fn write_str(&mut self, s: &str) -> fmt::Result { - for c in s.as_bytes().iter() { - self.0.push_back(*c); - if (*c == b'\n' || self.0.len() == CONSOLE_BUFFER_SIZE) && -1 == self.flush() { - return Err(fmt::Error); - } - } - Ok(()) - } -} - -#[allow(unused)] -pub fn print(args: fmt::Arguments) { - let mut buf = CONSOLE_BUFFER.lock(); - // buf.write_fmt(args).unwrap(); - // BUG FIX: 关闭 stdout 后,本函数不能触发 panic,否则会造成死锁 - buf.write_fmt(args); -} - -#[macro_export] -macro_rules! print { - ($fmt: literal $(, $($arg: tt)+)?) => { - $crate::console::print(format_args!($fmt $(, $($arg)+)?)); - } -} - -#[macro_export] -macro_rules! println { - ($fmt: literal $(, $($arg: tt)+)?) => { - $crate::console::print(format_args!(concat!($fmt, "\n") $(, $($arg)+)?)); - } -} - -pub fn getchar() -> u8 { - let mut c = [0u8; 1]; - read(STDIN, &mut c); - c[0] -} - -pub fn flush() { - let mut buf = CONSOLE_BUFFER.lock(); - buf.flush(); -} diff --git a/user/src/lang_items.rs b/user/src/lang_items.rs deleted file mode 100644 index 2d81a1d..0000000 --- a/user/src/lang_items.rs +++ /dev/null @@ -1,17 +0,0 @@ -use crate::exit; - -#[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 - ); - } else { - println!("Panicked: {}", err); - } - exit(-1); -} diff --git a/user/src/lib.rs b/user/src/lib.rs deleted file mode 100644 index cee97ee..0000000 --- a/user/src/lib.rs +++ /dev/null @@ -1,359 +0,0 @@ -#![no_std] -#![feature(linkage)] -#![feature(panic_info_message)] -#![feature(alloc_error_handler)] - -#[macro_use] -pub mod console; -mod lang_items; -mod syscall; - -extern crate alloc; -extern crate core; -#[macro_use] -extern crate bitflags; - -use alloc::vec::Vec; -use buddy_system_allocator::LockedHeap; -pub use console::{flush, STDIN, STDOUT}; -pub use syscall::*; - -const USER_HEAP_SIZE: usize = 16384; - -static mut HEAP_SPACE: [u8; USER_HEAP_SIZE] = [0; USER_HEAP_SIZE]; - -#[global_allocator] -static HEAP: LockedHeap = LockedHeap::empty(); - -#[alloc_error_handler] -pub fn handle_alloc_error(layout: core::alloc::Layout) -> ! { - panic!("Heap allocation error, layout = {:?}", layout); -} - -fn clear_bss() { - extern "C" { - fn start_bss(); - fn end_bss(); - } - unsafe { - core::slice::from_raw_parts_mut( - start_bss as usize as *mut u8, - end_bss as usize - start_bss as usize, - ) - .fill(0); - } -} - -#[no_mangle] -#[link_section = ".text.entry"] -pub extern "C" fn _start(argc: usize, argv: usize) -> ! { - clear_bss(); - unsafe { - HEAP.lock() - .init(HEAP_SPACE.as_ptr() as usize, USER_HEAP_SIZE); - } - 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(); - v.push( - core::str::from_utf8(unsafe { - core::slice::from_raw_parts(str_start as *const u8, len) - }) - .unwrap(), - ); - } - exit(main(argc, v.as_slice())); -} - -#[linkage = "weak"] -#[no_mangle] -fn main(_argc: usize, _argv: &[&str]) -> i32 { - panic!("Cannot find main!"); -} - -bitflags! { - pub struct OpenFlags: u32 { - const RDONLY = 0; - const WRONLY = 1 << 0; - const RDWR = 1 << 1; - const CREATE = 1 << 9; - const TRUNC = 1 << 10; - } -} - -#[repr(C)] -#[derive(Debug, Default)] -pub struct TimeVal { - pub sec: usize, - pub usec: usize, -} - -impl TimeVal { - pub fn new() -> Self { - Self::default() - } -} - -#[derive(Copy, Clone, PartialEq, Debug)] -pub enum TaskStatus { - UnInit, - Ready, - Running, - Exited, -} - -#[derive(Copy, Clone, Debug)] -pub struct SyscallInfo { - pub id: usize, - pub times: usize, -} - -const MAX_SYSCALL_NUM: usize = 500; - -#[derive(Debug)] -pub struct TaskInfo { - pub status: TaskStatus, - pub syscall_times: [u32; MAX_SYSCALL_NUM], - pub time: usize, -} - -impl TaskInfo { - pub fn new() -> Self { - TaskInfo { - status: TaskStatus::UnInit, - syscall_times: [0; MAX_SYSCALL_NUM], - time: 0, - } - } -} - -#[repr(C)] -#[derive(Debug)] -pub struct Stat { - /// ID of device containing file - pub dev: u64, - /// inode number - pub ino: u64, - /// file type and mode - pub mode: StatMode, - /// number of hard links - pub nlink: u32, - /// unused pad - pad: [u64; 7], -} - -impl Stat { - pub fn new() -> Self { - Stat { - dev: 0, - ino: 0, - mode: StatMode::NULL, - nlink: 0, - pad: [0; 7], - } - } -} - -impl Default for Stat { - fn default() -> Self { - Self::new() - } -} - -bitflags! { - pub struct StatMode: u32 { - const NULL = 0; - /// directory - const DIR = 0o040000; - /// ordinary regular file - const FILE = 0o100000; - } -} - -const AT_FDCWD: isize = -100; - -pub fn open(path: &str, flags: OpenFlags) -> isize { - sys_openat(AT_FDCWD as usize, path, flags.bits, OpenFlags::RDWR.bits) -} - -pub fn close(fd: usize) -> isize { - if fd == STDOUT { - console::flush(); - } - sys_close(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 link(old_path: &str, new_path: &str) -> isize { - sys_linkat(AT_FDCWD as usize, old_path, AT_FDCWD as usize, new_path, 0) -} - -pub fn unlink(path: &str) -> isize { - sys_unlinkat(AT_FDCWD as usize, path, 0) -} - -pub fn fstat(fd: usize, st: &Stat) -> isize { - sys_fstat(fd, st) -} - -pub fn mail_read(buf: &mut [u8]) -> isize { - sys_mail_read(buf) -} - -pub fn mail_write(pid: usize, buf: &[u8]) -> isize { - sys_mail_write(pid, buf) -} - -pub fn exit(exit_code: i32) -> ! { - console::flush(); - sys_exit(exit_code); -} - -pub fn yield_() -> isize { - sys_yield() -} - -pub fn get_time() -> isize { - let time = TimeVal::new(); - match sys_get_time(&time, 0) { - 0 => ((time.sec & 0xffff) * 1000 + time.usec / 1000) as isize, - _ => -1, - } -} - -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 set_priority(prio: isize) -> isize { - sys_set_priority(prio) -} - -pub fn wait(exit_code: &mut i32) -> isize { - loop { - match sys_waitpid(-1, exit_code as *mut _) { - -2 => { - sys_yield(); - } - n => { - return n; - } - } - } -} - -pub fn waitpid(pid: usize, exit_code: &mut i32) -> isize { - loop { - match sys_waitpid(pid as isize, exit_code as *mut _) { - -2 => { - sys_yield(); - } - n => { - return n; - } - } - } -} - -pub fn sleep_blocking(sleep_ms: usize) { - sys_sleep(sleep_ms); -} - -pub fn sleep(period_ms: usize) { - let start = get_time(); - while get_time() < start + period_ms as isize { - sys_yield(); - } -} -pub fn mmap(start: usize, len: usize, prot: usize) -> isize { - sys_mmap(start, len, prot) -} - -pub fn munmap(start: usize, len: usize) -> isize { - sys_munmap(start, len) -} - -pub fn spawn(path: &str) -> isize { - sys_spawn(path) -} - -pub fn dup(fd: usize) -> isize { - sys_dup(fd) -} -pub fn pipe(pipe_fd: &mut [usize]) -> isize { - sys_pipe(pipe_fd) -} - -pub fn task_info(info: &TaskInfo) -> isize { - sys_task_info(info) -} - -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_(); - } - 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) -> isize { - 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) -} -pub fn semaphore_up(sem_id: usize) { - sys_semaphore_up(sem_id); -} -pub fn enable_deadlock_detect(enabled: bool) -> isize { - sys_enable_deadlock_detect(enabled as usize) -} -pub fn semaphore_down(sem_id: usize) -> isize { - 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/linker.ld b/user/src/linker.ld deleted file mode 100644 index f3f996e..0000000 --- a/user/src/linker.ld +++ /dev/null @@ -1,33 +0,0 @@ -OUTPUT_ARCH(riscv) -ENTRY(_start) - -BASE_ADDRESS = 0x0; - -SECTIONS -{ - . = BASE_ADDRESS; - .text : { - *(.text.entry) - *(.text .text.*) - } - . = ALIGN(4K); - .rodata : { - *(.rodata .rodata.*) - *(.srodata .srodata.*) - } - . = ALIGN(4K); - .data : { - *(.data .data.*) - *(.sdata .sdata.*) - } - .bss : { - start_bss = .; - *(.bss .bss.*) - *(.sbss .sbss.*) - end_bss = .; - } - /DISCARD/ : { - *(.eh_frame) - *(.debug*) - } -} \ No newline at end of file diff --git a/user/src/syscall.rs b/user/src/syscall.rs deleted file mode 100644 index f671438..0000000 --- a/user/src/syscall.rs +++ /dev/null @@ -1,258 +0,0 @@ -use crate::TaskInfo; - -use super::{Stat, TimeVal}; - -pub const SYSCALL_OPENAT: usize = 56; -pub const SYSCALL_CLOSE: usize = 57; -pub const SYSCALL_READ: usize = 63; -pub const SYSCALL_WRITE: usize = 64; -pub const SYSCALL_UNLINKAT: usize = 35; -pub const SYSCALL_LINKAT: usize = 37; -pub const SYSCALL_FSTAT: usize = 80; -pub const SYSCALL_EXIT: usize = 93; -pub const SYSCALL_SLEEP: usize = 101; -pub const SYSCALL_YIELD: usize = 124; -pub const SYSCALL_GETTIMEOFDAY: usize = 169; -pub const SYSCALL_GETPID: usize = 172; -pub const SYSCALL_GETTID: usize = 178; -pub const SYSCALL_FORK: usize = 220; -pub const SYSCALL_EXEC: usize = 221; -pub const SYSCALL_WAITPID: usize = 260; -pub const SYSCALL_SET_PRIORITY: usize = 140; -pub const SYSCALL_MUNMAP: usize = 215; -pub const SYSCALL_MMAP: usize = 222; -pub const SYSCALL_SPAWN: usize = 400; -pub const SYSCALL_MAIL_READ: usize = 401; -pub const SYSCALL_MAIL_WRITE: usize = 402; -pub const SYSCALL_DUP: usize = 24; -pub const SYSCALL_PIPE: usize = 59; -pub const SYSCALL_TASK_INFO: usize = 410; -pub const SYSCALL_THREAD_CREATE: usize = 460; -pub const SYSCALL_WAITTID: usize = 462; -pub const SYSCALL_MUTEX_CREATE: usize = 463; -pub const SYSCALL_MUTEX_LOCK: usize = 464; -pub const SYSCALL_MUTEX_UNLOCK: usize = 466; -pub const SYSCALL_SEMAPHORE_CREATE: usize = 467; -pub const SYSCALL_SEMAPHORE_UP: usize = 468; -pub const SYSCALL_ENABLE_DEADLOCK_DETECT: usize = 469; -pub const SYSCALL_SEMAPHORE_DOWN: usize = 470; -pub const SYSCALL_CONDVAR_CREATE: usize = 471; -pub const SYSCALL_CONDVAR_SIGNAL: usize = 472; -pub const SYSCALL_CONDVAR_WAIT: usize = 473; - -pub fn syscall(id: usize, args: [usize; 3]) -> isize { - let mut ret: isize; - unsafe { - core::arch::asm!( - "ecall", - inlateout("x10") args[0] => ret, - in("x11") args[1], - in("x12") args[2], - in("x17") id - ); - } - ret -} - -pub fn syscall6(id: usize, args: [usize; 6]) -> isize { - let mut ret: isize; - unsafe { - core::arch::asm!("ecall", - inlateout("x10") args[0] => ret, - in("x11") args[1], - in("x12") args[2], - in("x13") args[3], - in("x14") args[4], - in("x15") args[5], - in("x17") id - ); - } - ret -} - -pub fn sys_openat(dirfd: usize, path: &str, flags: u32, mode: u32) -> isize { - syscall6( - SYSCALL_OPENAT, - [ - dirfd, - path.as_ptr() as usize, - flags as usize, - mode as usize, - 0, - 0, - ], - ) -} - -pub fn sys_close(fd: usize) -> isize { - syscall(SYSCALL_CLOSE, [fd, 0, 0]) -} - -pub fn sys_read(fd: usize, buffer: &mut [u8]) -> isize { - syscall( - SYSCALL_READ, - [fd, buffer.as_mut_ptr() as usize, buffer.len()], - ) -} - -pub fn sys_write(fd: usize, buffer: &[u8]) -> isize { - syscall(SYSCALL_WRITE, [fd, buffer.as_ptr() as usize, buffer.len()]) -} - -pub fn sys_linkat( - old_dirfd: usize, - old_path: &str, - new_dirfd: usize, - new_path: &str, - flags: usize, -) -> isize { - syscall6( - SYSCALL_LINKAT, - [ - old_dirfd, - old_path.as_ptr() as usize, - new_dirfd, - new_path.as_ptr() as usize, - flags, - 0, - ], - ) -} - -pub fn sys_unlinkat(dirfd: usize, path: &str, flags: usize) -> isize { - syscall(SYSCALL_UNLINKAT, [dirfd, path.as_ptr() as usize, flags]) -} - -pub fn sys_fstat(fd: usize, st: &Stat) -> isize { - syscall(SYSCALL_FSTAT, [fd, st as *const _ as usize, 0]) -} - -pub fn sys_mail_read(buffer: &mut [u8]) -> isize { - syscall( - SYSCALL_MAIL_READ, - [buffer.as_ptr() as usize, buffer.len(), 0], - ) -} - -pub fn sys_mail_write(pid: usize, buffer: &[u8]) -> isize { - syscall( - SYSCALL_MAIL_WRITE, - [pid, buffer.as_ptr() as usize, buffer.len()], - ) -} - -pub fn sys_exit(exit_code: i32) -> ! { - syscall(SYSCALL_EXIT, [exit_code as usize, 0, 0]); - panic!("sys_exit never returns!"); -} - -pub fn sys_sleep(sleep_ms: usize) -> isize { - syscall(SYSCALL_SLEEP, [sleep_ms, 0, 0]) -} - -pub fn sys_yield() -> isize { - syscall(SYSCALL_YIELD, [0, 0, 0]) -} - -pub fn sys_get_time(time: &TimeVal, tz: usize) -> isize { - syscall(SYSCALL_GETTIMEOFDAY, [time as *const _ as usize, tz, 0]) -} - -pub fn sys_getpid() -> isize { - syscall(SYSCALL_GETPID, [0, 0, 0]) -} - -pub fn sys_fork() -> isize { - syscall(SYSCALL_FORK, [0, 0, 0]) -} - -pub fn sys_exec(path: &str, args: &[*const u8]) -> isize { - syscall( - SYSCALL_EXEC, - [path.as_ptr() as usize, args.as_ptr() as usize, 0], - ) -} - -pub fn sys_waitpid(pid: isize, xstatus: *mut i32) -> isize { - syscall(SYSCALL_WAITPID, [pid as usize, xstatus as usize, 0]) -} - -pub fn sys_set_priority(prio: isize) -> isize { - syscall(SYSCALL_SET_PRIORITY, [prio as usize, 0, 0]) -} - -pub fn sys_mmap(start: usize, len: usize, prot: usize) -> isize { - syscall(SYSCALL_MMAP, [start, len, prot]) -} - -pub fn sys_munmap(start: usize, len: usize) -> isize { - syscall(SYSCALL_MUNMAP, [start, len, 0]) -} - -pub fn sys_spawn(path: &str) -> isize { - syscall(SYSCALL_SPAWN, [path.as_ptr() as usize, 0, 0]) -} - -pub fn sys_dup(fd: usize) -> isize { - syscall(SYSCALL_DUP, [fd, 0, 0]) -} - -pub fn sys_pipe(pipe: &mut [usize]) -> isize { - syscall(SYSCALL_PIPE, [pipe.as_mut_ptr() as usize, 0, 0]) -} - -pub fn sys_task_info(info: &TaskInfo) -> isize { - syscall(SYSCALL_TASK_INFO, [info as *const _ as usize, 0, 0]) -} - -pub fn sys_thread_create(entry: usize, arg: usize) -> isize { - syscall(SYSCALL_THREAD_CREATE, [entry, arg, 0]) -} - -pub fn sys_gettid() -> isize { - syscall(SYSCALL_GETTID, [0; 3]) -} - -pub fn sys_waittid(tid: usize) -> isize { - syscall(SYSCALL_WAITTID, [tid, 0, 0]) -} - -pub fn sys_mutex_create(blocking: bool) -> isize { - syscall(SYSCALL_MUTEX_CREATE, [blocking as usize, 0, 0]) -} - -pub fn sys_mutex_lock(id: usize) -> isize { - syscall(SYSCALL_MUTEX_LOCK, [id, 0, 0]) -} - -pub fn sys_mutex_unlock(id: usize) -> isize { - syscall(SYSCALL_MUTEX_UNLOCK, [id, 0, 0]) -} - -pub fn sys_semaphore_create(res_count: usize) -> isize { - syscall(SYSCALL_SEMAPHORE_CREATE, [res_count, 0, 0]) -} - -pub fn sys_semaphore_up(sem_id: usize) -> isize { - syscall(SYSCALL_SEMAPHORE_UP, [sem_id, 0, 0]) -} - -pub fn sys_enable_deadlock_detect(enabled: usize) -> isize { - syscall(SYSCALL_ENABLE_DEADLOCK_DETECT, [enabled, 0, 0]) -} - -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]) -} diff --git a/wechat1016.png b/wechat1016.png deleted file mode 100644 index a5946b7..0000000 Binary files a/wechat1016.png and /dev/null differ