Merge branch 'main' into main
This commit is contained in:
commit
88a4a0ad11
22 changed files with 98 additions and 61 deletions
21
.devcontainer/devcontainer.json
Normal file
21
.devcontainer/devcontainer.json
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"name": "rcore-tutorial-v3",
|
||||||
|
"build": {
|
||||||
|
"dockerfile": "../Dockerfile",
|
||||||
|
"args": {
|
||||||
|
"QEMU_VERSION": "7.0.0",
|
||||||
|
"DEBIAN_FRONTEND": "noninteractive",
|
||||||
|
"GDB_VERSION": "14.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"postCreateCommand": "rustup show",
|
||||||
|
"customizations": {
|
||||||
|
"vscode": {
|
||||||
|
"extensions": [
|
||||||
|
"rust-lang.rust-analyzer",
|
||||||
|
"ms-vscode.cpptools",
|
||||||
|
"tamasfe.even-better-toml"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
2
.github/workflows/doc-and-test.yml
vendored
2
.github/workflows/doc-and-test.yml
vendored
|
@ -4,7 +4,7 @@ on: [push]
|
||||||
|
|
||||||
env:
|
env:
|
||||||
CARGO_TERM_COLOR: always
|
CARGO_TERM_COLOR: always
|
||||||
rust_toolchain: nightly-2023-10-09
|
rust_toolchain: nightly-2024-01-18
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-doc:
|
build-doc:
|
||||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,6 +1,7 @@
|
||||||
.*/*
|
.*/*
|
||||||
!.github/*
|
!.github/*
|
||||||
!.vscode/settings.json
|
!.vscode/settings.json
|
||||||
|
!.devcontainer/devcontainer.json
|
||||||
|
|
||||||
**/target/
|
**/target/
|
||||||
**/Cargo.lock
|
**/Cargo.lock
|
||||||
|
|
26
Dockerfile
26
Dockerfile
|
@ -1,6 +1,6 @@
|
||||||
# syntax=docker/dockerfile:1
|
# syntax=docker/dockerfile:1
|
||||||
|
|
||||||
# Stage 1 Set up QEMU RISC-V
|
# Stage 1 Build QEMU
|
||||||
# - https://www.qemu.org/download/
|
# - https://www.qemu.org/download/
|
||||||
# - https://wiki.qemu.org/Hosts/Linux#Building_QEMU_for_Linux
|
# - https://wiki.qemu.org/Hosts/Linux#Building_QEMU_for_Linux
|
||||||
# - https://wiki.qemu.org/Documentation/Platforms/RISCV
|
# - https://wiki.qemu.org/Documentation/Platforms/RISCV
|
||||||
|
@ -20,30 +20,34 @@ RUN wget https://download.qemu.org/qemu-${QEMU_VERSION}.tar.xz && \
|
||||||
make -j$(nproc) && \
|
make -j$(nproc) && \
|
||||||
make install
|
make install
|
||||||
|
|
||||||
# Stage 2 Lab Environment
|
# Stage 2 Set Lab Environment
|
||||||
FROM ubuntu:20.04 as build
|
FROM ubuntu:20.04 as build
|
||||||
|
|
||||||
WORKDIR /tmp
|
WORKDIR /tmp
|
||||||
|
|
||||||
# 0. Install general tools
|
# 2.0. Install general tools
|
||||||
RUN sed -i 's/archive.ubuntu.com/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list && \
|
RUN sed -i 's/archive.ubuntu.com/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list && \
|
||||||
apt-get update && \
|
apt-get update && \
|
||||||
DEBIAN_FRONTEND=noninteractive apt-get install -y jq curl git python3 wget build-essential \
|
DEBIAN_FRONTEND=noninteractive apt-get install -y jq curl git python3 wget build-essential \
|
||||||
# qemu dependency
|
# qemu dependency
|
||||||
libglib2.0-0 libfdt1 libpixman-1-0 zlib1g
|
libglib2.0-0 libfdt1 libpixman-1-0 zlib1g \
|
||||||
|
# gdb
|
||||||
|
gdb-multiarch
|
||||||
|
|
||||||
# 1. Copy qemu
|
# 2.1. Copy qemu
|
||||||
COPY --from=build_qemu /usr/local/bin/* /usr/local/bin
|
COPY --from=build_qemu /usr/local/bin/* /usr/local/bin
|
||||||
|
|
||||||
# 2. Install Rust
|
# 2.2. Install Rust
|
||||||
# - https://www.rust-lang.org/tools/install
|
# - https://www.rust-lang.org/tools/install
|
||||||
ENV RUSTUP_HOME=/usr/local/rustup \
|
ENV RUSTUP_HOME=/usr/local/rustup \
|
||||||
CARGO_HOME=/usr/local/cargo \
|
CARGO_HOME=/usr/local/cargo \
|
||||||
PATH=/usr/local/cargo/bin:$PATH
|
PATH=/usr/local/cargo/bin:$PATH \
|
||||||
|
RUSTUP_DIST_SERVER=https://mirrors.ustc.edu.cn/rust-static \
|
||||||
|
RUSTUP_UPDATE_ROOT=https://mirrors.ustc.edu.cn/rust-static/rustup
|
||||||
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | \
|
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | \
|
||||||
sh -s -- -y --no-modify-path --profile minimal --default-toolchain nightly
|
sh -s -- -y --no-modify-path --profile minimal --default-toolchain nightly
|
||||||
|
|
||||||
# 3. Build env for labs
|
# 2.3. Build env for labs
|
||||||
# See os/Makefile `env:` for example.
|
# See os/Makefile `env:` for example.
|
||||||
# This avoids having to wait for these steps each time using a new container.
|
# This avoids having to wait for these steps each time using a new container.
|
||||||
COPY rust-toolchain.toml rust-toolchain.toml
|
COPY rust-toolchain.toml rust-toolchain.toml
|
||||||
|
@ -54,10 +58,14 @@ RUN rustup target add riscv64gc-unknown-none-elf && \
|
||||||
rustup install $RUST_VERSION && \
|
rustup install $RUST_VERSION && \
|
||||||
rustup component add --toolchain $RUST_VERSION $Components
|
rustup component add --toolchain $RUST_VERSION $Components
|
||||||
|
|
||||||
|
# 2.4. Set GDB
|
||||||
|
RUN ln -s /usr/bin/gdb-multiarch /usr/bin/riscv64-unknown-elf-gdb
|
||||||
|
|
||||||
# Stage 3 Sanity checking
|
# Stage 3 Sanity checking
|
||||||
FROM build as test
|
FROM build as test
|
||||||
RUN qemu-system-riscv64 --version && \
|
RUN qemu-system-riscv64 --version && \
|
||||||
qemu-riscv64 --version && \
|
qemu-riscv64 --version && \
|
||||||
rustup --version && \
|
rustup --version && \
|
||||||
cargo --version && \
|
cargo --version && \
|
||||||
rustc --version
|
rustc --version && \
|
||||||
|
riscv64-unknown-elf-gdb --version
|
|
@ -1,4 +1,5 @@
|
||||||
pub const CLOCK_FREQ: usize = 12500000;
|
pub const CLOCK_FREQ: usize = 12500000;
|
||||||
|
pub const MEMORY_END: usize = 0x8800_0000;
|
||||||
|
|
||||||
pub const MMIO: &[(usize, usize)] = &[
|
pub const MMIO: &[(usize, usize)] = &[
|
||||||
(0x0010_0000, 0x00_2000), // VIRT_TEST/RTC in virt machine
|
(0x0010_0000, 0x00_2000), // VIRT_TEST/RTC in virt machine
|
||||||
|
|
|
@ -3,11 +3,10 @@
|
||||||
pub const USER_STACK_SIZE: usize = 4096 * 2;
|
pub const USER_STACK_SIZE: usize = 4096 * 2;
|
||||||
pub const KERNEL_STACK_SIZE: usize = 4096 * 2;
|
pub const KERNEL_STACK_SIZE: usize = 4096 * 2;
|
||||||
pub const KERNEL_HEAP_SIZE: usize = 0x100_0000;
|
pub const KERNEL_HEAP_SIZE: usize = 0x100_0000;
|
||||||
pub const MEMORY_END: usize = 0x88000000;
|
|
||||||
pub const PAGE_SIZE: usize = 0x1000;
|
pub const PAGE_SIZE: usize = 0x1000;
|
||||||
pub const PAGE_SIZE_BITS: usize = 0xc;
|
pub const PAGE_SIZE_BITS: usize = 0xc;
|
||||||
|
|
||||||
pub const TRAMPOLINE: usize = usize::MAX - PAGE_SIZE + 1;
|
pub const TRAMPOLINE: usize = usize::MAX - PAGE_SIZE + 1;
|
||||||
pub const TRAP_CONTEXT_BASE: usize = TRAMPOLINE - PAGE_SIZE;
|
pub const TRAP_CONTEXT_BASE: usize = TRAMPOLINE - PAGE_SIZE;
|
||||||
|
|
||||||
pub use crate::board::{CLOCK_FREQ, MMIO};
|
pub use crate::board::{CLOCK_FREQ, MEMORY_END, MMIO};
|
||||||
|
|
|
@ -8,7 +8,6 @@ pub mod plic;
|
||||||
|
|
||||||
pub use block::BLOCK_DEVICE;
|
pub use block::BLOCK_DEVICE;
|
||||||
pub use bus::*;
|
pub use bus::*;
|
||||||
pub use chardev::UART;
|
|
||||||
pub use gpu::*;
|
pub use gpu::*;
|
||||||
pub use input::*;
|
pub use input::*;
|
||||||
pub use net::*;
|
pub use net::*;
|
||||||
|
|
|
@ -11,6 +11,6 @@ pub trait File: Send + Sync {
|
||||||
fn write(&self, buf: UserBuffer) -> usize;
|
fn write(&self, buf: UserBuffer) -> usize;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use inode::{list_apps, open_file, OSInode, OpenFlags, ROOT_INODE};
|
pub use inode::{list_apps, open_file, OpenFlags};
|
||||||
pub use pipe::{make_pipe, Pipe};
|
pub use pipe::make_pipe;
|
||||||
pub use stdio::{Stdin, Stdout};
|
pub use stdio::{Stdin, Stdout};
|
||||||
|
|
|
@ -7,12 +7,11 @@ mod page_table;
|
||||||
pub use address::VPNRange;
|
pub use address::VPNRange;
|
||||||
pub use address::{PhysAddr, PhysPageNum, StepByOne, VirtAddr, VirtPageNum};
|
pub use address::{PhysAddr, PhysPageNum, StepByOne, VirtAddr, VirtPageNum};
|
||||||
pub use frame_allocator::{frame_alloc, frame_alloc_more, frame_dealloc, FrameTracker};
|
pub use frame_allocator::{frame_alloc, frame_alloc_more, frame_dealloc, FrameTracker};
|
||||||
pub use memory_set::remap_test;
|
|
||||||
pub use memory_set::{kernel_token, MapArea, MapPermission, MapType, MemorySet, KERNEL_SPACE};
|
pub use memory_set::{kernel_token, MapArea, MapPermission, MapType, MemorySet, KERNEL_SPACE};
|
||||||
use page_table::PTEFlags;
|
use page_table::PTEFlags;
|
||||||
pub use page_table::{
|
pub use page_table::{
|
||||||
translated_byte_buffer, translated_ref, translated_refmut, translated_str, PageTable,
|
translated_byte_buffer, translated_ref, translated_refmut, translated_str, PageTable,
|
||||||
PageTableEntry, UserBuffer, UserBufferIterator,
|
PageTableEntry, UserBuffer,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn init() {
|
pub fn init() {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
[toolchain]
|
[toolchain]
|
||||||
profile = "minimal"
|
profile = "minimal"
|
||||||
# use the nightly version of the last stable toolchain, see <https://forge.rust-lang.org/>
|
# use the nightly version of the last stable toolchain, see <https://forge.rust-lang.org/>
|
||||||
channel = "nightly-2023-10-09"
|
channel = "nightly-2024-01-18"
|
||||||
components = ["rust-src", "llvm-tools", "rustfmt", "clippy"]
|
components = ["rust-src", "llvm-tools", "rustfmt", "clippy"]
|
||||||
|
targets = ["riscv64gc-unknown-none-elf"]
|
|
@ -6,6 +6,7 @@ extern crate user_lib;
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
use core::ptr::addr_of_mut;
|
||||||
use user_lib::{exit, get_time, thread_create, waittid};
|
use user_lib::{exit, get_time, thread_create, waittid};
|
||||||
|
|
||||||
static mut A: usize = 0;
|
static mut A: usize = 0;
|
||||||
|
@ -14,7 +15,7 @@ const THREAD_COUNT_DEFAULT: usize = 16;
|
||||||
static mut PER_THREAD: usize = 0;
|
static mut PER_THREAD: usize = 0;
|
||||||
|
|
||||||
unsafe fn critical_section(t: &mut usize) {
|
unsafe fn critical_section(t: &mut usize) {
|
||||||
let a = &mut A as *mut usize;
|
let a = addr_of_mut!(A);
|
||||||
let cur = a.read_volatile();
|
let cur = a.read_volatile();
|
||||||
for _ in 0..500 {
|
for _ in 0..500 {
|
||||||
*t = (*t) * (*t) % 10007;
|
*t = (*t) * (*t) % 10007;
|
||||||
|
|
|
@ -6,6 +6,7 @@ extern crate user_lib;
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
use core::ptr::addr_of_mut;
|
||||||
use core::sync::atomic::{AtomicBool, Ordering};
|
use core::sync::atomic::{AtomicBool, Ordering};
|
||||||
use user_lib::{exit, get_time, thread_create, waittid, yield_};
|
use user_lib::{exit, get_time, thread_create, waittid, yield_};
|
||||||
|
|
||||||
|
@ -16,7 +17,7 @@ const THREAD_COUNT_DEFAULT: usize = 16;
|
||||||
static mut PER_THREAD: usize = 0;
|
static mut PER_THREAD: usize = 0;
|
||||||
|
|
||||||
unsafe fn critical_section(t: &mut usize) {
|
unsafe fn critical_section(t: &mut usize) {
|
||||||
let a = &mut A as *mut usize;
|
let a = addr_of_mut!(A);
|
||||||
let cur = a.read_volatile();
|
let cur = a.read_volatile();
|
||||||
for _ in 0..500 {
|
for _ in 0..500 {
|
||||||
*t = (*t) * (*t) % 10007;
|
*t = (*t) * (*t) % 10007;
|
||||||
|
|
|
@ -6,6 +6,7 @@ extern crate user_lib;
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
use core::ptr::addr_of_mut;
|
||||||
use user_lib::{exit, get_time, thread_create, waittid};
|
use user_lib::{exit, get_time, thread_create, waittid};
|
||||||
use user_lib::{mutex_blocking_create, mutex_lock, mutex_unlock};
|
use user_lib::{mutex_blocking_create, mutex_lock, mutex_unlock};
|
||||||
|
|
||||||
|
@ -15,7 +16,7 @@ const THREAD_COUNT_DEFAULT: usize = 16;
|
||||||
static mut PER_THREAD: usize = 0;
|
static mut PER_THREAD: usize = 0;
|
||||||
|
|
||||||
unsafe fn critical_section(t: &mut usize) {
|
unsafe fn critical_section(t: &mut usize) {
|
||||||
let a = &mut A as *mut usize;
|
let a = addr_of_mut!(A);
|
||||||
let cur = a.read_volatile();
|
let cur = a.read_volatile();
|
||||||
for _ in 0..500 {
|
for _ in 0..500 {
|
||||||
*t = (*t) * (*t) % 10007;
|
*t = (*t) * (*t) % 10007;
|
||||||
|
|
|
@ -6,6 +6,7 @@ extern crate user_lib;
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
use core::ptr::addr_of_mut;
|
||||||
use user_lib::{exit, get_time, thread_create, waittid};
|
use user_lib::{exit, get_time, thread_create, waittid};
|
||||||
use user_lib::{mutex_create, mutex_lock, mutex_unlock};
|
use user_lib::{mutex_create, mutex_lock, mutex_unlock};
|
||||||
|
|
||||||
|
@ -15,7 +16,7 @@ const THREAD_COUNT_DEFAULT: usize = 16;
|
||||||
static mut PER_THREAD: usize = 0;
|
static mut PER_THREAD: usize = 0;
|
||||||
|
|
||||||
unsafe fn critical_section(t: &mut usize) {
|
unsafe fn critical_section(t: &mut usize) {
|
||||||
let a = &mut A as *mut usize;
|
let a = addr_of_mut!(A);
|
||||||
let cur = a.read_volatile();
|
let cur = a.read_volatile();
|
||||||
for _ in 0..500 {
|
for _ in 0..500 {
|
||||||
*t = (*t) * (*t) % 10007;
|
*t = (*t) * (*t) % 10007;
|
||||||
|
|
|
@ -2,13 +2,13 @@
|
||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![feature(core_intrinsics)]
|
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate user_lib;
|
extern crate user_lib;
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
use core::ptr::addr_of_mut;
|
||||||
use core::sync::atomic::{compiler_fence, Ordering};
|
use core::sync::atomic::{compiler_fence, Ordering};
|
||||||
use user_lib::{exit, get_time, thread_create, waittid};
|
use user_lib::{exit, get_time, thread_create, waittid};
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ const THREAD_COUNT_DEFAULT: usize = 2;
|
||||||
static mut PER_THREAD: usize = 0;
|
static mut PER_THREAD: usize = 0;
|
||||||
|
|
||||||
unsafe fn critical_section(t: &mut usize) {
|
unsafe fn critical_section(t: &mut usize) {
|
||||||
let a = &mut A as *mut usize;
|
let a = addr_of_mut!(A);
|
||||||
let cur = a.read_volatile();
|
let cur = a.read_volatile();
|
||||||
for _ in 0..500 {
|
for _ in 0..500 {
|
||||||
*t = (*t) * (*t) % 10007;
|
*t = (*t) * (*t) % 10007;
|
||||||
|
@ -39,7 +39,7 @@ unsafe fn lock(id: usize) {
|
||||||
// Otherwise the compiler will assume that they will never
|
// Otherwise the compiler will assume that they will never
|
||||||
// be changed on this thread. Thus, they will be accessed
|
// be changed on this thread. Thus, they will be accessed
|
||||||
// only once!
|
// only once!
|
||||||
while vload!(&FLAG[j]) && vload!(&TURN) == j {}
|
while vload!(FLAG[j]) && vload!(TURN) == j {}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn unlock(id: usize) {
|
unsafe fn unlock(id: usize) {
|
||||||
|
|
|
@ -2,14 +2,16 @@
|
||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![feature(core_intrinsics)]
|
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate user_lib;
|
extern crate user_lib;
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use core::sync::atomic::{compiler_fence, Ordering};
|
use core::{
|
||||||
|
ptr::addr_of_mut,
|
||||||
|
sync::atomic::{compiler_fence, Ordering},
|
||||||
|
};
|
||||||
use user_lib::{exit, get_time, thread_create, waittid, yield_};
|
use user_lib::{exit, get_time, thread_create, waittid, yield_};
|
||||||
|
|
||||||
static mut A: usize = 0;
|
static mut A: usize = 0;
|
||||||
|
@ -20,7 +22,7 @@ const THREAD_COUNT_DEFAULT: usize = 2;
|
||||||
static mut PER_THREAD: usize = 0;
|
static mut PER_THREAD: usize = 0;
|
||||||
|
|
||||||
unsafe fn critical_section(t: &mut usize) {
|
unsafe fn critical_section(t: &mut usize) {
|
||||||
let a = &mut A as *mut usize;
|
let a = addr_of_mut!(A);
|
||||||
let cur = a.read_volatile();
|
let cur = a.read_volatile();
|
||||||
for _ in 0..500 {
|
for _ in 0..500 {
|
||||||
*t = (*t) * (*t) % 10007;
|
*t = (*t) * (*t) % 10007;
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![feature(core_intrinsics)]
|
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate user_lib;
|
extern crate user_lib;
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
use core::ptr::addr_of_mut;
|
||||||
use user_lib::{exit, get_time, thread_create, waittid};
|
use user_lib::{exit, get_time, thread_create, waittid};
|
||||||
|
|
||||||
static mut A: usize = 0;
|
static mut A: usize = 0;
|
||||||
|
@ -16,7 +16,7 @@ const THREAD_COUNT_DEFAULT: usize = 16;
|
||||||
static mut PER_THREAD: usize = 0;
|
static mut PER_THREAD: usize = 0;
|
||||||
|
|
||||||
unsafe fn critical_section(t: &mut usize) {
|
unsafe fn critical_section(t: &mut usize) {
|
||||||
let a = &mut A as *mut usize;
|
let a = addr_of_mut!(A);
|
||||||
let cur = a.read_volatile();
|
let cur = a.read_volatile();
|
||||||
for _ in 0..500 {
|
for _ in 0..500 {
|
||||||
*t = (*t) * (*t) % 10007;
|
*t = (*t) * (*t) % 10007;
|
||||||
|
@ -25,7 +25,7 @@ unsafe fn critical_section(t: &mut usize) {
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn lock() {
|
unsafe fn lock() {
|
||||||
while vload!(&OCCUPIED) {}
|
while vload!(OCCUPIED) {}
|
||||||
OCCUPIED = true;
|
OCCUPIED = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![feature(core_intrinsics)]
|
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate user_lib;
|
extern crate user_lib;
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
use core::ptr::addr_of_mut;
|
||||||
use user_lib::{exit, get_time, thread_create, waittid, yield_};
|
use user_lib::{exit, get_time, thread_create, waittid, yield_};
|
||||||
|
|
||||||
static mut A: usize = 0;
|
static mut A: usize = 0;
|
||||||
|
@ -16,7 +16,7 @@ const THREAD_COUNT_DEFAULT: usize = 16;
|
||||||
static mut PER_THREAD: usize = 0;
|
static mut PER_THREAD: usize = 0;
|
||||||
|
|
||||||
unsafe fn critical_section(t: &mut usize) {
|
unsafe fn critical_section(t: &mut usize) {
|
||||||
let a = &mut A as *mut usize;
|
let a = addr_of_mut!(A);
|
||||||
let cur = a.read_volatile();
|
let cur = a.read_volatile();
|
||||||
for _ in 0..500 {
|
for _ in 0..500 {
|
||||||
*t = (*t) * (*t) % 10007;
|
*t = (*t) * (*t) % 10007;
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![feature(core_intrinsics)]
|
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate user_lib;
|
extern crate user_lib;
|
||||||
|
@ -8,7 +7,9 @@ extern crate alloc;
|
||||||
extern crate core;
|
extern crate core;
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use core::sync::atomic::{AtomicUsize, Ordering};
|
use core::{
|
||||||
|
sync::atomic::{AtomicUsize, Ordering},
|
||||||
|
};
|
||||||
use user_lib::{exit, sleep, thread_create, waittid};
|
use user_lib::{exit, sleep, thread_create, waittid};
|
||||||
|
|
||||||
const N: usize = 2;
|
const N: usize = 2;
|
||||||
|
@ -38,19 +39,19 @@ fn critical_test_exit() {
|
||||||
assert_eq!(GUARD.fetch_sub(1, Ordering::SeqCst), 1);
|
assert_eq!(GUARD.fetch_sub(1, Ordering::SeqCst), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eisenberg_enter_critical(id: usize) {
|
unsafe fn eisenberg_enter_critical(id: usize) {
|
||||||
/* announce that we want to enter */
|
/* announce that we want to enter */
|
||||||
loop {
|
loop {
|
||||||
println!("Thread[{}] try enter", id);
|
println!("Thread[{}] try enter", id);
|
||||||
vstore!(&FLAG[id], FlagState::Want);
|
vstore!(FLAG[id], FlagState::Want);
|
||||||
loop {
|
loop {
|
||||||
/* check if any with higher priority is `Want` or `In` */
|
/* check if any with higher priority is `Want` or `In` */
|
||||||
let mut prior_thread: Option<usize> = None;
|
let mut prior_thread: Option<usize> = None;
|
||||||
let turn = vload!(&TURN);
|
let turn = vload!(TURN);
|
||||||
let ring_id = if id < turn { id + THREAD_NUM } else { id };
|
let ring_id = if id < turn { id + THREAD_NUM } else { id };
|
||||||
// FLAG.iter() may lead to some errors, use for-loop instead
|
// FLAG.iter() may lead to some errors, use for-loop instead
|
||||||
for i in turn..ring_id {
|
for i in turn..ring_id {
|
||||||
if vload!(&FLAG[i % THREAD_NUM]) != FlagState::Out {
|
if vload!(FLAG[i % THREAD_NUM]) != FlagState::Out {
|
||||||
prior_thread = Some(i % THREAD_NUM);
|
prior_thread = Some(i % THREAD_NUM);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -66,13 +67,13 @@ fn eisenberg_enter_critical(id: usize) {
|
||||||
sleep(1);
|
sleep(1);
|
||||||
}
|
}
|
||||||
/* now tentatively claim the resource */
|
/* now tentatively claim the resource */
|
||||||
vstore!(&FLAG[id], FlagState::In);
|
vstore!(FLAG[id], FlagState::In);
|
||||||
/* enforce the order of `claim` and `conflict check`*/
|
/* enforce the order of `claim` and `conflict check`*/
|
||||||
memory_fence!();
|
memory_fence!();
|
||||||
/* check if anthor thread is also `In`, which imply a conflict*/
|
/* check if anthor thread is also `In`, which imply a conflict*/
|
||||||
let mut conflict = false;
|
let mut conflict = false;
|
||||||
for i in 0..THREAD_NUM {
|
for i in 0..THREAD_NUM {
|
||||||
if i != id && vload!(&FLAG[i]) == FlagState::In {
|
if i != id && vload!(FLAG[i]) == FlagState::In {
|
||||||
conflict = true;
|
conflict = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,28 +84,28 @@ fn eisenberg_enter_critical(id: usize) {
|
||||||
/* no need to sleep */
|
/* no need to sleep */
|
||||||
}
|
}
|
||||||
/* clain the trun */
|
/* clain the trun */
|
||||||
vstore!(&TURN, id);
|
vstore!(TURN, id);
|
||||||
println!("Thread[{}] enter", id);
|
println!("Thread[{}] enter", id);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eisenberg_exit_critical(id: usize) {
|
unsafe fn eisenberg_exit_critical(id: usize) {
|
||||||
/* find next one who wants to enter and give the turn to it*/
|
/* find next one who wants to enter and give the turn to it*/
|
||||||
let mut next = id;
|
let mut next = id;
|
||||||
let ring_id = id + THREAD_NUM;
|
let ring_id = id + THREAD_NUM;
|
||||||
for i in (id + 1)..ring_id {
|
for i in (id + 1)..ring_id {
|
||||||
let idx = i % THREAD_NUM;
|
let idx = i % THREAD_NUM;
|
||||||
if vload!(&FLAG[idx]) == FlagState::Want {
|
if vload!(FLAG[idx]) == FlagState::Want {
|
||||||
next = idx;
|
next = idx;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vstore!(&TURN, next);
|
vstore!(TURN, next);
|
||||||
/* All done */
|
/* All done */
|
||||||
vstore!(&FLAG[id], FlagState::Out);
|
vstore!(FLAG[id], FlagState::Out);
|
||||||
println!("Thread[{}] exit, give turn to {}", id, next);
|
println!("Thread[{}] exit, give turn to {}", id, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn thread_fn(id: usize) -> ! {
|
pub unsafe fn thread_fn(id: usize) -> ! {
|
||||||
println!("Thread[{}] init.", id);
|
println!("Thread[{}] init.", id);
|
||||||
for _ in 0..N {
|
for _ in 0..N {
|
||||||
eisenberg_enter_critical(id);
|
eisenberg_enter_critical(id);
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![feature(core_intrinsics)]
|
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate user_lib;
|
extern crate user_lib;
|
||||||
|
@ -28,12 +27,12 @@ fn critical_test_exit() {
|
||||||
assert_eq!(GUARD.fetch_sub(1, Ordering::SeqCst), 1);
|
assert_eq!(GUARD.fetch_sub(1, Ordering::SeqCst), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn peterson_enter_critical(id: usize, peer_id: usize) {
|
unsafe fn peterson_enter_critical(id: usize, peer_id: usize) {
|
||||||
// println!("Thread[{}] try enter", id);
|
// println!("Thread[{}] try enter", id);
|
||||||
vstore!(&FLAG[id], true);
|
vstore!(FLAG[id], true);
|
||||||
vstore!(&TURN, peer_id);
|
vstore!(TURN, peer_id);
|
||||||
memory_fence!();
|
memory_fence!();
|
||||||
while vload!(&FLAG[peer_id]) && vload!(&TURN) == peer_id {
|
while vload!(FLAG[peer_id]) && vload!(TURN) == peer_id {
|
||||||
// println!("Thread[{}] enter fail", id);
|
// println!("Thread[{}] enter fail", id);
|
||||||
sleep(1);
|
sleep(1);
|
||||||
// println!("Thread[{}] retry enter", id);
|
// println!("Thread[{}] retry enter", id);
|
||||||
|
@ -41,12 +40,12 @@ fn peterson_enter_critical(id: usize, peer_id: usize) {
|
||||||
// println!("Thread[{}] enter", id);
|
// println!("Thread[{}] enter", id);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn peterson_exit_critical(id: usize) {
|
unsafe fn peterson_exit_critical(id: usize) {
|
||||||
vstore!(&FLAG[id], false);
|
vstore!(FLAG[id], false);
|
||||||
// println!("Thread[{}] exit", id);
|
// println!("Thread[{}] exit", id);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn thread_fn(id: usize) -> ! {
|
pub unsafe fn thread_fn(id: usize) -> ! {
|
||||||
// println!("Thread[{}] init.", id);
|
// println!("Thread[{}] init.", id);
|
||||||
let peer_id: usize = id ^ 1;
|
let peer_id: usize = id ^ 1;
|
||||||
for iter in 0..N {
|
for iter in 0..N {
|
||||||
|
|
|
@ -7,6 +7,7 @@ extern crate alloc;
|
||||||
|
|
||||||
use crate::alloc::string::ToString;
|
use crate::alloc::string::ToString;
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
use core::ptr::addr_of_mut;
|
||||||
use user_lib::{exit, get_time, thread_create, waittid};
|
use user_lib::{exit, get_time, thread_create, waittid};
|
||||||
|
|
||||||
static mut A: usize = 0;
|
static mut A: usize = 0;
|
||||||
|
@ -16,7 +17,7 @@ const THREAD_COUNT: usize = 16;
|
||||||
unsafe fn f(count: usize) -> ! {
|
unsafe fn f(count: usize) -> ! {
|
||||||
let mut t = 2usize;
|
let mut t = 2usize;
|
||||||
for _ in 0..PER_THREAD {
|
for _ in 0..PER_THREAD {
|
||||||
let a = &mut A as *mut usize;
|
let a = addr_of_mut!(A);
|
||||||
let cur = a.read_volatile();
|
let cur = a.read_volatile();
|
||||||
for _ in 0..count {
|
for _ in 0..count {
|
||||||
t = t * t % 10007;
|
t = t * t % 10007;
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
#![feature(linkage)]
|
#![feature(linkage)]
|
||||||
#![feature(panic_info_message)]
|
#![feature(panic_info_message)]
|
||||||
#![feature(alloc_error_handler)]
|
#![feature(alloc_error_handler)]
|
||||||
#![feature(core_intrinsics)]
|
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod console;
|
pub mod console;
|
||||||
|
@ -71,15 +70,17 @@ fn main(_argc: usize, _argv: &[&str]) -> i32 {
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! vstore {
|
macro_rules! vstore {
|
||||||
($var_ref: expr, $value: expr) => {
|
($var: expr, $value: expr) => {
|
||||||
unsafe { core::intrinsics::volatile_store($var_ref as *const _ as _, $value) }
|
// unsafe { core::intrinsics::volatile_store($var_ref as *const _ as _, $value) }
|
||||||
|
unsafe { core::ptr::write_volatile(core::ptr::addr_of_mut!($var), $value); }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! vload {
|
macro_rules! vload {
|
||||||
($var_ref: expr) => {
|
($var: expr) => {
|
||||||
unsafe { core::intrinsics::volatile_load($var_ref as *const _ as _) }
|
// unsafe { core::intrinsics::volatile_load($var_ref as *const _ as _) }
|
||||||
|
unsafe { core::ptr::read_volatile(core::ptr::addr_of!($var)) }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue