mirror of
https://github.com/rcore-os/rCore-Tutorial-v3.git
synced 2024-11-22 01:16:26 +04:00
Merge ch9
This commit is contained in:
commit
fc173e5344
@ -85,9 +85,9 @@ fn easy_fs_pack() -> std::io::Result<()> {
|
||||
inode.write_at(0, all_data.as_slice());
|
||||
}
|
||||
// list apps
|
||||
for app in root_inode.ls() {
|
||||
println!("{}", app);
|
||||
}
|
||||
// for app in root_inode.ls() {
|
||||
// println!("{}", app);
|
||||
// }
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,6 @@ volatile = "0.3"
|
||||
virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "4ee80e5" }
|
||||
lose-net-stack = { git = "https://github.com/yfblock/lose-net-stack", rev = "3f467dd" }
|
||||
easy-fs = { path = "../easy-fs" }
|
||||
virtio-input-decoder = "0.1.4"
|
||||
embedded-graphics = "0.7.1"
|
||||
tinybmp = "0.3.1"
|
||||
|
||||
|
@ -12,7 +12,7 @@ pub type CharDeviceImpl = crate::drivers::chardev::NS16550a<VIRT_UART>;
|
||||
|
||||
pub const VIRT_PLIC: usize = 0xC00_0000;
|
||||
pub const VIRT_UART: usize = 0x1000_0000;
|
||||
|
||||
#[allow(unused)]
|
||||
pub const VIRTGPU_XRES: u32 = 1280;
|
||||
#[allow(unused)]
|
||||
pub const VIRTGPU_YRES: u32 = 800;
|
||||
|
@ -131,7 +131,7 @@ pub struct NS16550a<const BASE_ADDR: usize> {
|
||||
|
||||
impl<const BASE_ADDR: usize> NS16550a<BASE_ADDR> {
|
||||
pub fn new() -> Self {
|
||||
let mut inner = NS16550aInner {
|
||||
let inner = NS16550aInner {
|
||||
ns16550a: NS16550aRaw::new(BASE_ADDR),
|
||||
read_buffer: VecDeque::new(),
|
||||
};
|
||||
@ -141,14 +141,20 @@ impl<const BASE_ADDR: usize> NS16550a<BASE_ADDR> {
|
||||
condvar: Condvar::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_buffer_is_empty(&self) -> bool {
|
||||
self.inner
|
||||
.exclusive_session(|inner| inner.read_buffer.is_empty())
|
||||
}
|
||||
}
|
||||
|
||||
impl<const BASE_ADDR: usize> CharDevice for NS16550a<BASE_ADDR> {
|
||||
fn init(&self){
|
||||
fn init(&self) {
|
||||
let mut inner = self.inner.exclusive_access();
|
||||
inner.ns16550a.init();
|
||||
drop(inner);
|
||||
}
|
||||
|
||||
fn read(&self) -> u8 {
|
||||
loop {
|
||||
let mut inner = self.inner.exclusive_access();
|
||||
|
@ -1,20 +1,28 @@
|
||||
use crate::drivers::bus::virtio::VirtioHal;
|
||||
use crate::{
|
||||
gui::{move_rect, reset},
|
||||
sync::UPIntrFreeCell,
|
||||
};
|
||||
use crate::sync::{Condvar, UPIntrFreeCell};
|
||||
use crate::task::schedule;
|
||||
use alloc::collections::VecDeque;
|
||||
use alloc::sync::Arc;
|
||||
use core::any::Any;
|
||||
use virtio_drivers::{VirtIOHeader, VirtIOInput};
|
||||
use virtio_input_decoder::{Decoder, Key, KeyType};
|
||||
|
||||
const VIRTIO5: usize = 0x10005000;
|
||||
const VIRTIO6: usize = 0x10006000;
|
||||
|
||||
struct VirtIOInputWrapper(UPIntrFreeCell<VirtIOInput<'static, VirtioHal>>);
|
||||
struct VirtIOInputInner {
|
||||
virtio_input: VirtIOInput<'static, VirtioHal>,
|
||||
events: VecDeque<u64>,
|
||||
}
|
||||
|
||||
struct VirtIOInputWrapper {
|
||||
inner: UPIntrFreeCell<VirtIOInputInner>,
|
||||
condvar: Condvar,
|
||||
}
|
||||
|
||||
pub trait InputDevice: Send + Sync + Any {
|
||||
fn read_event(&self) -> u64;
|
||||
fn handle_irq(&self);
|
||||
fn is_empty(&self) -> bool;
|
||||
}
|
||||
|
||||
lazy_static::lazy_static!(
|
||||
@ -24,52 +32,52 @@ lazy_static::lazy_static!(
|
||||
|
||||
impl VirtIOInputWrapper {
|
||||
pub fn new(addr: usize) -> Self {
|
||||
Self(unsafe {
|
||||
UPIntrFreeCell::new(
|
||||
VirtIOInput::<VirtioHal>::new(&mut *(addr as *mut VirtIOHeader)).unwrap(),
|
||||
)
|
||||
})
|
||||
let inner = VirtIOInputInner {
|
||||
virtio_input: unsafe {
|
||||
VirtIOInput::<VirtioHal>::new(&mut *(addr as *mut VirtIOHeader)).unwrap()
|
||||
},
|
||||
events: VecDeque::new(),
|
||||
};
|
||||
Self {
|
||||
inner: unsafe { UPIntrFreeCell::new(inner) },
|
||||
condvar: Condvar::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl InputDevice for VirtIOInputWrapper {
|
||||
fn handle_irq(&self) {
|
||||
let mut input = self.0.exclusive_access();
|
||||
input.ack_interrupt();
|
||||
while let Some(event) = input.pop_pending_event() {
|
||||
let dtype = match Decoder::decode(
|
||||
event.event_type as usize,
|
||||
event.code as usize,
|
||||
event.value as usize,
|
||||
) {
|
||||
Ok(dtype) => dtype,
|
||||
Err(_) => break,
|
||||
};
|
||||
match dtype {
|
||||
virtio_input_decoder::DecodeType::Key(key, r#type) => {
|
||||
if r#type == KeyType::Press {
|
||||
match key {
|
||||
Key::C | Key::MouseLeft => {
|
||||
reset();
|
||||
}
|
||||
Key::W => {
|
||||
move_rect(0, -10);
|
||||
}
|
||||
Key::S => {
|
||||
move_rect(0, 10);
|
||||
}
|
||||
Key::A => {
|
||||
move_rect(-10, 0);
|
||||
}
|
||||
Key::D => {
|
||||
move_rect(10, 0);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
fn is_empty(&self) -> bool {
|
||||
self.inner.exclusive_access().events.is_empty()
|
||||
}
|
||||
|
||||
fn read_event(&self) -> u64 {
|
||||
loop {
|
||||
let mut inner = self.inner.exclusive_access();
|
||||
if let Some(event) = inner.events.pop_front() {
|
||||
return event;
|
||||
} else {
|
||||
let task_cx_ptr = self.condvar.wait_no_sched();
|
||||
drop(inner);
|
||||
schedule(task_cx_ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_irq(&self) {
|
||||
let mut count = 0;
|
||||
let mut result = 0;
|
||||
self.inner.exclusive_session(|inner| {
|
||||
inner.virtio_input.ack_interrupt();
|
||||
while let Some(event) = inner.virtio_input.pop_pending_event() {
|
||||
count += 1;
|
||||
result = (event.event_type as u64) << 48
|
||||
| (event.code as u64) << 32
|
||||
| (event.value) as u64;
|
||||
inner.events.push_back(result);
|
||||
}
|
||||
});
|
||||
if count > 0 {
|
||||
self.condvar.signal();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,63 +0,0 @@
|
||||
use alloc::sync::Arc;
|
||||
use embedded_graphics::{
|
||||
draw_target::DrawTarget,
|
||||
pixelcolor::Rgb888,
|
||||
prelude::{OriginDimensions, Point, RgbColor, Size},
|
||||
};
|
||||
|
||||
use crate::board::VIRTGPU_XRES;
|
||||
use crate::drivers::{GpuDevice, GPU_DEVICE};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Graphics {
|
||||
pub size: Size,
|
||||
pub point: Point,
|
||||
pub drv: Arc<dyn GpuDevice>,
|
||||
}
|
||||
|
||||
impl Graphics {
|
||||
pub fn new(size: Size, point: Point) -> Self {
|
||||
Self {
|
||||
size,
|
||||
point,
|
||||
drv: GPU_DEVICE.clone(),
|
||||
}
|
||||
}
|
||||
pub fn reset(&self) {
|
||||
let fb = self.drv.get_framebuffer();
|
||||
fb.fill(0u8);
|
||||
}
|
||||
}
|
||||
|
||||
impl OriginDimensions for Graphics {
|
||||
fn size(&self) -> Size {
|
||||
self.size
|
||||
}
|
||||
}
|
||||
|
||||
impl DrawTarget for Graphics {
|
||||
type Color = Rgb888;
|
||||
|
||||
type Error = core::convert::Infallible;
|
||||
|
||||
fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
|
||||
where
|
||||
I: IntoIterator<Item = embedded_graphics::Pixel<Self::Color>>,
|
||||
{
|
||||
let fb = self.drv.get_framebuffer();
|
||||
|
||||
pixels.into_iter().for_each(|px| {
|
||||
let idx = ((self.point.y + px.0.y) * VIRTGPU_XRES as i32 + self.point.x + px.0.x)
|
||||
as usize
|
||||
* 4;
|
||||
if idx + 2 >= fb.len() {
|
||||
return;
|
||||
}
|
||||
fb[idx] = px.1.b();
|
||||
fb[idx + 1] = px.1.g();
|
||||
fb[idx + 2] = px.1.r();
|
||||
});
|
||||
self.drv.flush();
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
mod graphic;
|
||||
mod paint;
|
||||
|
||||
use graphic::Graphics;
|
||||
pub use paint::{init_paint, move_rect, reset};
|
@ -1,62 +0,0 @@
|
||||
use super::Graphics;
|
||||
use crate::sync::UPIntrFreeCell;
|
||||
use embedded_graphics::pixelcolor::Rgb888;
|
||||
use embedded_graphics::prelude::{Drawable, Point, RgbColor, Size};
|
||||
use embedded_graphics::primitives::Primitive;
|
||||
use embedded_graphics::primitives::{PrimitiveStyle, Rectangle};
|
||||
use lazy_static::*;
|
||||
|
||||
const INIT_X: i32 = 640;
|
||||
const INIT_Y: i32 = 400;
|
||||
const RECT_SIZE: u32 = 40;
|
||||
|
||||
pub struct DrawingBoard {
|
||||
graphics: Graphics,
|
||||
latest_pos: Point,
|
||||
}
|
||||
|
||||
impl DrawingBoard {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
graphics: Graphics::new(Size::new(1280, 800), Point::new(0, 0)),
|
||||
latest_pos: Point::new(INIT_X, INIT_Y),
|
||||
}
|
||||
}
|
||||
fn paint(&mut self) {
|
||||
Rectangle::with_center(self.latest_pos, Size::new(RECT_SIZE, RECT_SIZE))
|
||||
.into_styled(PrimitiveStyle::with_stroke(Rgb888::WHITE, 1))
|
||||
.draw(&mut self.graphics)
|
||||
.ok();
|
||||
}
|
||||
pub fn move_rect(&mut self, dx: i32, dy: i32) {
|
||||
self.latest_pos.x += dx;
|
||||
self.latest_pos.y += dy;
|
||||
self.paint();
|
||||
}
|
||||
pub fn reset(&mut self) {
|
||||
self.latest_pos = Point::new(INIT_X, INIT_Y);
|
||||
self.graphics.reset();
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
pub static ref DRAWING_BOARD: UPIntrFreeCell<DrawingBoard> = unsafe { UPIntrFreeCell::new(DrawingBoard::new()) };
|
||||
}
|
||||
|
||||
pub fn init_paint() {
|
||||
DRAWING_BOARD.exclusive_session(|ripple| {
|
||||
ripple.paint();
|
||||
});
|
||||
}
|
||||
|
||||
pub fn move_rect(dx: i32, dy: i32) {
|
||||
DRAWING_BOARD.exclusive_session(|ripple| {
|
||||
ripple.move_rect(dx, dy);
|
||||
});
|
||||
}
|
||||
|
||||
pub fn reset() {
|
||||
DRAWING_BOARD.exclusive_session(|ripple| {
|
||||
ripple.reset();
|
||||
});
|
||||
}
|
@ -5,8 +5,8 @@
|
||||
#![feature(naked_functions)]
|
||||
#![feature(fn_align)]
|
||||
|
||||
//use crate::drivers::{GPU_DEVICE, KEYBOARD_DEVICE, MOUSE_DEVICE, INPUT_CONDVAR};
|
||||
use crate::drivers::{GPU_DEVICE, KEYBOARD_DEVICE, MOUSE_DEVICE};
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
#[macro_use]
|
||||
@ -20,7 +20,6 @@ mod console;
|
||||
mod config;
|
||||
mod drivers;
|
||||
mod fs;
|
||||
mod gui;
|
||||
mod lang_items;
|
||||
mod mm;
|
||||
mod sbi;
|
||||
@ -256,8 +255,6 @@ pub fn rust_main() -> ! {
|
||||
//clear_bss();
|
||||
mm::init();
|
||||
UART.init();
|
||||
println!("KERN: begin");
|
||||
//loop{};
|
||||
println!("KERN: init gpu");
|
||||
let _gpu = GPU_DEVICE.clone();
|
||||
println!("KERN: init keyboard");
|
||||
@ -270,7 +267,6 @@ pub fn rust_main() -> ! {
|
||||
//timer::set_next_trigger();
|
||||
board::device_init();
|
||||
fs::list_apps();
|
||||
//gui::init_paint();
|
||||
task::add_initproc();
|
||||
*DEV_NON_BLOCKING_ACCESS.exclusive_access() = true;
|
||||
task::run_tasks();
|
||||
|
@ -71,7 +71,10 @@ impl MemorySet {
|
||||
self.areas.remove(idx);
|
||||
}
|
||||
}
|
||||
fn push(&mut self, mut map_area: MapArea, data: Option<&[u8]>) {
|
||||
/// Add a new MapArea into this MemorySet.
|
||||
/// Assuming that there are no conflicts in the virtual address
|
||||
/// space.
|
||||
pub fn push(&mut self, mut map_area: MapArea, data: Option<&[u8]>) {
|
||||
map_area.map(&mut self.page_table);
|
||||
if let Some(data) = data {
|
||||
map_area.copy_data(&mut self.page_table, data);
|
||||
@ -286,6 +289,11 @@ impl MapArea {
|
||||
ppn = frame.ppn;
|
||||
self.data_frames.insert(vpn, frame);
|
||||
}
|
||||
MapType::Linear(pn_offset) => {
|
||||
// check for sv39
|
||||
assert!(vpn.0 < (1usize << 27));
|
||||
ppn = PhysPageNum((vpn.0 as isize + pn_offset) as usize);
|
||||
}
|
||||
}
|
||||
let pte_flags = PTEFlags::from_bits(self.map_perm.bits).unwrap();
|
||||
page_table.map(vpn, ppn, pte_flags);
|
||||
@ -334,6 +342,8 @@ impl MapArea {
|
||||
pub enum MapType {
|
||||
Identical,
|
||||
Framed,
|
||||
/// offset of page num
|
||||
Linear(isize),
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
|
@ -4,11 +4,11 @@ mod heap_allocator;
|
||||
mod memory_set;
|
||||
mod page_table;
|
||||
|
||||
use address::VPNRange;
|
||||
pub use address::VPNRange;
|
||||
pub use address::{PhysAddr, PhysPageNum, StepByOne, VirtAddr, VirtPageNum};
|
||||
pub use frame_allocator::{frame_alloc, frame_alloc_more, frame_dealloc, FrameTracker};
|
||||
pub use memory_set::remap_test;
|
||||
pub use memory_set::{kernel_token, MapPermission, MemorySet, KERNEL_SPACE};
|
||||
pub use memory_set::{kernel_token, MapArea, MapPermission, MapType, MemorySet, KERNEL_SPACE};
|
||||
use page_table::PTEFlags;
|
||||
pub use page_table::{
|
||||
translated_byte_buffer, translated_ref, translated_refmut, translated_str, PageTable,
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::sync::{Mutex, UPIntrFreeCell};
|
||||
use crate::task::{
|
||||
add_task, block_current_and_run_next, block_current_task, current_task, TaskContext,
|
||||
wakeup_task, block_current_and_run_next, block_current_task, current_task, TaskContext,
|
||||
TaskControlBlock,
|
||||
};
|
||||
use alloc::{collections::VecDeque, sync::Arc};
|
||||
@ -27,7 +27,7 @@ impl Condvar {
|
||||
pub fn signal(&self) {
|
||||
let mut inner = self.inner.exclusive_access();
|
||||
if let Some(task) = inner.wait_queue.pop_front() {
|
||||
add_task(task);
|
||||
wakeup_task(task);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
use super::UPIntrFreeCell;
|
||||
use crate::task::TaskControlBlock;
|
||||
use crate::task::{add_task, current_task};
|
||||
use crate::task::{wakeup_task, current_task};
|
||||
use crate::task::{block_current_and_run_next, suspend_current_and_run_next};
|
||||
use alloc::{collections::VecDeque, sync::Arc};
|
||||
|
||||
@ -80,7 +80,7 @@ impl Mutex for MutexBlocking {
|
||||
let mut mutex_inner = self.inner.exclusive_access();
|
||||
assert!(mutex_inner.locked);
|
||||
if let Some(waking_task) = mutex_inner.wait_queue.pop_front() {
|
||||
add_task(waking_task);
|
||||
wakeup_task(waking_task);
|
||||
} else {
|
||||
mutex_inner.locked = false;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::sync::UPIntrFreeCell;
|
||||
use crate::task::{add_task, block_current_and_run_next, current_task, TaskControlBlock};
|
||||
use crate::task::{wakeup_task, block_current_and_run_next, current_task, TaskControlBlock};
|
||||
use alloc::{collections::VecDeque, sync::Arc};
|
||||
|
||||
pub struct Semaphore {
|
||||
@ -28,7 +28,7 @@ impl Semaphore {
|
||||
inner.count += 1;
|
||||
if inner.count <= 0 {
|
||||
if let Some(task) = inner.wait_queue.pop_front() {
|
||||
add_task(task);
|
||||
wakeup_task(task);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
34
os/src/syscall/gui.rs
Normal file
34
os/src/syscall/gui.rs
Normal file
@ -0,0 +1,34 @@
|
||||
use crate::drivers::GPU_DEVICE;
|
||||
use crate::mm::{MapArea, MapPermission, MapType, PhysAddr, VirtAddr};
|
||||
use crate::task::current_process;
|
||||
|
||||
const FB_VADDR: usize = 0x10000000;
|
||||
|
||||
pub fn sys_framebuffer() -> isize {
|
||||
let fb = GPU_DEVICE.get_framebuffer();
|
||||
let len = fb.len();
|
||||
// println!("[kernel] FrameBuffer: addr 0x{:X}, len {}", fb.as_ptr() as usize , len);
|
||||
let fb_start_pa = PhysAddr::from(fb.as_ptr() as usize);
|
||||
assert!(fb_start_pa.aligned());
|
||||
let fb_start_ppn = fb_start_pa.floor();
|
||||
let fb_start_vpn = VirtAddr::from(FB_VADDR).floor();
|
||||
let pn_offset = fb_start_ppn.0 as isize - fb_start_vpn.0 as isize;
|
||||
|
||||
let current_process = current_process();
|
||||
let mut inner = current_process.inner_exclusive_access();
|
||||
inner.memory_set.push(
|
||||
MapArea::new(
|
||||
(FB_VADDR as usize).into(),
|
||||
(FB_VADDR + len as usize).into(),
|
||||
MapType::Linear(pn_offset),
|
||||
MapPermission::R | MapPermission::W | MapPermission::U,
|
||||
),
|
||||
None,
|
||||
);
|
||||
FB_VADDR as isize
|
||||
}
|
||||
|
||||
pub fn sys_framebuffer_flush() -> isize {
|
||||
GPU_DEVICE.flush();
|
||||
0
|
||||
}
|
28
os/src/syscall/input.rs
Normal file
28
os/src/syscall/input.rs
Normal file
@ -0,0 +1,28 @@
|
||||
//use crate::drivers::{KEYBOARD_DEVICE,MOUSE_DEVICE,INPUT_CONDVAR,read_input_event};
|
||||
use crate::drivers::{KEYBOARD_DEVICE, MOUSE_DEVICE};
|
||||
|
||||
pub fn sys_event_get() -> isize {
|
||||
let kb = KEYBOARD_DEVICE.clone();
|
||||
let mouse = MOUSE_DEVICE.clone();
|
||||
//let input=INPUT_CONDVAR.clone();
|
||||
//read_input_event() as isize
|
||||
if !kb.is_empty() {
|
||||
kb.read_event() as isize
|
||||
} else if !mouse.is_empty() {
|
||||
mouse.read_event() as isize
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
use crate::drivers::chardev::UART;
|
||||
|
||||
/// check UART's read-buffer is empty or not
|
||||
pub fn sys_key_pressed() -> isize {
|
||||
let res = !UART.read_buffer_is_empty();
|
||||
if res {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
@ -26,14 +26,22 @@ const SYSCALL_SEMAPHORE_DOWN: usize = 1022;
|
||||
const SYSCALL_CONDVAR_CREATE: usize = 1030;
|
||||
const SYSCALL_CONDVAR_SIGNAL: usize = 1031;
|
||||
const SYSCALL_CONDVAR_WAIT: usize = 1032;
|
||||
const SYSCALL_FRAMEBUFFER: usize = 2000;
|
||||
const SYSCALL_FRAMEBUFFER_FLUSH: usize = 2001;
|
||||
const SYSCALL_EVENT_GET: usize = 3000;
|
||||
const SYSCALL_KEY_PRESSED: usize = 3001;
|
||||
|
||||
mod fs;
|
||||
mod gui;
|
||||
mod input;
|
||||
mod process;
|
||||
mod sync;
|
||||
mod thread;
|
||||
mod net;
|
||||
|
||||
use fs::*;
|
||||
use gui::*;
|
||||
use input::*;
|
||||
use process::*;
|
||||
use sync::*;
|
||||
use thread::*;
|
||||
@ -66,9 +74,13 @@ pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize {
|
||||
SYSCALL_SEMAPHORE_CREATE => sys_semaphore_create(args[0]),
|
||||
SYSCALL_SEMAPHORE_UP => sys_semaphore_up(args[0]),
|
||||
SYSCALL_SEMAPHORE_DOWN => sys_semaphore_down(args[0]),
|
||||
SYSCALL_CONDVAR_CREATE => sys_condvar_create(args[0]),
|
||||
SYSCALL_CONDVAR_CREATE => sys_condvar_create(),
|
||||
SYSCALL_CONDVAR_SIGNAL => sys_condvar_signal(args[0]),
|
||||
SYSCALL_CONDVAR_WAIT => sys_condvar_wait(args[0], args[1]),
|
||||
SYSCALL_FRAMEBUFFER => sys_framebuffer(),
|
||||
SYSCALL_FRAMEBUFFER_FLUSH => sys_framebuffer_flush(),
|
||||
SYSCALL_EVENT_GET => sys_event_get(),
|
||||
SYSCALL_KEY_PRESSED => sys_key_pressed(),
|
||||
_ => panic!("Unsupported syscall_id: {}", syscall_id),
|
||||
}
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ pub fn sys_semaphore_down(sem_id: usize) -> isize {
|
||||
0
|
||||
}
|
||||
|
||||
pub fn sys_condvar_create(_arg: usize) -> isize {
|
||||
pub fn sys_condvar_create() -> isize {
|
||||
let process = current_process();
|
||||
let mut process_inner = process.inner_exclusive_access();
|
||||
let id = if let Some(id) = process_inner
|
||||
|
@ -1,4 +1,4 @@
|
||||
use super::{ProcessControlBlock, TaskControlBlock};
|
||||
use super::{ProcessControlBlock, TaskControlBlock, TaskStatus};
|
||||
use crate::sync::UPIntrFreeCell;
|
||||
use alloc::collections::{BTreeMap, VecDeque};
|
||||
use alloc::sync::Arc;
|
||||
@ -34,6 +34,13 @@ pub fn add_task(task: Arc<TaskControlBlock>) {
|
||||
TASK_MANAGER.exclusive_access().add(task);
|
||||
}
|
||||
|
||||
pub fn wakeup_task(task: Arc<TaskControlBlock>) {
|
||||
let mut task_inner = task.inner_exclusive_access();
|
||||
task_inner.task_status = TaskStatus::Ready;
|
||||
drop(task_inner);
|
||||
add_task(task);
|
||||
}
|
||||
|
||||
pub fn fetch_task() -> Option<Arc<TaskControlBlock>> {
|
||||
TASK_MANAGER.exclusive_access().fetch()
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ use switch::__switch;
|
||||
|
||||
pub use context::TaskContext;
|
||||
pub use id::{kstack_alloc, pid_alloc, KernelStack, PidHandle, IDLE_PID};
|
||||
pub use manager::{add_task, pid2process, remove_from_pid2process};
|
||||
pub use manager::{add_task, wakeup_task, pid2process, remove_from_pid2process};
|
||||
pub use processor::{
|
||||
current_kstack_top, current_process, current_task, current_trap_cx, current_trap_cx_user_va,
|
||||
current_user_token, run_tasks, schedule, take_current_task,
|
||||
@ -48,7 +48,7 @@ pub fn suspend_current_and_run_next() {
|
||||
pub fn block_current_task() -> *mut TaskContext {
|
||||
let task = take_current_task().unwrap();
|
||||
let mut task_inner = task.inner_exclusive_access();
|
||||
task_inner.task_status = TaskStatus::Blocking;
|
||||
task_inner.task_status = TaskStatus::Blocked;
|
||||
&mut task_inner.task_cx as *mut TaskContext
|
||||
}
|
||||
|
||||
|
@ -76,5 +76,5 @@ impl TaskControlBlock {
|
||||
pub enum TaskStatus {
|
||||
Ready,
|
||||
Running,
|
||||
Blocking,
|
||||
Blocked,
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ use core::cmp::Ordering;
|
||||
use crate::config::CLOCK_FREQ;
|
||||
use crate::sbi::set_timer;
|
||||
use crate::sync::UPIntrFreeCell;
|
||||
use crate::task::{add_task, TaskControlBlock};
|
||||
use crate::task::{wakeup_task, TaskControlBlock};
|
||||
use alloc::collections::BinaryHeap;
|
||||
use alloc::sync::Arc;
|
||||
use lazy_static::*;
|
||||
@ -64,7 +64,7 @@ pub fn check_timer() {
|
||||
TIMERS.exclusive_session(|timers| {
|
||||
while let Some(timer) = timers.peek() {
|
||||
if timer.expire_ms <= current_ms {
|
||||
add_task(Arc::clone(&timer.task));
|
||||
wakeup_task(Arc::clone(&timer.task));
|
||||
timers.pop();
|
||||
} else {
|
||||
break;
|
||||
|
@ -10,10 +10,10 @@ edition = "2018"
|
||||
buddy_system_allocator = "0.6"
|
||||
bitflags = "1.2.1"
|
||||
riscv = { git = "https://github.com/rcore-os/riscv", features = ["inline-asm"] }
|
||||
lazy_static = { version = "1.4.0", features = ["spin_no_std"] }
|
||||
embedded-graphics = "0.7.1"
|
||||
oorandom ="11"
|
||||
virtio-input-decoder = "0.1.4"
|
||||
|
||||
[profile.release]
|
||||
debug = true
|
||||
|
||||
# [features]
|
||||
# board_qemu = []
|
||||
# board_k210 = []
|
@ -19,7 +19,7 @@ ifeq ($(TEST), 1)
|
||||
endif
|
||||
|
||||
binary: elf
|
||||
$(foreach elf, $(ELFS), $(OBJCOPY) $(elf) --strip-all -O binary $(patsubst $(TARGET_DIR)/%, $(TARGET_DIR)/%.bin, $(elf));)
|
||||
@$(foreach elf, $(ELFS), $(OBJCOPY) $(elf) --strip-all -O binary $(patsubst $(TARGET_DIR)/%, $(TARGET_DIR)/%.bin, $(elf));)
|
||||
|
||||
build: binary
|
||||
|
||||
|
55
user/src/bin/adder.rs
Normal file
55
user/src/bin/adder.rs
Normal file
@ -0,0 +1,55 @@
|
||||
#![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_DEFAULT: usize = 10000;
|
||||
const THREAD_COUNT_DEFAULT: usize = 16;
|
||||
static mut PER_THREAD: usize = 0;
|
||||
|
||||
unsafe fn critical_section(t: &mut usize) {
|
||||
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);
|
||||
}
|
||||
|
||||
unsafe fn f() -> ! {
|
||||
let mut t = 2usize;
|
||||
for _ in 0..PER_THREAD {
|
||||
critical_section(&mut t);
|
||||
}
|
||||
exit(t as i32)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn main(argc: usize, argv: &[&str]) -> i32 {
|
||||
let mut thread_count = THREAD_COUNT_DEFAULT;
|
||||
let mut per_thread = PER_THREAD_DEFAULT;
|
||||
if argc >= 2 {
|
||||
thread_count = argv[1].parse().unwrap();
|
||||
if argc >= 3 {
|
||||
per_thread = argv[2].parse().unwrap();
|
||||
}
|
||||
}
|
||||
unsafe { PER_THREAD = per_thread; }
|
||||
let start = get_time();
|
||||
let mut v = Vec::new();
|
||||
for _ in 0..thread_count {
|
||||
v.push(thread_create(f as usize, 0) as usize);
|
||||
}
|
||||
for tid in v.into_iter() {
|
||||
waittid(tid);
|
||||
}
|
||||
println!("time cost is {}ms", get_time() - start);
|
||||
assert_eq!(unsafe { A }, unsafe { PER_THREAD } * thread_count);
|
||||
0
|
||||
}
|
72
user/src/bin/adder_atomic.rs
Normal file
72
user/src/bin/adder_atomic.rs
Normal file
@ -0,0 +1,72 @@
|
||||
#![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_DEFAULT: usize = 10000;
|
||||
const THREAD_COUNT_DEFAULT: usize = 16;
|
||||
static mut PER_THREAD: usize = 0;
|
||||
|
||||
unsafe fn critical_section(t: &mut usize) {
|
||||
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);
|
||||
}
|
||||
|
||||
fn lock() {
|
||||
while OCCUPIED
|
||||
.compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
|
||||
.is_err()
|
||||
{
|
||||
yield_();
|
||||
}
|
||||
}
|
||||
|
||||
fn unlock() {
|
||||
OCCUPIED.store(false, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
unsafe fn f() -> ! {
|
||||
let mut t = 2usize;
|
||||
for _ in 0..PER_THREAD {
|
||||
lock();
|
||||
critical_section(&mut t);
|
||||
unlock();
|
||||
}
|
||||
exit(t as i32)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn main(argc: usize, argv: &[&str]) -> i32 {
|
||||
let mut thread_count = THREAD_COUNT_DEFAULT;
|
||||
let mut per_thread = PER_THREAD_DEFAULT;
|
||||
if argc >= 2 {
|
||||
thread_count = argv[1].parse().unwrap();
|
||||
if argc >= 3 {
|
||||
per_thread = argv[2].parse().unwrap();
|
||||
}
|
||||
}
|
||||
unsafe { PER_THREAD = per_thread; }
|
||||
let start = get_time();
|
||||
let mut v = Vec::new();
|
||||
for _ in 0..thread_count {
|
||||
v.push(thread_create(f as usize, 0) as usize);
|
||||
}
|
||||
for tid in v.into_iter() {
|
||||
waittid(tid);
|
||||
}
|
||||
println!("time cost is {}ms", get_time() - start);
|
||||
assert_eq!(unsafe { A }, unsafe { PER_THREAD } * thread_count);
|
||||
0
|
||||
}
|
59
user/src/bin/adder_mutex_blocking.rs
Normal file
59
user/src/bin/adder_mutex_blocking.rs
Normal file
@ -0,0 +1,59 @@
|
||||
#![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_blocking_create, mutex_lock, mutex_unlock};
|
||||
|
||||
static mut A: usize = 0;
|
||||
const PER_THREAD_DEFAULT: usize = 10000;
|
||||
const THREAD_COUNT_DEFAULT: usize = 16;
|
||||
static mut PER_THREAD: usize = 0;
|
||||
|
||||
unsafe fn critical_section(t: &mut usize) {
|
||||
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);
|
||||
}
|
||||
unsafe fn f() -> ! {
|
||||
let mut t = 2usize;
|
||||
for _ in 0..PER_THREAD {
|
||||
mutex_lock(0);
|
||||
critical_section(&mut t);
|
||||
mutex_unlock(0);
|
||||
}
|
||||
exit(t as i32)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn main(argc: usize, argv: &[&str]) -> i32 {
|
||||
let mut thread_count = THREAD_COUNT_DEFAULT;
|
||||
let mut per_thread = PER_THREAD_DEFAULT;
|
||||
if argc >= 2 {
|
||||
thread_count = argv[1].parse().unwrap();
|
||||
if argc >= 3 {
|
||||
per_thread = argv[2].parse().unwrap();
|
||||
}
|
||||
}
|
||||
unsafe { PER_THREAD = per_thread; }
|
||||
|
||||
let start = get_time();
|
||||
assert_eq!(mutex_blocking_create(), 0);
|
||||
let mut v = Vec::new();
|
||||
for _ in 0..thread_count {
|
||||
v.push(thread_create(f as usize, 0) as usize);
|
||||
}
|
||||
for tid in v.into_iter() {
|
||||
waittid(tid);
|
||||
}
|
||||
println!("time cost is {}ms", get_time() - start);
|
||||
assert_eq!(unsafe { A }, unsafe { PER_THREAD } * thread_count);
|
||||
0
|
||||
}
|
60
user/src/bin/adder_mutex_spin.rs
Normal file
60
user/src/bin/adder_mutex_spin.rs
Normal file
@ -0,0 +1,60 @@
|
||||
#![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_DEFAULT: usize = 10000;
|
||||
const THREAD_COUNT_DEFAULT: usize = 16;
|
||||
static mut PER_THREAD: usize = 0;
|
||||
|
||||
unsafe fn critical_section(t: &mut usize) {
|
||||
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);
|
||||
}
|
||||
|
||||
unsafe fn f() -> ! {
|
||||
let mut t = 2usize;
|
||||
for _ in 0..PER_THREAD {
|
||||
mutex_lock(0);
|
||||
critical_section(&mut t);
|
||||
mutex_unlock(0);
|
||||
}
|
||||
exit(t as i32)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn main(argc: usize, argv: &[&str]) -> i32 {
|
||||
let mut thread_count = THREAD_COUNT_DEFAULT;
|
||||
let mut per_thread = PER_THREAD_DEFAULT;
|
||||
if argc >= 2 {
|
||||
thread_count = argv[1].parse().unwrap();
|
||||
if argc >= 3 {
|
||||
per_thread = argv[2].parse().unwrap();
|
||||
}
|
||||
}
|
||||
unsafe { PER_THREAD = per_thread; }
|
||||
|
||||
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);
|
||||
}
|
||||
for tid in v.into_iter() {
|
||||
waittid(tid);
|
||||
}
|
||||
println!("time cost is {}ms", get_time() - start);
|
||||
assert_eq!(unsafe { A }, unsafe { PER_THREAD } * thread_count);
|
||||
0
|
||||
}
|
90
user/src/bin/adder_peterson_spin.rs
Normal file
90
user/src/bin/adder_peterson_spin.rs
Normal file
@ -0,0 +1,90 @@
|
||||
//! It only works on a single CPU!
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(core_intrinsics)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate user_lib;
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use user_lib::{exit, get_time, thread_create, waittid};
|
||||
use core::sync::atomic::{compiler_fence, Ordering};
|
||||
|
||||
static mut A: usize = 0;
|
||||
static mut FLAG: [bool; 2] = [false; 2];
|
||||
static mut TURN: usize = 0;
|
||||
const PER_THREAD_DEFAULT: usize = 2000;
|
||||
const THREAD_COUNT_DEFAULT: usize = 2;
|
||||
static mut PER_THREAD: usize = 0;
|
||||
|
||||
unsafe fn critical_section(t: &mut usize) {
|
||||
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);
|
||||
}
|
||||
|
||||
unsafe fn lock(id: usize) {
|
||||
FLAG[id] = true;
|
||||
let j = 1 - id;
|
||||
TURN = j;
|
||||
// Tell the compiler not to reorder memory operations
|
||||
// across this fence.
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
// Why do we need to use volatile_read here?
|
||||
// Otherwise the compiler will assume that they will never
|
||||
// be changed on this thread. Thus, they will be accessed
|
||||
// only once!
|
||||
while vload!(&FLAG[j]) && vload!(&TURN) == j {}
|
||||
}
|
||||
|
||||
unsafe fn unlock(id: usize) {
|
||||
FLAG[id] = false;
|
||||
}
|
||||
|
||||
unsafe fn f(id: usize) -> ! {
|
||||
let mut t = 2usize;
|
||||
for _iter in 0..PER_THREAD {
|
||||
lock(id);
|
||||
critical_section(&mut t);
|
||||
unlock(id);
|
||||
}
|
||||
exit(t as i32)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn main(argc: usize, argv: &[&str]) -> i32 {
|
||||
let mut thread_count = THREAD_COUNT_DEFAULT;
|
||||
let mut per_thread = PER_THREAD_DEFAULT;
|
||||
if argc >= 2 {
|
||||
thread_count = argv[1].parse().unwrap();
|
||||
if argc >= 3 {
|
||||
per_thread = argv[2].parse().unwrap();
|
||||
}
|
||||
}
|
||||
unsafe { PER_THREAD = per_thread; }
|
||||
|
||||
// uncomment this if you want to check the assembly
|
||||
// println!(
|
||||
// "addr: lock={:#x}, unlock={:#x}",
|
||||
// lock as usize,
|
||||
// unlock as usize
|
||||
// );
|
||||
let start = get_time();
|
||||
let mut v = Vec::new();
|
||||
assert_eq!(thread_count, 2, "Peterson works when there are only 2 threads.");
|
||||
for id in 0..thread_count {
|
||||
v.push(thread_create(f as usize, id) 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 }, unsafe { PER_THREAD } * thread_count);
|
||||
0
|
||||
}
|
89
user/src/bin/adder_peterson_yield.rs
Normal file
89
user/src/bin/adder_peterson_yield.rs
Normal file
@ -0,0 +1,89 @@
|
||||
//! It only works on a single CPU!
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(core_intrinsics)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate user_lib;
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use user_lib::{exit, get_time, thread_create, waittid, yield_};
|
||||
use core::sync::atomic::{compiler_fence, Ordering};
|
||||
|
||||
static mut A: usize = 0;
|
||||
static mut FLAG: [bool; 2] = [false; 2];
|
||||
static mut TURN: usize = 0;
|
||||
const PER_THREAD_DEFAULT: usize = 2000;
|
||||
const THREAD_COUNT_DEFAULT: usize = 2;
|
||||
static mut PER_THREAD: usize = 0;
|
||||
|
||||
unsafe fn critical_section(t: &mut usize) {
|
||||
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);
|
||||
}
|
||||
|
||||
unsafe fn lock(id: usize) {
|
||||
FLAG[id] = true;
|
||||
let j = 1 - id;
|
||||
TURN = j;
|
||||
// Tell the compiler not to reorder memory operations
|
||||
// across this fence.
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
while FLAG[j] && TURN == j {
|
||||
yield_();
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn unlock(id: usize) {
|
||||
FLAG[id] = false;
|
||||
}
|
||||
|
||||
unsafe fn f(id: usize) -> ! {
|
||||
let mut t = 2usize;
|
||||
for _iter in 0..PER_THREAD {
|
||||
lock(id);
|
||||
critical_section(&mut t);
|
||||
unlock(id);
|
||||
}
|
||||
exit(t as i32)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn main(argc: usize, argv: &[&str]) -> i32 {
|
||||
let mut thread_count = THREAD_COUNT_DEFAULT;
|
||||
let mut per_thread = PER_THREAD_DEFAULT;
|
||||
if argc >= 2 {
|
||||
thread_count = argv[1].parse().unwrap();
|
||||
if argc >= 3 {
|
||||
per_thread = argv[2].parse().unwrap();
|
||||
}
|
||||
}
|
||||
unsafe { PER_THREAD = per_thread; }
|
||||
|
||||
// uncomment this if you want to check the assembly
|
||||
// println!(
|
||||
// "addr: lock={:#x}, unlock={:#x}",
|
||||
// lock as usize,
|
||||
// unlock as usize
|
||||
// );
|
||||
|
||||
let start = get_time();
|
||||
let mut v = Vec::new();
|
||||
assert_eq!(thread_count, 2, "Peterson works when there are only 2 threads.");
|
||||
for id in 0..thread_count {
|
||||
v.push(thread_create(f as usize, id) 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 }, unsafe { PER_THREAD } * thread_count);
|
||||
0
|
||||
}
|
68
user/src/bin/adder_simple_spin.rs
Normal file
68
user/src/bin/adder_simple_spin.rs
Normal file
@ -0,0 +1,68 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(core_intrinsics)]
|
||||
|
||||
#[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;
|
||||
static mut OCCUPIED: bool = false;
|
||||
const PER_THREAD_DEFAULT: usize = 10000;
|
||||
const THREAD_COUNT_DEFAULT: usize = 16;
|
||||
static mut PER_THREAD: usize = 0;
|
||||
|
||||
unsafe fn critical_section(t: &mut usize) {
|
||||
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);
|
||||
}
|
||||
|
||||
unsafe fn lock() {
|
||||
while vload!(&OCCUPIED) {}
|
||||
OCCUPIED = true;
|
||||
}
|
||||
|
||||
unsafe fn unlock() {
|
||||
OCCUPIED = false;
|
||||
}
|
||||
|
||||
unsafe fn f() -> ! {
|
||||
let mut t = 2usize;
|
||||
for _ in 0..PER_THREAD {
|
||||
lock();
|
||||
critical_section(&mut t);
|
||||
unlock();
|
||||
}
|
||||
exit(t as i32)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn main(argc: usize, argv: &[&str]) -> i32 {
|
||||
let mut thread_count = THREAD_COUNT_DEFAULT;
|
||||
let mut per_thread = PER_THREAD_DEFAULT;
|
||||
if argc >= 2 {
|
||||
thread_count = argv[1].parse().unwrap();
|
||||
if argc >= 3 {
|
||||
per_thread = argv[2].parse().unwrap();
|
||||
}
|
||||
}
|
||||
unsafe { PER_THREAD = per_thread; }
|
||||
let start = get_time();
|
||||
let mut v = Vec::new();
|
||||
for _ in 0..thread_count {
|
||||
v.push(thread_create(f as usize, 0) as usize);
|
||||
}
|
||||
for tid in v.into_iter() {
|
||||
waittid(tid);
|
||||
}
|
||||
println!("time cost is {}ms", get_time() - start);
|
||||
assert_eq!(unsafe { A }, unsafe { PER_THREAD } * thread_count);
|
||||
0
|
||||
}
|
70
user/src/bin/adder_simple_yield.rs
Normal file
70
user/src/bin/adder_simple_yield.rs
Normal file
@ -0,0 +1,70 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(core_intrinsics)]
|
||||
|
||||
#[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_DEFAULT: usize = 10000;
|
||||
const THREAD_COUNT_DEFAULT: usize = 16;
|
||||
static mut PER_THREAD: usize = 0;
|
||||
|
||||
unsafe fn critical_section(t: &mut usize) {
|
||||
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);
|
||||
}
|
||||
|
||||
unsafe fn lock() {
|
||||
while OCCUPIED {
|
||||
yield_();
|
||||
}
|
||||
OCCUPIED = true;
|
||||
}
|
||||
|
||||
unsafe fn unlock() {
|
||||
OCCUPIED = false;
|
||||
}
|
||||
|
||||
unsafe fn f() -> ! {
|
||||
let mut t = 2usize;
|
||||
for _ in 0..PER_THREAD {
|
||||
lock();
|
||||
critical_section(&mut t);
|
||||
unlock();
|
||||
}
|
||||
exit(t as i32)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn main(argc: usize, argv: &[&str]) -> i32 {
|
||||
let mut thread_count = THREAD_COUNT_DEFAULT;
|
||||
let mut per_thread = PER_THREAD_DEFAULT;
|
||||
if argc >= 2 {
|
||||
thread_count = argv[1].parse().unwrap();
|
||||
if argc >= 3 {
|
||||
per_thread = argv[2].parse().unwrap();
|
||||
}
|
||||
}
|
||||
unsafe { PER_THREAD = per_thread; }
|
||||
let start = get_time();
|
||||
let mut v = Vec::new();
|
||||
for _ in 0..thread_count {
|
||||
v.push(thread_create(f as usize, 0) as usize);
|
||||
}
|
||||
for tid in v.into_iter() {
|
||||
waittid(tid);
|
||||
}
|
||||
println!("time cost is {}ms", get_time() - start);
|
||||
assert_eq!(unsafe { A }, unsafe { PER_THREAD } * thread_count);
|
||||
0
|
||||
}
|
72
user/src/bin/barrier_condvar.rs
Normal file
72
user/src/bin/barrier_condvar.rs
Normal file
@ -0,0 +1,72 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
#[macro_use]
|
||||
extern crate user_lib;
|
||||
extern crate alloc;
|
||||
|
||||
use user_lib::{thread_create, exit, waittid, mutex_create, mutex_lock, mutex_unlock, condvar_create, condvar_signal, condvar_wait};
|
||||
use alloc::vec::Vec;
|
||||
use core::cell::UnsafeCell;
|
||||
use lazy_static::*;
|
||||
|
||||
const THREAD_NUM: usize = 3;
|
||||
|
||||
struct Barrier {
|
||||
mutex_id: usize,
|
||||
condvar_id: usize,
|
||||
count: UnsafeCell<usize>,
|
||||
}
|
||||
|
||||
impl Barrier {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
mutex_id: mutex_create() as usize,
|
||||
condvar_id: condvar_create() as usize,
|
||||
count: UnsafeCell::new(0),
|
||||
}
|
||||
}
|
||||
pub fn block(&self) {
|
||||
mutex_lock(self.mutex_id);
|
||||
let count = self.count.get();
|
||||
// SAFETY: Here, the accesses of the count is in the
|
||||
// critical section protected by the mutex.
|
||||
unsafe { *count = *count + 1; }
|
||||
if unsafe { *count } == THREAD_NUM {
|
||||
condvar_signal(self.condvar_id);
|
||||
} else {
|
||||
condvar_wait(self.condvar_id, self.mutex_id);
|
||||
condvar_signal(self.condvar_id);
|
||||
}
|
||||
mutex_unlock(self.mutex_id);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Sync for Barrier {}
|
||||
|
||||
lazy_static! {
|
||||
static ref BARRIER_AB: Barrier = Barrier::new();
|
||||
static ref BARRIER_BC: Barrier = Barrier::new();
|
||||
}
|
||||
|
||||
fn thread_fn() {
|
||||
for _ in 0..300 { print!("a"); }
|
||||
BARRIER_AB.block();
|
||||
for _ in 0..300 { print!("b"); }
|
||||
BARRIER_BC.block();
|
||||
for _ in 0..300 { print!("c"); }
|
||||
exit(0)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn main() -> i32 {
|
||||
let mut v: Vec<isize> = Vec::new();
|
||||
for _ in 0..THREAD_NUM {
|
||||
v.push(thread_create(thread_fn as usize, 0));
|
||||
}
|
||||
for tid in v.into_iter() {
|
||||
waittid(tid as usize);
|
||||
}
|
||||
println!("\nOK!");
|
||||
0
|
||||
}
|
33
user/src/bin/barrier_fail.rs
Normal file
33
user/src/bin/barrier_fail.rs
Normal file
@ -0,0 +1,33 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
#[macro_use]
|
||||
extern crate user_lib;
|
||||
extern crate alloc;
|
||||
|
||||
use user_lib::{thread_create, exit, waittid};
|
||||
use alloc::vec::Vec;
|
||||
|
||||
const THREAD_NUM: usize = 3;
|
||||
|
||||
fn thread_fn() {
|
||||
for ch in 'a'..='c' {
|
||||
for _ in 0..300 {
|
||||
print!("{}", ch);
|
||||
}
|
||||
}
|
||||
exit(0)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn main() -> i32 {
|
||||
let mut v: Vec<isize> = Vec::new();
|
||||
for _ in 0..THREAD_NUM {
|
||||
v.push(thread_create(thread_fn as usize, 0));
|
||||
}
|
||||
for tid in v.into_iter() {
|
||||
waittid(tid as usize);
|
||||
}
|
||||
println!("\nOK!");
|
||||
0
|
||||
}
|
@ -35,8 +35,8 @@ unsafe fn second() -> ! {
|
||||
println!("Second: A is {}", A);
|
||||
condvar_wait(CONDVAR_ID, MUTEX_ID);
|
||||
}
|
||||
mutex_unlock(MUTEX_ID);
|
||||
println!("A is {}, Second can work now", A);
|
||||
mutex_unlock(MUTEX_ID);
|
||||
exit(0)
|
||||
}
|
||||
|
64
user/src/bin/condsync_sem.rs
Normal file
64
user/src/bin/condsync_sem.rs
Normal file
@ -0,0 +1,64 @@
|
||||
#![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, mutex_blocking_create, mutex_lock, mutex_unlock,
|
||||
};
|
||||
use user_lib::{sleep, thread_create, waittid};
|
||||
|
||||
static mut A: usize = 0;
|
||||
|
||||
const SEM_ID: usize = 0;
|
||||
const MUTEX_ID: usize = 0;
|
||||
|
||||
unsafe fn first() -> ! {
|
||||
sleep(10);
|
||||
println!("First work, Change A --> 1 and wakeup Second");
|
||||
mutex_lock(MUTEX_ID);
|
||||
A = 1;
|
||||
semaphore_up(SEM_ID);
|
||||
mutex_unlock(MUTEX_ID);
|
||||
exit(0)
|
||||
}
|
||||
|
||||
unsafe fn second() -> ! {
|
||||
println!("Second want to continue,but need to wait A=1");
|
||||
loop {
|
||||
mutex_lock(MUTEX_ID);
|
||||
if A == 0 {
|
||||
println!("Second: A is {}", A);
|
||||
mutex_unlock(MUTEX_ID);
|
||||
semaphore_down(SEM_ID);
|
||||
} else {
|
||||
mutex_unlock(MUTEX_ID);
|
||||
break;
|
||||
}
|
||||
}
|
||||
println!("A is {}, Second can work now", A);
|
||||
exit(0)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn main() -> i32 {
|
||||
// create semaphore & mutex
|
||||
assert_eq!(semaphore_create(0) as usize, SEM_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
|
||||
}
|
67
user/src/bin/gui_rect.rs
Normal file
67
user/src/bin/gui_rect.rs
Normal file
@ -0,0 +1,67 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
extern crate alloc;
|
||||
extern crate user_lib;
|
||||
|
||||
use user_lib::{Display, VIRTGPU_XRES, VIRTGPU_YRES};
|
||||
|
||||
use embedded_graphics::pixelcolor::Rgb888;
|
||||
use embedded_graphics::prelude::{DrawTarget, Drawable, Point, RgbColor, Size};
|
||||
use embedded_graphics::primitives::{Circle, Primitive, PrimitiveStyle, Rectangle,Triangle};
|
||||
|
||||
const INIT_X: i32 = 80;
|
||||
const INIT_Y: i32 = 400;
|
||||
const RECT_SIZE: u32 = 150;
|
||||
|
||||
pub struct DrawingBoard {
|
||||
disp: Display,
|
||||
latest_pos: Point,
|
||||
}
|
||||
|
||||
impl DrawingBoard {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
disp: Display::new(Size::new(VIRTGPU_XRES, VIRTGPU_YRES)),
|
||||
latest_pos: Point::new(INIT_X, INIT_Y),
|
||||
}
|
||||
}
|
||||
fn paint(&mut self) {
|
||||
Rectangle::with_center(self.latest_pos, Size::new(RECT_SIZE, RECT_SIZE))
|
||||
.into_styled(PrimitiveStyle::with_stroke(Rgb888::RED, 10))
|
||||
.draw(&mut self.disp)
|
||||
.ok();
|
||||
Circle::new(self.latest_pos + Point::new(-70, -300), 150)
|
||||
.into_styled(PrimitiveStyle::with_fill(Rgb888::BLUE))
|
||||
.draw(&mut self.disp)
|
||||
.ok();
|
||||
Triangle::new(self.latest_pos + Point::new(0, 150), self.latest_pos + Point::new(80, 200), self.latest_pos + Point::new(-120, 300))
|
||||
.into_styled(PrimitiveStyle::with_stroke(Rgb888::GREEN, 10))
|
||||
.draw(&mut self.disp)
|
||||
.ok();
|
||||
}
|
||||
fn unpaint(&mut self) {
|
||||
Rectangle::with_center(self.latest_pos, Size::new(RECT_SIZE, RECT_SIZE))
|
||||
.into_styled(PrimitiveStyle::with_stroke(Rgb888::BLACK, 10))
|
||||
.draw(&mut self.disp)
|
||||
.ok();
|
||||
}
|
||||
pub fn move_rect(&mut self, dx: i32, dy: i32) {
|
||||
self.unpaint();
|
||||
self.latest_pos.x += dx;
|
||||
self.latest_pos.y += dy;
|
||||
self.paint();
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn main() -> i32 {
|
||||
let mut board = DrawingBoard::new();
|
||||
let _ = board.disp.clear(Rgb888::BLACK).unwrap();
|
||||
for i in 0..5 {
|
||||
board.latest_pos.x += (RECT_SIZE as i32 + 20);
|
||||
//board.latest_pos.y += i;
|
||||
board.paint();
|
||||
}
|
||||
0
|
||||
}
|
23
user/src/bin/gui_simple.rs
Normal file
23
user/src/bin/gui_simple.rs
Normal file
@ -0,0 +1,23 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
extern crate user_lib;
|
||||
|
||||
use user_lib::{VIRTGPU_XRES, VIRTGPU_YRES, Display};
|
||||
use embedded_graphics::prelude::Size;
|
||||
|
||||
#[no_mangle]
|
||||
pub fn main() -> i32 {
|
||||
let mut disp = Display::new(Size::new(VIRTGPU_XRES, VIRTGPU_YRES));
|
||||
disp.paint_on_framebuffer(|fb| {
|
||||
for y in 0..VIRTGPU_YRES as usize {
|
||||
for x in 0..VIRTGPU_XRES as usize {
|
||||
let idx = (y * VIRTGPU_XRES as usize + x) * 4;
|
||||
fb[idx] = x as u8;
|
||||
fb[idx + 1] = y as u8;
|
||||
fb[idx + 2] = (x + y) as u8;
|
||||
}
|
||||
}
|
||||
});
|
||||
0
|
||||
}
|
351
user/src/bin/gui_snake.rs
Normal file
351
user/src/bin/gui_snake.rs
Normal file
@ -0,0 +1,351 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
extern crate user_lib;
|
||||
extern crate alloc;
|
||||
|
||||
use user_lib::console::getchar;
|
||||
use user_lib::{Display, key_pressed, sleep, VIRTGPU_XRES, VIRTGPU_YRES};
|
||||
|
||||
use embedded_graphics::pixelcolor::*;
|
||||
use embedded_graphics::prelude::{Drawable, Point, RgbColor, Size};
|
||||
use embedded_graphics::primitives::Primitive;
|
||||
use embedded_graphics::primitives::{PrimitiveStyle, Rectangle};
|
||||
use embedded_graphics::Pixel;
|
||||
use embedded_graphics::{draw_target::DrawTarget, prelude::OriginDimensions};
|
||||
use oorandom; //random generator
|
||||
|
||||
struct Snake<T: PixelColor, const MAX_SIZE: usize> {
|
||||
parts: [Pixel<T>; MAX_SIZE],
|
||||
len: usize,
|
||||
direction: Direction,
|
||||
size_x: u32,
|
||||
size_y: u32,
|
||||
}
|
||||
|
||||
struct SnakeIntoIterator<'a, T: PixelColor, const MAX_SIZE: usize> {
|
||||
snake: &'a Snake<T, MAX_SIZE>,
|
||||
index: usize,
|
||||
}
|
||||
|
||||
impl<'a, T: PixelColor, const MAX_SIZE: usize> IntoIterator for &'a Snake<T, MAX_SIZE> {
|
||||
type Item = Pixel<T>;
|
||||
type IntoIter = SnakeIntoIterator<'a, T, MAX_SIZE>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
SnakeIntoIterator {
|
||||
snake: self,
|
||||
index: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: PixelColor, const MAX_SIZE: usize> Iterator for SnakeIntoIterator<'a, T, MAX_SIZE> {
|
||||
type Item = Pixel<T>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let cur = self.snake.parts[self.index];
|
||||
if self.index < self.snake.len {
|
||||
self.index += 1;
|
||||
return Some(cur);
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PixelColor, const MAX_SIZE: usize> Snake<T, MAX_SIZE> {
|
||||
fn new(color: T, size_x: u32, size_y: u32) -> Snake<T, MAX_SIZE> {
|
||||
Snake {
|
||||
parts: [Pixel::<T>(Point { x: 0, y: 0 }, color); MAX_SIZE],
|
||||
len: 1,
|
||||
direction: Direction::None,
|
||||
size_x,
|
||||
size_y,
|
||||
}
|
||||
}
|
||||
fn set_direction(&mut self, direction: Direction) {
|
||||
self.direction = direction;
|
||||
}
|
||||
fn contains(&self, this: Point) -> bool {
|
||||
for part in self.into_iter() {
|
||||
if part.0 == this {
|
||||
return true;
|
||||
};
|
||||
}
|
||||
false
|
||||
}
|
||||
fn grow(&mut self) {
|
||||
if self.len < MAX_SIZE - 1 {
|
||||
self.len += 1;
|
||||
}
|
||||
}
|
||||
fn make_step(&mut self) {
|
||||
let mut i = self.len;
|
||||
while i > 0 {
|
||||
self.parts[i] = self.parts[i - 1];
|
||||
i -= 1;
|
||||
}
|
||||
match self.direction {
|
||||
Direction::Left => {
|
||||
if self.parts[0].0.x == 0 {
|
||||
self.parts[0].0.x = (self.size_x - 1) as i32;
|
||||
} else {
|
||||
self.parts[0].0.x -= 1;
|
||||
}
|
||||
}
|
||||
Direction::Right => {
|
||||
if self.parts[0].0.x == (self.size_x - 1) as i32 {
|
||||
self.parts[0].0.x = 0;
|
||||
} else {
|
||||
self.parts[0].0.x += 1;
|
||||
}
|
||||
}
|
||||
Direction::Up => {
|
||||
if self.parts[0].0.y == 0 {
|
||||
self.parts[0].0.y = (self.size_y - 1) as i32;
|
||||
} else {
|
||||
self.parts[0].0.y -= 1;
|
||||
}
|
||||
}
|
||||
Direction::Down => {
|
||||
if self.parts[0].0.y == (self.size_y - 1) as i32 {
|
||||
self.parts[0].0.y = 0;
|
||||
} else {
|
||||
self.parts[0].0.y += 1;
|
||||
}
|
||||
}
|
||||
Direction::None => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Food<T: PixelColor> {
|
||||
size_x: u32,
|
||||
size_y: u32,
|
||||
place: Pixel<T>,
|
||||
rng: oorandom::Rand32,
|
||||
}
|
||||
|
||||
impl<T: PixelColor> Food<T> {
|
||||
pub fn new(color: T, size_x: u32, size_y: u32) -> Self {
|
||||
let seed = 4;
|
||||
let rng = oorandom::Rand32::new(seed);
|
||||
Food {
|
||||
size_x,
|
||||
size_y,
|
||||
place: Pixel(Point { x: 0, y: 0 }, color),
|
||||
rng,
|
||||
}
|
||||
}
|
||||
fn replace<'a, const MAX_SIZE: usize>(&mut self, iter_source: &Snake<T, MAX_SIZE>) {
|
||||
let mut p: Point;
|
||||
'outer: loop {
|
||||
let random_number = self.rng.rand_u32();
|
||||
let blocked_positions = iter_source.into_iter();
|
||||
p = Point {
|
||||
x: ((random_number >> 24) as u16 % self.size_x as u16).into(),
|
||||
y: ((random_number >> 16) as u16 % self.size_y as u16).into(),
|
||||
};
|
||||
for blocked_position in blocked_positions {
|
||||
if p == blocked_position.0 {
|
||||
continue 'outer;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
self.place = Pixel::<T> {
|
||||
0: p,
|
||||
1: self.place.1,
|
||||
}
|
||||
}
|
||||
fn get_pixel(&self) -> Pixel<T> {
|
||||
self.place
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug, Clone, Copy)]
|
||||
pub enum Direction {
|
||||
Left,
|
||||
Right,
|
||||
Up,
|
||||
Down,
|
||||
None,
|
||||
}
|
||||
|
||||
pub struct SnakeGame<const MAX_SNAKE_SIZE: usize, T: PixelColor> {
|
||||
snake: Snake<T, MAX_SNAKE_SIZE>,
|
||||
food: Food<T>,
|
||||
food_age: u32,
|
||||
food_lifetime: u32,
|
||||
size_x: u32,
|
||||
size_y: u32,
|
||||
scale_x: u32,
|
||||
scale_y: u32,
|
||||
}
|
||||
|
||||
impl<const MAX_SIZE: usize, T: PixelColor> SnakeGame<MAX_SIZE, T> {
|
||||
pub fn new(
|
||||
size_x: u32,
|
||||
size_y: u32,
|
||||
scale_x: u32,
|
||||
scale_y: u32,
|
||||
snake_color: T,
|
||||
food_color: T,
|
||||
food_lifetime: u32,
|
||||
) -> Self {
|
||||
let snake = Snake::<T, MAX_SIZE>::new(snake_color, size_x / scale_x, size_y / scale_y);
|
||||
let mut food = Food::<T>::new(food_color, size_x / scale_x, size_y / scale_y);
|
||||
food.replace(&snake);
|
||||
SnakeGame {
|
||||
snake,
|
||||
food,
|
||||
food_age: 0,
|
||||
food_lifetime,
|
||||
size_x,
|
||||
size_y,
|
||||
scale_x,
|
||||
scale_y,
|
||||
}
|
||||
}
|
||||
pub fn set_direction(&mut self, direction: Direction) {
|
||||
self.snake.set_direction(direction);
|
||||
}
|
||||
pub fn draw<D>(&mut self, target: &mut D) -> ()
|
||||
where
|
||||
D: DrawTarget<Color = T>,
|
||||
{
|
||||
self.snake.make_step();
|
||||
let hit = self.snake.contains(self.food.get_pixel().0);
|
||||
if hit {
|
||||
self.snake.grow();
|
||||
}
|
||||
self.food_age += 1;
|
||||
if self.food_age >= self.food_lifetime || hit {
|
||||
self.food.replace(&self.snake);
|
||||
self.food_age = 0;
|
||||
}
|
||||
|
||||
let mut scaled_display = ScaledDisplay::<D> {
|
||||
real_display: target,
|
||||
size_x: self.size_x / self.scale_x,
|
||||
size_y: self.size_y / self.scale_y,
|
||||
scale_x: self.scale_x,
|
||||
scale_y: self.scale_y,
|
||||
};
|
||||
|
||||
for part in self.snake.into_iter() {
|
||||
_ = part.draw(&mut scaled_display);
|
||||
}
|
||||
_ = self.food.get_pixel().draw(&mut scaled_display);
|
||||
}
|
||||
}
|
||||
|
||||
/// A dummy DrawTarget implementation that can magnify each pixel so the user code does not need to adapt for scaling things
|
||||
struct ScaledDisplay<'a, T: DrawTarget> {
|
||||
real_display: &'a mut T,
|
||||
size_x: u32,
|
||||
size_y: u32,
|
||||
scale_x: u32,
|
||||
scale_y: u32,
|
||||
}
|
||||
|
||||
impl<'a, T: DrawTarget> DrawTarget for ScaledDisplay<'a, T> {
|
||||
type Color = T::Color;
|
||||
type Error = T::Error;
|
||||
|
||||
fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
|
||||
where
|
||||
I: IntoIterator<Item = Pixel<Self::Color>>,
|
||||
{
|
||||
for pixel in pixels {
|
||||
let style = PrimitiveStyle::with_fill(pixel.1);
|
||||
Rectangle::new(
|
||||
Point::new(
|
||||
pixel.0.x * self.scale_x as i32,
|
||||
pixel.0.y * self.scale_y as i32,
|
||||
),
|
||||
Size::new(self.scale_x as u32, self.scale_y as u32),
|
||||
)
|
||||
.into_styled(style)
|
||||
.draw(self.real_display)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: DrawTarget> OriginDimensions for ScaledDisplay<'a, T> {
|
||||
fn size(&self) -> Size {
|
||||
Size::new(self.size_x as u32, self.size_y as u32)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use crate::Snake;
|
||||
use embedded_graphics::pixelcolor::*;
|
||||
use embedded_graphics::prelude::*;
|
||||
|
||||
#[test]
|
||||
fn snake_basic() {
|
||||
let mut snake = Snake::<Rgb888, 20>::new(Rgb888::RED, 8, 8);
|
||||
snake.set_direction(crate::Direction::Right);
|
||||
assert_eq!(
|
||||
Pixel::<Rgb888>(Point { x: 0, y: 0 }, Rgb888::RED),
|
||||
snake.into_iter().next().unwrap()
|
||||
);
|
||||
snake.make_step();
|
||||
assert_eq!(
|
||||
Pixel::<Rgb888>(Point { x: 1, y: 0 }, Rgb888::RED),
|
||||
snake.into_iter().nth(0).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
Pixel::<Rgb888>(Point { x: 0, y: 0 }, Rgb888::RED),
|
||||
snake.into_iter().nth(1).unwrap()
|
||||
);
|
||||
snake.set_direction(crate::Direction::Down);
|
||||
snake.make_step();
|
||||
assert_eq!(
|
||||
Pixel::<Rgb888>(Point { x: 1, y: 1 }, Rgb888::RED),
|
||||
snake.into_iter().nth(0).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
Pixel::<Rgb888>(Point { x: 1, y: 0 }, Rgb888::RED),
|
||||
snake.into_iter().nth(1).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
Pixel::<Rgb888>(Point { x: 0, y: 0 }, Rgb888::RED),
|
||||
snake.into_iter().nth(2).unwrap()
|
||||
);
|
||||
assert_eq!(true, snake.contains(Point { x: 0, y: 0 }));
|
||||
assert_eq!(true, snake.contains(Point { x: 1, y: 0 }));
|
||||
assert_eq!(true, snake.contains(Point { x: 1, y: 1 }));
|
||||
}
|
||||
}
|
||||
|
||||
const LF: u8 = 0x0au8;
|
||||
const CR: u8 = 0x0du8;
|
||||
#[no_mangle]
|
||||
pub fn main() -> i32 {
|
||||
let mut disp = Display::new(Size::new(VIRTGPU_XRES, VIRTGPU_YRES));
|
||||
let mut game = SnakeGame::<20, Rgb888>::new(1280, 800, 20, 20, Rgb888::RED, Rgb888::YELLOW, 50);
|
||||
let _ = disp.clear(Rgb888::BLACK).unwrap();
|
||||
loop {
|
||||
if key_pressed() {
|
||||
let c = getchar();
|
||||
match c {
|
||||
LF => break,
|
||||
CR => break,
|
||||
b'w' => game.set_direction(Direction::Up),
|
||||
b's' => game.set_direction(Direction::Down),
|
||||
b'a' => game.set_direction(Direction::Left),
|
||||
b'd' => game.set_direction(Direction::Right),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
let _ = disp.clear(Rgb888::BLACK).unwrap();
|
||||
game.draw(&mut disp);
|
||||
sleep(10);
|
||||
}
|
||||
0
|
||||
}
|
125
user/src/bin/gui_uart.rs
Normal file
125
user/src/bin/gui_uart.rs
Normal file
@ -0,0 +1,125 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
#[macro_use]
|
||||
extern crate user_lib;
|
||||
extern crate alloc;
|
||||
|
||||
use user_lib::console::getchar;
|
||||
use user_lib::{framebuffer, framebuffer_flush};
|
||||
|
||||
use embedded_graphics::pixelcolor::Rgb888;
|
||||
use embedded_graphics::prelude::{Drawable, Point, RgbColor, Size};
|
||||
use embedded_graphics::primitives::Primitive;
|
||||
use embedded_graphics::primitives::{PrimitiveStyle, Rectangle};
|
||||
use embedded_graphics::{draw_target::DrawTarget, prelude::OriginDimensions};
|
||||
|
||||
pub const VIRTGPU_XRES: usize = 1280;
|
||||
pub const VIRTGPU_YRES: usize = 800;
|
||||
pub const VIRTGPU_LEN: usize = VIRTGPU_XRES * VIRTGPU_YRES * 4;
|
||||
|
||||
const INIT_X: i32 = 640;
|
||||
const INIT_Y: i32 = 400;
|
||||
const RECT_SIZE: u32 = 40;
|
||||
|
||||
pub struct Display {
|
||||
pub size: Size,
|
||||
pub point: Point,
|
||||
//pub fb: Arc<&'static mut [u8]>,
|
||||
pub fb: &'static mut [u8],
|
||||
}
|
||||
|
||||
impl Display {
|
||||
pub fn new(size: Size, point: Point) -> Self {
|
||||
let fb_ptr = framebuffer() as *mut u8;
|
||||
println!(
|
||||
"Hello world from user mode program! 0x{:X} , len {}",
|
||||
fb_ptr as usize, VIRTGPU_LEN
|
||||
);
|
||||
let fb =
|
||||
unsafe { core::slice::from_raw_parts_mut(fb_ptr as *mut u8, VIRTGPU_LEN as usize) };
|
||||
Self { size, point, fb }
|
||||
}
|
||||
}
|
||||
|
||||
impl OriginDimensions for Display {
|
||||
fn size(&self) -> Size {
|
||||
self.size
|
||||
}
|
||||
}
|
||||
|
||||
impl DrawTarget for Display {
|
||||
type Color = Rgb888;
|
||||
|
||||
type Error = core::convert::Infallible;
|
||||
|
||||
fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
|
||||
where
|
||||
I: IntoIterator<Item = embedded_graphics::Pixel<Self::Color>>,
|
||||
{
|
||||
pixels.into_iter().for_each(|px| {
|
||||
let idx = ((self.point.y + px.0.y) * VIRTGPU_XRES as i32 + self.point.x + px.0.x)
|
||||
as usize
|
||||
* 4;
|
||||
if idx + 2 >= self.fb.len() {
|
||||
return;
|
||||
}
|
||||
self.fb[idx] = px.1.b();
|
||||
self.fb[idx + 1] = px.1.g();
|
||||
self.fb[idx + 2] = px.1.r();
|
||||
});
|
||||
framebuffer_flush();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DrawingBoard {
|
||||
disp: Display,
|
||||
latest_pos: Point,
|
||||
}
|
||||
|
||||
impl DrawingBoard {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
disp: Display::new(Size::new(1280, 800), Point::new(0, 0)),
|
||||
latest_pos: Point::new(INIT_X, INIT_Y),
|
||||
}
|
||||
}
|
||||
fn paint(&mut self) {
|
||||
Rectangle::with_center(self.latest_pos, Size::new(RECT_SIZE, RECT_SIZE))
|
||||
.into_styled(PrimitiveStyle::with_stroke(Rgb888::WHITE, 1))
|
||||
.draw(&mut self.disp)
|
||||
.ok();
|
||||
}
|
||||
fn unpaint(&mut self) {
|
||||
Rectangle::with_center(self.latest_pos, Size::new(RECT_SIZE, RECT_SIZE))
|
||||
.into_styled(PrimitiveStyle::with_stroke(Rgb888::BLACK, 1))
|
||||
.draw(&mut self.disp)
|
||||
.ok();
|
||||
}
|
||||
pub fn move_rect(&mut self, dx: i32, dy: i32) {
|
||||
self.unpaint();
|
||||
self.latest_pos.x += dx;
|
||||
self.latest_pos.y += dy;
|
||||
self.paint();
|
||||
}
|
||||
}
|
||||
|
||||
const LF: u8 = 0x0au8;
|
||||
const CR: u8 = 0x0du8;
|
||||
#[no_mangle]
|
||||
pub fn main() -> i32 {
|
||||
// let fb_ptr = framebuffer() as *mut u8;
|
||||
let mut board = DrawingBoard::new();
|
||||
let _ = board.disp.clear(Rgb888::BLACK).unwrap();
|
||||
for i in 0..20 {
|
||||
let c=getchar();
|
||||
if c == LF || c == CR {
|
||||
break;
|
||||
}
|
||||
board.latest_pos.x += i;
|
||||
board.latest_pos.y += i;
|
||||
board.paint();
|
||||
}
|
||||
0
|
||||
}
|
25
user/src/bin/inputdev_event.rs
Normal file
25
user/src/bin/inputdev_event.rs
Normal file
@ -0,0 +1,25 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use user_lib::{event_get, DecodeType, Key, KeyType};
|
||||
|
||||
#[macro_use]
|
||||
extern crate user_lib;
|
||||
|
||||
#[no_mangle]
|
||||
pub fn main() -> i32 {
|
||||
println!("Input device event test");
|
||||
loop {
|
||||
if let Some(event) = event_get() {
|
||||
if let Some(decoder_type) = event.decode() {
|
||||
println!("{:?}", decoder_type);
|
||||
if let DecodeType::Key(key, keytype) = decoder_type {
|
||||
if key == Key::Enter && keytype == KeyType::Press {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
0
|
||||
}
|
@ -14,7 +14,7 @@ use user_lib::{thread_create, waittid};
|
||||
|
||||
const SEM_MUTEX: usize = 0;
|
||||
const SEM_EMPTY: usize = 1;
|
||||
const SEM_EXISTED: usize = 2;
|
||||
const SEM_AVAIL: usize = 2;
|
||||
const BUFFER_SIZE: usize = 8;
|
||||
static mut BUFFER: [usize; BUFFER_SIZE] = [0; BUFFER_SIZE];
|
||||
static mut FRONT: usize = 0;
|
||||
@ -27,20 +27,20 @@ unsafe fn producer(id: *const usize) -> ! {
|
||||
for _ in 0..NUMBER_PER_PRODUCER {
|
||||
semaphore_down(SEM_EMPTY);
|
||||
semaphore_down(SEM_MUTEX);
|
||||
BUFFER[FRONT] = id;
|
||||
FRONT = (FRONT + 1) % BUFFER_SIZE;
|
||||
BUFFER[TAIL] = id;
|
||||
TAIL = (TAIL + 1) % BUFFER_SIZE;
|
||||
semaphore_up(SEM_MUTEX);
|
||||
semaphore_up(SEM_EXISTED);
|
||||
semaphore_up(SEM_AVAIL);
|
||||
}
|
||||
exit(0)
|
||||
}
|
||||
|
||||
unsafe fn consumer() -> ! {
|
||||
for _ in 0..PRODUCER_COUNT * NUMBER_PER_PRODUCER {
|
||||
semaphore_down(SEM_EXISTED);
|
||||
semaphore_down(SEM_AVAIL);
|
||||
semaphore_down(SEM_MUTEX);
|
||||
print!("{} ", BUFFER[TAIL]);
|
||||
TAIL = (TAIL + 1) % BUFFER_SIZE;
|
||||
print!("{} ", BUFFER[FRONT]);
|
||||
FRONT = (FRONT + 1) % BUFFER_SIZE;
|
||||
semaphore_up(SEM_MUTEX);
|
||||
semaphore_up(SEM_EMPTY);
|
||||
}
|
||||
@ -53,7 +53,7 @@ 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);
|
||||
assert_eq!(semaphore_create(0) as usize, SEM_AVAIL);
|
||||
// create threads
|
||||
let ids: Vec<_> = (0..PRODUCER_COUNT).collect();
|
||||
let mut threads = Vec::new();
|
||||
|
@ -10,7 +10,7 @@ extern crate core;
|
||||
use alloc::vec::Vec;
|
||||
use core::sync::atomic::{AtomicUsize, Ordering};
|
||||
use user_lib::{exit, sleep, thread_create, waittid};
|
||||
const N: usize = 3;
|
||||
const N: usize = 1000;
|
||||
|
||||
static mut TURN: usize = 0;
|
||||
static mut FLAG: [bool; 2] = [false; 2];
|
||||
@ -29,27 +29,30 @@ fn critical_test_exit() {
|
||||
}
|
||||
|
||||
fn peterson_enter_critical(id: usize, peer_id: usize) {
|
||||
println!("Thread[{}] try enter", id);
|
||||
// println!("Thread[{}] try enter", id);
|
||||
vstore!(&FLAG[id], true);
|
||||
vstore!(&TURN, peer_id);
|
||||
memory_fence!();
|
||||
while vload!(&FLAG[peer_id]) && vload!(&TURN) == peer_id {
|
||||
println!("Thread[{}] enter fail", id);
|
||||
// println!("Thread[{}] enter fail", id);
|
||||
sleep(1);
|
||||
println!("Thread[{}] retry enter", id);
|
||||
// println!("Thread[{}] retry enter", id);
|
||||
}
|
||||
println!("Thread[{}] enter", id);
|
||||
// println!("Thread[{}] enter", id);
|
||||
}
|
||||
|
||||
fn peterson_exit_critical(id: usize) {
|
||||
vstore!(&FLAG[id], false);
|
||||
println!("Thread[{}] exit", id);
|
||||
// println!("Thread[{}] exit", id);
|
||||
}
|
||||
|
||||
pub fn thread_fn(id: usize) -> ! {
|
||||
println!("Thread[{}] init.", id);
|
||||
// println!("Thread[{}] init.", id);
|
||||
let peer_id: usize = id ^ 1;
|
||||
for _ in 0..N {
|
||||
for iter in 0..N {
|
||||
if iter % 10 == 0 {
|
||||
println!("[{}] it={}", id, iter);
|
||||
}
|
||||
peterson_enter_critical(id, peer_id);
|
||||
critical_test_enter();
|
||||
for _ in 0..3 {
|
||||
|
@ -1,42 +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);
|
||||
0
|
||||
}
|
@ -1,51 +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);
|
||||
0
|
||||
}
|
@ -1,51 +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);
|
||||
0
|
||||
}
|
@ -1,46 +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_blocking_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_blocking_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);
|
||||
0
|
||||
}
|
@ -1,46 +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);
|
||||
0
|
||||
}
|
16
user/src/bin/random_num.rs
Normal file
16
user/src/bin/random_num.rs
Normal file
@ -0,0 +1,16 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
#[macro_use]
|
||||
extern crate user_lib;
|
||||
use oorandom;
|
||||
|
||||
#[no_mangle]
|
||||
pub fn main() -> i32 {
|
||||
println!("random num program!");
|
||||
let seed = 4;
|
||||
let mut rng = oorandom::Rand32::new(seed);
|
||||
println!("OORandom: Random number 32bit: {}", rng.rand_i32());
|
||||
println!("OORandom: Random number range: {}", rng.rand_range(1..100));
|
||||
0
|
||||
}
|
@ -27,19 +27,22 @@ static SUCC_TESTS: &[(&str, &str, &str, &str, i32)] = &[
|
||||
("phil_din_mutex\0", "\0", "\0", "\0", 0),
|
||||
("pipe_large_test\0", "\0", "\0", "\0", 0),
|
||||
("pipetest\0", "\0", "\0", "\0", 0),
|
||||
("race_adder_arg\0", "3\0", "\0", "\0", 0),
|
||||
("race_adder_atomic\0", "\0", "\0", "\0", 0),
|
||||
("race_adder_mutex_blocking\0", "\0", "\0", "\0", 0),
|
||||
("race_adder_mutex_spin\0", "\0", "\0", "\0", 0),
|
||||
("adder_peterson_spin\0", "\0", "\0", "\0", 0),
|
||||
("adder_peterson_yield\0", "\0", "\0", "\0", 0),
|
||||
("adder_mutex_blocking\0", "\0", "\0", "\0", 0),
|
||||
("adder_mutex_spin\0", "\0", "\0", "\0", 0),
|
||||
("run_pipe_test\0", "\0", "\0", "\0", 0),
|
||||
("sleep_simple\0", "\0", "\0", "\0", 0),
|
||||
("sleep\0", "\0", "\0", "\0", 0),
|
||||
("sleep_simple\0", "\0", "\0", "\0", 0),
|
||||
("sync_sem\0", "\0", "\0", "\0", 0),
|
||||
("test_condvar\0", "\0", "\0", "\0", 0),
|
||||
("condsync_sem\0", "\0", "\0", "\0", 0),
|
||||
("condsync_condvar\0", "\0", "\0", "\0", 0),
|
||||
("threads_arg\0", "\0", "\0", "\0", 0),
|
||||
("threads\0", "\0", "\0", "\0", 0),
|
||||
("yield\0", "\0", "\0", "\0", 0),
|
||||
("barrier_fail\0", "\0", "\0", "\0", 0),
|
||||
("barrier_condvar\0", "\0", "\0", "\0", 0),
|
||||
];
|
||||
|
||||
static FAIL_TESTS: &[(&str, &str, &str, &str, i32)] = &[
|
||||
@ -49,8 +52,9 @@ static FAIL_TESTS: &[(&str, &str, &str, &str, i32)] = &[
|
||||
("priv_inst\0", "\0", "\0", "\0", -4),
|
||||
("store_fault\0", "\0", "\0", "\0", -11),
|
||||
("until_timeout\0", "\0", "\0", "\0", -6),
|
||||
("race_adder\0", "\0", "\0", "\0", -6),
|
||||
("huge_write_mt\0", "\0", "\0", "\0", -6),
|
||||
("adder\0", "\0", "\0", "\0", -6),
|
||||
("adder_simple_spin\0", "\0", "\0", "\0", -6),
|
||||
("adder_simple_yield\0", "\0", "\0", "\0", -6),
|
||||
];
|
||||
|
||||
use user_lib::{exec, fork, waitpid};
|
||||
|
30
user/src/file.rs
Normal file
30
user/src/file.rs
Normal file
@ -0,0 +1,30 @@
|
||||
use super::*;
|
||||
|
||||
bitflags! {
|
||||
pub struct OpenFlags: u32 {
|
||||
const RDONLY = 0;
|
||||
const WRONLY = 1 << 0;
|
||||
const RDWR = 1 << 1;
|
||||
const CREATE = 1 << 9;
|
||||
const TRUNC = 1 << 10;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dup(fd: usize) -> isize {
|
||||
sys_dup(fd)
|
||||
}
|
||||
pub fn open(path: &str, flags: OpenFlags) -> isize {
|
||||
sys_open(path, flags.bits)
|
||||
}
|
||||
pub fn close(fd: usize) -> isize {
|
||||
sys_close(fd)
|
||||
}
|
||||
pub fn pipe(pipe_fd: &mut [usize]) -> isize {
|
||||
sys_pipe(pipe_fd)
|
||||
}
|
||||
pub fn read(fd: usize, buf: &mut [u8]) -> isize {
|
||||
sys_read(fd, buf)
|
||||
}
|
||||
pub fn write(fd: usize, buf: &[u8]) -> isize {
|
||||
sys_write(fd, buf)
|
||||
}
|
118
user/src/io.rs
Normal file
118
user/src/io.rs
Normal file
@ -0,0 +1,118 @@
|
||||
use super::*;
|
||||
use embedded_graphics::prelude::{RgbColor, Size};
|
||||
use embedded_graphics::{draw_target::DrawTarget, prelude::OriginDimensions};
|
||||
use embedded_graphics::pixelcolor::Rgb888;
|
||||
use virtio_input_decoder::Decoder;
|
||||
pub use virtio_input_decoder::{DecodeType, Key, KeyType, Mouse};
|
||||
|
||||
pub const VIRTGPU_XRES: u32 = 1280;
|
||||
pub const VIRTGPU_YRES: u32 = 800;
|
||||
pub const VIRTGPU_LEN: usize = (VIRTGPU_XRES * VIRTGPU_YRES * 4) as usize;
|
||||
|
||||
pub fn framebuffer() -> isize {
|
||||
sys_framebuffer()
|
||||
}
|
||||
pub fn framebuffer_flush() -> isize {
|
||||
sys_framebuffer_flush()
|
||||
}
|
||||
|
||||
pub struct Display {
|
||||
pub size: Size,
|
||||
pub fb: &'static mut [u8],
|
||||
}
|
||||
|
||||
impl Display {
|
||||
pub fn new(size: Size) -> Self {
|
||||
let fb_ptr = framebuffer() as *mut u8;
|
||||
let fb =
|
||||
unsafe { core::slice::from_raw_parts_mut(fb_ptr, VIRTGPU_LEN as usize) };
|
||||
Self { size, fb}
|
||||
}
|
||||
pub fn framebuffer(&mut self) -> &mut [u8] {
|
||||
self.fb
|
||||
}
|
||||
pub fn paint_on_framebuffer(&mut self, p: impl FnOnce(&mut [u8]) -> ()) {
|
||||
p(self.framebuffer());
|
||||
framebuffer_flush();
|
||||
}
|
||||
}
|
||||
|
||||
impl OriginDimensions for Display {
|
||||
fn size(&self) -> Size {
|
||||
self.size
|
||||
}
|
||||
}
|
||||
|
||||
impl DrawTarget for Display {
|
||||
type Color = Rgb888;
|
||||
|
||||
type Error = core::convert::Infallible;
|
||||
|
||||
fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
|
||||
where
|
||||
I: IntoIterator<Item = embedded_graphics::Pixel<Self::Color>>,
|
||||
{
|
||||
pixels.into_iter().for_each(|px| {
|
||||
let idx = (px.0.y * VIRTGPU_XRES as i32 + px.0.x)
|
||||
as usize
|
||||
* 4;
|
||||
if idx + 2 >= self.fb.len() {
|
||||
return;
|
||||
}
|
||||
self.fb[idx] = px.1.b();
|
||||
self.fb[idx + 1] = px.1.g();
|
||||
self.fb[idx + 2] = px.1.r();
|
||||
});
|
||||
framebuffer_flush();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn event_get() -> Option<InputEvent> {
|
||||
let raw_value = sys_event_get();
|
||||
if raw_value == 0 {
|
||||
None
|
||||
} else {
|
||||
Some((raw_value as u64).into())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn key_pressed() -> bool {
|
||||
if sys_key_pressed() == 1 {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct InputEvent {
|
||||
pub event_type: u16,
|
||||
pub code: u16,
|
||||
pub value: u32,
|
||||
}
|
||||
|
||||
impl From<u64> for InputEvent {
|
||||
fn from(mut v: u64) -> Self {
|
||||
let value = v as u32;
|
||||
v >>= 32;
|
||||
let code = v as u16;
|
||||
v >>= 16;
|
||||
let event_type = v as u16;
|
||||
Self {
|
||||
event_type,
|
||||
code,
|
||||
value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl InputEvent {
|
||||
pub fn decode(&self) -> Option<DecodeType> {
|
||||
Decoder::decode(
|
||||
self.event_type as usize,
|
||||
self.code as usize,
|
||||
self.value as usize,
|
||||
).ok()
|
||||
}
|
||||
}
|
151
user/src/lib.rs
151
user/src/lib.rs
@ -8,6 +8,10 @@
|
||||
pub mod console;
|
||||
mod lang_items;
|
||||
mod syscall;
|
||||
mod file;
|
||||
mod task;
|
||||
mod sync;
|
||||
mod io;
|
||||
|
||||
extern crate alloc;
|
||||
#[macro_use]
|
||||
@ -16,6 +20,10 @@ extern crate bitflags;
|
||||
use alloc::vec::Vec;
|
||||
use buddy_system_allocator::LockedHeap;
|
||||
use syscall::*;
|
||||
pub use file::*;
|
||||
pub use task::*;
|
||||
pub use sync::*;
|
||||
pub use io::*;
|
||||
|
||||
const USER_HEAP_SIZE: usize = 32768;
|
||||
|
||||
@ -59,149 +67,6 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dup(fd: usize) -> isize {
|
||||
sys_dup(fd)
|
||||
}
|
||||
pub fn connect(ip: u32, sport: u16, dport: u16) -> isize {
|
||||
sys_connect(ip, sport, dport)
|
||||
}
|
||||
pub fn open(path: &str, flags: OpenFlags) -> isize {
|
||||
sys_open(path, flags.bits)
|
||||
}
|
||||
pub fn close(fd: usize) -> isize {
|
||||
sys_close(fd)
|
||||
}
|
||||
pub fn pipe(pipe_fd: &mut [usize]) -> isize {
|
||||
sys_pipe(pipe_fd)
|
||||
}
|
||||
pub fn read(fd: usize, buf: &mut [u8]) -> isize {
|
||||
sys_read(fd, buf)
|
||||
}
|
||||
pub fn write(fd: usize, buf: &[u8]) -> isize {
|
||||
sys_write(fd, buf)
|
||||
}
|
||||
pub fn exit(exit_code: i32) -> ! {
|
||||
sys_exit(exit_code);
|
||||
}
|
||||
pub fn yield_() -> isize {
|
||||
sys_yield()
|
||||
}
|
||||
pub fn get_time() -> isize {
|
||||
sys_get_time()
|
||||
}
|
||||
pub fn getpid() -> isize {
|
||||
sys_getpid()
|
||||
}
|
||||
pub fn fork() -> isize {
|
||||
sys_fork()
|
||||
}
|
||||
pub fn exec(path: &str, args: &[*const u8]) -> isize {
|
||||
sys_exec(path, args)
|
||||
}
|
||||
pub fn wait(exit_code: &mut i32) -> isize {
|
||||
loop {
|
||||
match sys_waitpid(-1, exit_code as *mut _) {
|
||||
-2 => {
|
||||
yield_();
|
||||
}
|
||||
// -1 or a real pid
|
||||
exit_pid => return exit_pid,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn waitpid(pid: usize, exit_code: &mut i32) -> isize {
|
||||
loop {
|
||||
match sys_waitpid(pid as isize, exit_code as *mut _) {
|
||||
-2 => {
|
||||
yield_();
|
||||
}
|
||||
// -1 or a real pid
|
||||
exit_pid => return exit_pid,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn waitpid_nb(pid: usize, exit_code: &mut i32) -> isize {
|
||||
sys_waitpid(pid as isize, exit_code as *mut _)
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
pub struct SignalFlags: i32 {
|
||||
const SIGINT = 1 << 2;
|
||||
const SIGILL = 1 << 4;
|
||||
const SIGABRT = 1 << 6;
|
||||
const SIGFPE = 1 << 8;
|
||||
const SIGSEGV = 1 << 11;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn kill(pid: usize, signal: i32) -> isize {
|
||||
sys_kill(pid, signal)
|
||||
}
|
||||
|
||||
pub fn sleep(sleep_ms: usize) {
|
||||
sys_sleep(sleep_ms);
|
||||
}
|
||||
|
||||
pub fn thread_create(entry: usize, arg: usize) -> isize {
|
||||
sys_thread_create(entry, arg)
|
||||
}
|
||||
pub fn gettid() -> isize {
|
||||
sys_gettid()
|
||||
}
|
||||
pub fn 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) {
|
||||
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 semaphore_down(sem_id: usize) {
|
||||
sys_semaphore_down(sem_id);
|
||||
}
|
||||
pub fn condvar_create() -> isize {
|
||||
sys_condvar_create(0)
|
||||
}
|
||||
pub fn condvar_signal(condvar_id: usize) {
|
||||
sys_condvar_signal(condvar_id);
|
||||
}
|
||||
pub fn condvar_wait(condvar_id: usize, mutex_id: usize) {
|
||||
sys_condvar_wait(condvar_id, mutex_id);
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! vstore {
|
||||
($var_ref: expr, $value: expr) => {
|
||||
|
32
user/src/sync.rs
Normal file
32
user/src/sync.rs
Normal file
@ -0,0 +1,32 @@
|
||||
use super::*;
|
||||
|
||||
pub fn mutex_create() -> isize {
|
||||
sys_mutex_create(false)
|
||||
}
|
||||
pub fn mutex_blocking_create() -> isize {
|
||||
sys_mutex_create(true)
|
||||
}
|
||||
pub fn mutex_lock(mutex_id: usize) {
|
||||
sys_mutex_lock(mutex_id);
|
||||
}
|
||||
pub fn mutex_unlock(mutex_id: usize) {
|
||||
sys_mutex_unlock(mutex_id);
|
||||
}
|
||||
pub fn semaphore_create(res_count: usize) -> isize {
|
||||
sys_semaphore_create(res_count)
|
||||
}
|
||||
pub fn semaphore_up(sem_id: usize) {
|
||||
sys_semaphore_up(sem_id);
|
||||
}
|
||||
pub fn semaphore_down(sem_id: usize) {
|
||||
sys_semaphore_down(sem_id);
|
||||
}
|
||||
pub fn condvar_create() -> isize {
|
||||
sys_condvar_create()
|
||||
}
|
||||
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);
|
||||
}
|
@ -26,6 +26,10 @@ const SYSCALL_SEMAPHORE_DOWN: usize = 1022;
|
||||
const SYSCALL_CONDVAR_CREATE: usize = 1030;
|
||||
const SYSCALL_CONDVAR_SIGNAL: usize = 1031;
|
||||
const SYSCALL_CONDVAR_WAIT: usize = 1032;
|
||||
const SYSCALL_FRAMEBUFFER: usize = 2000;
|
||||
const SYSCALL_FRAMEBUFFER_FLUSH: usize = 2001;
|
||||
const SYSCALL_EVENT_GET: usize = 3000;
|
||||
const SYSCALL_KEY_PRESSED: usize = 3001;
|
||||
|
||||
fn syscall(id: usize, args: [usize; 3]) -> isize {
|
||||
let mut ret: isize;
|
||||
@ -148,8 +152,8 @@ 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_create() -> isize {
|
||||
syscall(SYSCALL_CONDVAR_CREATE, [0, 0, 0])
|
||||
}
|
||||
|
||||
pub fn sys_condvar_signal(condvar_id: usize) -> isize {
|
||||
@ -159,3 +163,20 @@ pub fn sys_condvar_signal(condvar_id: usize) -> isize {
|
||||
pub fn sys_condvar_wait(condvar_id: usize, mutex_id: usize) -> isize {
|
||||
syscall(SYSCALL_CONDVAR_WAIT, [condvar_id, mutex_id, 0])
|
||||
}
|
||||
|
||||
|
||||
pub fn sys_framebuffer() -> isize {
|
||||
syscall(SYSCALL_FRAMEBUFFER, [0, 0, 0])
|
||||
}
|
||||
|
||||
pub fn sys_framebuffer_flush() -> isize {
|
||||
syscall(SYSCALL_FRAMEBUFFER_FLUSH, [0, 0, 0])
|
||||
}
|
||||
|
||||
pub fn sys_event_get() -> isize {
|
||||
syscall(SYSCALL_EVENT_GET, [0, 0, 0])
|
||||
}
|
||||
|
||||
pub fn sys_key_pressed() -> isize {
|
||||
syscall(SYSCALL_KEY_PRESSED, [0, 0, 0])
|
||||
}
|
85
user/src/task.rs
Normal file
85
user/src/task.rs
Normal file
@ -0,0 +1,85 @@
|
||||
use super::*;
|
||||
|
||||
pub fn exit(exit_code: i32) -> ! {
|
||||
sys_exit(exit_code);
|
||||
}
|
||||
pub fn yield_() -> isize {
|
||||
sys_yield()
|
||||
}
|
||||
pub fn get_time() -> isize {
|
||||
sys_get_time()
|
||||
}
|
||||
pub fn getpid() -> isize {
|
||||
sys_getpid()
|
||||
}
|
||||
pub fn fork() -> isize {
|
||||
sys_fork()
|
||||
}
|
||||
pub fn exec(path: &str, args: &[*const u8]) -> isize {
|
||||
sys_exec(path, args)
|
||||
}
|
||||
pub fn connect(raddr: u32, lport: u16, rport: u16) -> isize {
|
||||
sys_connect(raddr, lport, rport)
|
||||
}
|
||||
pub fn wait(exit_code: &mut i32) -> isize {
|
||||
loop {
|
||||
match sys_waitpid(-1, exit_code as *mut _) {
|
||||
-2 => {
|
||||
yield_();
|
||||
}
|
||||
// -1 or a real pid
|
||||
exit_pid => return exit_pid,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn waitpid(pid: usize, exit_code: &mut i32) -> isize {
|
||||
loop {
|
||||
match sys_waitpid(pid as isize, exit_code as *mut _) {
|
||||
-2 => {
|
||||
yield_();
|
||||
}
|
||||
// -1 or a real pid
|
||||
exit_pid => return exit_pid,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn waitpid_nb(pid: usize, exit_code: &mut i32) -> isize {
|
||||
sys_waitpid(pid as isize, exit_code as *mut _)
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
pub struct SignalFlags: i32 {
|
||||
const SIGINT = 1 << 2;
|
||||
const SIGILL = 1 << 4;
|
||||
const SIGABRT = 1 << 6;
|
||||
const SIGFPE = 1 << 8;
|
||||
const SIGSEGV = 1 << 11;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn kill(pid: usize, signal: i32) -> isize {
|
||||
sys_kill(pid, signal)
|
||||
}
|
||||
|
||||
pub fn sleep(sleep_ms: usize) {
|
||||
sys_sleep(sleep_ms);
|
||||
}
|
||||
|
||||
pub fn thread_create(entry: usize, arg: usize) -> isize {
|
||||
sys_thread_create(entry, arg)
|
||||
}
|
||||
pub fn gettid() -> isize {
|
||||
sys_gettid()
|
||||
}
|
||||
pub fn waittid(tid: usize) -> isize {
|
||||
loop {
|
||||
match sys_waittid(tid) {
|
||||
-2 => {
|
||||
yield_();
|
||||
}
|
||||
exit_code => return exit_code,
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user