add generic Lock struct and println macro
This commit is contained in:
parent
b3be1f8d47
commit
bc8aa35180
@ -83,7 +83,6 @@ int pipewrite(struct pipe*, uint64, int);
|
||||
|
||||
// printf.c
|
||||
__attribute__((noreturn)) void panic(char *s);
|
||||
void printfinit(void);
|
||||
void printstr(char *s);
|
||||
void printint(int n);
|
||||
void printhex(int n);
|
||||
|
@ -14,7 +14,7 @@ pub mod uart;
|
||||
use crate::{
|
||||
fs::file::{devsw, CONSOLE},
|
||||
proc::{killed, myproc, procdump, wakeup},
|
||||
sync::spinmutex::SpinMutex,
|
||||
sync::mutex::Mutex,
|
||||
};
|
||||
use core::{ffi::c_void, ptr::addr_of_mut};
|
||||
use uart::UART0;
|
||||
@ -54,7 +54,7 @@ impl core::fmt::Write for Console {
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub static cons: SpinMutex<Console> = SpinMutex::new(Console {
|
||||
pub static cons: Mutex<Console> = Mutex::new(Console {
|
||||
buffer: [0u8; INPUT_BUF_SIZE],
|
||||
read_index: 0,
|
||||
write_index: 0,
|
||||
@ -108,7 +108,7 @@ pub fn consoleread(user_dst: i32, mut dst: u64, mut n: i32) -> i32 {
|
||||
let mut c;
|
||||
let mut cbuf;
|
||||
|
||||
let mut console = cons.lock();
|
||||
let mut console = cons.lock_spinning();
|
||||
|
||||
while n > 0 {
|
||||
// Wait until interrupt handler has put
|
||||
@ -172,7 +172,7 @@ pub unsafe fn consoleinit() {
|
||||
/// Do erase/kill processing, then append to cons.buf.
|
||||
/// Wake up consoleread() if a whole line has arrived.
|
||||
pub fn consoleintr(mut c: u8) {
|
||||
let mut console = cons.lock();
|
||||
let mut console = cons.lock_spinning();
|
||||
|
||||
if c == ctrl_x(b'P') {
|
||||
// Print process list.
|
||||
|
@ -1,30 +1,33 @@
|
||||
use crate::sync::spinlock::Spinlock;
|
||||
use crate::sync::lock::Lock;
|
||||
use core::ffi::{c_char, CStr};
|
||||
|
||||
pub use crate::panic;
|
||||
|
||||
#[no_mangle]
|
||||
pub static mut PRINT_LOCK: Spinlock = Spinlock::new();
|
||||
|
||||
#[repr(C)]
|
||||
pub struct PrintLock {
|
||||
pub lock: Spinlock,
|
||||
pub locking: i32,
|
||||
}
|
||||
pub static PRINT_LOCK: Lock = Lock::new();
|
||||
|
||||
/// Print out formatted text to the UART.
|
||||
/// Spins to acquire the lock.
|
||||
macro_rules! print {
|
||||
($($arg:tt)*) => {{
|
||||
use core::fmt::Write;
|
||||
|
||||
// Still unsafe because static mut.
|
||||
let _guard = unsafe { $crate::console::printf::PRINT_LOCK.lock() };
|
||||
let _guard = $crate::console::printf::PRINT_LOCK.lock_spinning();
|
||||
let mut cons = $crate::console::cons.lock_spinning();
|
||||
|
||||
let mut cons = $crate::console::cons.lock();
|
||||
let _ = core::write!(cons.as_mut(), $($arg)*);
|
||||
}};
|
||||
}
|
||||
pub(crate) use print;
|
||||
|
||||
macro_rules! println {
|
||||
($($arg:tt)*) => {{
|
||||
use $crate::console::printf::print;
|
||||
print!($($arg)*);
|
||||
print!("\n");
|
||||
}};
|
||||
}
|
||||
pub(crate) use println;
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn printint(n: i32) {
|
||||
print!("{}", n);
|
||||
@ -45,8 +48,3 @@ pub unsafe extern "C" fn printstr(s: *const c_char) {
|
||||
let s = CStr::from_ptr(s).to_str().unwrap_or_default();
|
||||
print!("{}", s);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn printfinit() {
|
||||
PRINT_LOCK = Spinlock::new();
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ pub mod trap;
|
||||
use crate::proc::cpuid;
|
||||
use core::ffi::{c_char, CStr};
|
||||
|
||||
pub(crate) use crate::console::printf::print;
|
||||
pub(crate) use crate::console::printf::{print, println};
|
||||
|
||||
pub static mut STARTED: bool = false;
|
||||
pub static mut PANICKED: bool = false;
|
||||
@ -60,9 +60,8 @@ pub const MAXPATH: usize = 128;
|
||||
pub unsafe extern "C" fn main() -> ! {
|
||||
if cpuid() == 0 {
|
||||
console::consoleinit();
|
||||
console::printf::printfinit();
|
||||
mem::kalloc::kinit();
|
||||
print!("\nxv6 kernel is booting\n");
|
||||
println!("\nxv6 kernel is booting");
|
||||
mem::virtual_memory::kvminit();
|
||||
mem::virtual_memory::kvminithart();
|
||||
proc::procinit();
|
||||
@ -97,21 +96,21 @@ fn panic_wrapper(panic_info: &core::panic::PanicInfo) -> ! {
|
||||
}
|
||||
|
||||
if let Some(s) = panic_info.message() {
|
||||
print!("{}\n", s);
|
||||
println!("{}", s);
|
||||
} else if let Some(s) = panic_info.payload().downcast_ref::<&str>() {
|
||||
print!("{}\n", s);
|
||||
println!("{}", s);
|
||||
} else if let Some(s) = panic_info.payload().downcast_ref::<&CStr>() {
|
||||
print!("{:?}\n", s);
|
||||
println!("{:?}", s);
|
||||
} else {
|
||||
print!("could not recover error message\n");
|
||||
println!("could not recover error message");
|
||||
}
|
||||
|
||||
print!("███████╗██╗ ██╗ ██████╗██╗ ██╗██╗██╗\n");
|
||||
print!("██╔════╝██║ ██║██╔════╝██║ ██╔╝██║██║\n");
|
||||
print!("█████╗ ██║ ██║██║ █████╔╝ ██║██║\n");
|
||||
print!("██╔══╝ ██║ ██║██║ ██╔═██╗ ╚═╝╚═╝\n");
|
||||
print!("██║ ╚██████╔╝╚██████╗██║ ██╗██╗██╗\n");
|
||||
print!("╚═╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝╚═╝╚═╝\n");
|
||||
println!("███████╗██╗ ██╗ ██████╗██╗ ██╗██╗██╗");
|
||||
println!("██╔════╝██║ ██║██╔════╝██║ ██╔╝██║██║");
|
||||
println!("█████╗ ██║ ██║██║ █████╔╝ ██║██║");
|
||||
println!("██╔══╝ ██║ ██║██║ ██╔═██╗ ╚═╝╚═╝");
|
||||
println!("██║ ╚██████╔╝╚██████╗██║ ██╗██╗██╗");
|
||||
println!("╚═╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝╚═╝╚═╝");
|
||||
|
||||
unsafe {
|
||||
crate::PANICKED = true;
|
||||
|
105
kernel/rustkernel/src/sync/lock.rs
Normal file
105
kernel/rustkernel/src/sync/lock.rs
Normal file
@ -0,0 +1,105 @@
|
||||
use super::LockStrategy;
|
||||
use crate::proc::{myproc, sched, sleep, wakeup, ProcState};
|
||||
use core::{
|
||||
cell::UnsafeCell,
|
||||
ops::Drop,
|
||||
ptr::{addr_of, null_mut},
|
||||
sync::atomic::{AtomicBool, Ordering},
|
||||
};
|
||||
|
||||
pub struct Lock {
|
||||
locked: AtomicBool,
|
||||
lock_strategy: UnsafeCell<LockStrategy>,
|
||||
}
|
||||
impl Lock {
|
||||
pub const fn new() -> Lock {
|
||||
Lock {
|
||||
locked: AtomicBool::new(false),
|
||||
lock_strategy: UnsafeCell::new(LockStrategy::Spin),
|
||||
}
|
||||
}
|
||||
pub fn lock_strategy(&self) -> LockStrategy {
|
||||
unsafe { *self.lock_strategy.get() }
|
||||
}
|
||||
|
||||
pub unsafe fn lock_unguarded(&self, lock_strategy: LockStrategy) {
|
||||
// Lock it first, then store the lock strategy.
|
||||
|
||||
match lock_strategy {
|
||||
LockStrategy::Spin => {
|
||||
crate::trap::push_intr_off();
|
||||
|
||||
while self.locked.swap(true, Ordering::Acquire) {
|
||||
core::hint::spin_loop();
|
||||
}
|
||||
}
|
||||
LockStrategy::Sleep => {
|
||||
while self.locked.swap(true, Ordering::Acquire) {
|
||||
// Put the process to sleep until the mutex gets released.
|
||||
sleep(addr_of!(*self).cast_mut().cast());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
*self.lock_strategy.get() = lock_strategy;
|
||||
}
|
||||
pub fn lock(&self, lock_strategy: LockStrategy) -> LockGuard<'_> {
|
||||
unsafe {
|
||||
self.lock_unguarded(lock_strategy);
|
||||
}
|
||||
LockGuard { lock: self }
|
||||
}
|
||||
pub fn lock_spinning(&self) -> LockGuard<'_> {
|
||||
self.lock(LockStrategy::Spin)
|
||||
}
|
||||
pub fn lock_sleeping(&self) -> LockGuard<'_> {
|
||||
self.lock(LockStrategy::Sleep)
|
||||
}
|
||||
pub unsafe fn unlock(&self) {
|
||||
let lock_strategy = self.lock_strategy();
|
||||
self.locked.store(false, Ordering::Release);
|
||||
|
||||
match lock_strategy {
|
||||
LockStrategy::Spin => {
|
||||
crate::trap::pop_intr_off();
|
||||
}
|
||||
LockStrategy::Sleep => {
|
||||
wakeup(addr_of!(*self).cast_mut().cast());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Default for Lock {
|
||||
fn default() -> Lock {
|
||||
Lock::new()
|
||||
}
|
||||
}
|
||||
unsafe impl Sync for Lock {}
|
||||
|
||||
pub struct LockGuard<'l> {
|
||||
pub lock: &'l Lock,
|
||||
}
|
||||
impl<'l> LockGuard<'l> {
|
||||
/// Sleep until `wakeup(chan)` is called somewhere
|
||||
/// else, yielding access to the lock until then.
|
||||
pub unsafe fn sleep(&self, chan: *mut core::ffi::c_void) {
|
||||
let p = myproc();
|
||||
let _guard = (*p).lock.lock();
|
||||
let strategy = self.lock.lock_strategy();
|
||||
self.lock.unlock();
|
||||
|
||||
// Put the process to sleep.
|
||||
(*p).chan = chan;
|
||||
(*p).state = ProcState::Sleeping;
|
||||
sched();
|
||||
|
||||
// Tidy up and reacquire the lock.
|
||||
(*p).chan = null_mut();
|
||||
self.lock.lock_unguarded(strategy);
|
||||
}
|
||||
}
|
||||
impl<'l> Drop for LockGuard<'l> {
|
||||
fn drop(&mut self) {
|
||||
unsafe { self.lock.unlock() }
|
||||
}
|
||||
}
|
@ -1,3 +1,13 @@
|
||||
pub mod lock;
|
||||
pub mod mutex;
|
||||
|
||||
// These have to stick around until the entire program is in rust =(
|
||||
pub mod sleeplock;
|
||||
pub mod spinlock;
|
||||
pub mod spinmutex;
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default, PartialEq)]
|
||||
pub enum LockStrategy {
|
||||
#[default]
|
||||
Spin,
|
||||
Sleep,
|
||||
}
|
||||
|
85
kernel/rustkernel/src/sync/mutex.rs
Normal file
85
kernel/rustkernel/src/sync/mutex.rs
Normal file
@ -0,0 +1,85 @@
|
||||
use super::{
|
||||
lock::{Lock, LockGuard},
|
||||
LockStrategy,
|
||||
};
|
||||
use core::{
|
||||
cell::UnsafeCell,
|
||||
convert::{AsMut, AsRef},
|
||||
ops::{Deref, DerefMut, Drop},
|
||||
};
|
||||
|
||||
pub struct Mutex<T> {
|
||||
lock: Lock,
|
||||
inner: UnsafeCell<T>,
|
||||
}
|
||||
impl<T> Mutex<T> {
|
||||
pub const fn new(value: T) -> Mutex<T> {
|
||||
Mutex {
|
||||
lock: Lock::new(),
|
||||
inner: UnsafeCell::new(value),
|
||||
}
|
||||
}
|
||||
pub unsafe fn as_inner(&self) -> *mut T {
|
||||
self.inner.get()
|
||||
}
|
||||
pub unsafe fn lock_unguarded(&self, lock_strategy: LockStrategy) {
|
||||
self.lock.lock_unguarded(lock_strategy);
|
||||
}
|
||||
pub fn lock(&self, lock_strategy: LockStrategy) -> MutexGuard<'_, T> {
|
||||
unsafe {
|
||||
self.lock_unguarded(lock_strategy);
|
||||
}
|
||||
MutexGuard { mutex: self }
|
||||
}
|
||||
pub fn lock_spinning(&self) -> MutexGuard<'_, T> {
|
||||
self.lock(LockStrategy::Spin)
|
||||
}
|
||||
pub fn lock_sleeping(&self) -> MutexGuard<'_, T> {
|
||||
self.lock(LockStrategy::Sleep)
|
||||
}
|
||||
pub unsafe fn unlock(&self) {
|
||||
self.lock.unlock();
|
||||
}
|
||||
}
|
||||
unsafe impl<T> Sync for Mutex<T> where T: Send {}
|
||||
|
||||
pub struct MutexGuard<'m, T> {
|
||||
pub mutex: &'m Mutex<T>,
|
||||
}
|
||||
impl<'m, T> MutexGuard<'m, T> {
|
||||
/// Sleep until `wakeup(chan)` is called somewhere else, yielding access to the mutex until then.
|
||||
pub unsafe fn sleep(&mut self, chan: *mut core::ffi::c_void) {
|
||||
let guard = LockGuard {
|
||||
lock: &self.mutex.lock,
|
||||
};
|
||||
guard.sleep(chan);
|
||||
core::mem::forget(guard);
|
||||
}
|
||||
}
|
||||
impl<'m, T> Deref for MutexGuard<'m, T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
unsafe { &*self.mutex.as_inner() }
|
||||
}
|
||||
}
|
||||
impl<'m, T> DerefMut for MutexGuard<'m, T> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
unsafe { &mut *self.mutex.as_inner() }
|
||||
}
|
||||
}
|
||||
impl<'m, T> AsRef<T> for MutexGuard<'m, T> {
|
||||
fn as_ref(&self) -> &T {
|
||||
self.deref()
|
||||
}
|
||||
}
|
||||
impl<'m, T> AsMut<T> for MutexGuard<'m, T> {
|
||||
fn as_mut(&mut self) -> &mut T {
|
||||
self.deref_mut()
|
||||
}
|
||||
}
|
||||
impl<'m, T> Drop for MutexGuard<'m, T> {
|
||||
fn drop(&mut self) {
|
||||
unsafe { self.mutex.unlock() }
|
||||
}
|
||||
}
|
@ -1,87 +0,0 @@
|
||||
use crate::{
|
||||
proc::{myproc, sched, ProcState},
|
||||
sync::spinlock::Spinlock,
|
||||
};
|
||||
use core::{
|
||||
cell::UnsafeCell,
|
||||
convert::{AsMut, AsRef},
|
||||
ops::{Deref, DerefMut, Drop},
|
||||
ptr::null_mut,
|
||||
};
|
||||
|
||||
pub struct SpinMutex<T> {
|
||||
lock: Spinlock,
|
||||
inner: UnsafeCell<T>,
|
||||
}
|
||||
impl<T> SpinMutex<T> {
|
||||
pub const fn new(value: T) -> SpinMutex<T> {
|
||||
SpinMutex {
|
||||
lock: Spinlock::new(),
|
||||
inner: UnsafeCell::new(value),
|
||||
}
|
||||
}
|
||||
pub unsafe fn as_inner(&self) -> *mut T {
|
||||
self.inner.get()
|
||||
}
|
||||
pub unsafe fn lock_unguarded(&self) {
|
||||
self.lock.lock_unguarded();
|
||||
}
|
||||
pub fn lock(&self) -> SpinMutexGuard<'_, T> {
|
||||
unsafe {
|
||||
self.lock_unguarded();
|
||||
}
|
||||
SpinMutexGuard { mutex: self }
|
||||
}
|
||||
pub unsafe fn unlock(&self) {
|
||||
self.lock.unlock();
|
||||
}
|
||||
}
|
||||
unsafe impl<T> Sync for SpinMutex<T> where T: Send {}
|
||||
|
||||
pub struct SpinMutexGuard<'m, T> {
|
||||
pub mutex: &'m SpinMutex<T>,
|
||||
}
|
||||
impl<'m, T> SpinMutexGuard<'m, T> {
|
||||
/// Sleep until `wakeup(chan)` is called somewhere else, yielding access to the mutex until then.
|
||||
pub unsafe fn sleep(&mut self, chan: *mut core::ffi::c_void) {
|
||||
let p = myproc();
|
||||
let _guard = (*p).lock.lock();
|
||||
self.mutex.unlock();
|
||||
|
||||
// Put the process to sleep.
|
||||
(*p).chan = chan;
|
||||
(*p).state = ProcState::Sleeping;
|
||||
sched();
|
||||
|
||||
// Tidy up and reacquire the mutex.
|
||||
(*p).chan = null_mut();
|
||||
self.mutex.lock_unguarded();
|
||||
}
|
||||
}
|
||||
impl<'m, T> Deref for SpinMutexGuard<'m, T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
unsafe { &*self.mutex.as_inner() }
|
||||
}
|
||||
}
|
||||
impl<'m, T> DerefMut for SpinMutexGuard<'m, T> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
unsafe { &mut *self.mutex.as_inner() }
|
||||
}
|
||||
}
|
||||
impl<'m, T> AsRef<T> for SpinMutexGuard<'m, T> {
|
||||
fn as_ref(&self) -> &T {
|
||||
self.deref()
|
||||
}
|
||||
}
|
||||
impl<'m, T> AsMut<T> for SpinMutexGuard<'m, T> {
|
||||
fn as_mut(&mut self) -> &mut T {
|
||||
self.deref_mut()
|
||||
}
|
||||
}
|
||||
impl<'m, T> Drop for SpinMutexGuard<'m, T> {
|
||||
fn drop(&mut self) {
|
||||
unsafe { self.mutex.unlock() }
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
console::printf::print,
|
||||
println,
|
||||
proc::{self, myproc, sleep_lock},
|
||||
riscv::{memlayout::QEMU_POWER, Pagetable},
|
||||
string::strlen,
|
||||
@ -261,25 +261,11 @@ pub unsafe extern "C" fn syscall() {
|
||||
let p = myproc();
|
||||
let num = (*(*p).trapframe).a7;
|
||||
|
||||
// print!("syscall {}\n", num);
|
||||
|
||||
(*(*p).trapframe).a0 = match TryInto::<Syscall>::try_into(num as usize) {
|
||||
Ok(syscall) => syscall.call(),
|
||||
Err(_) => {
|
||||
print!("{} unknown syscall {}\n", (*p).pid, num);
|
||||
println!("{} unknown syscall {}", (*p).pid, num);
|
||||
-1i64 as u64
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// #[no_mangle]
|
||||
// pub unsafe extern "C" fn rust_syscall(num: u64) -> u64 {
|
||||
// match TryInto::<Syscall>::try_into(num as usize) {
|
||||
// Ok(syscall) => syscall.call(),
|
||||
// Err(_) => {
|
||||
// print!("unknown syscall {}\n", num);
|
||||
// -1i64 as u64
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
console::printf::print,
|
||||
println,
|
||||
proc::{cpuid, exit, killed, mycpu, myproc, r#yield, setkilled, wakeup, ProcState},
|
||||
riscv::*,
|
||||
sync::spinlock::Spinlock,
|
||||
@ -60,7 +60,7 @@ pub unsafe extern "C" fn devintr() -> i32 {
|
||||
} else if irq == VIRTIO0_IRQ {
|
||||
virtio_disk_intr();
|
||||
} else if irq > 0 {
|
||||
print!("unexpected interrupt irq={}\n", irq);
|
||||
println!("unexpected interrupt irq={}", irq);
|
||||
}
|
||||
|
||||
// The PLIC allows each device to raise at most one
|
||||
@ -198,7 +198,7 @@ pub unsafe extern "C" fn kerneltrap() {
|
||||
|
||||
let which_dev = devintr();
|
||||
if which_dev == 0 {
|
||||
print!("scause {}\nsepc={} stval={}\n", scause, r_sepc(), r_stval());
|
||||
println!("scause {}\nsepc={} stval={}", scause, r_sepc(), r_stval());
|
||||
panic!("kerneltrap");
|
||||
} else if which_dev == 2 && !myproc().is_null() && (*myproc()).state == ProcState::Running {
|
||||
// Give up the CPU if this is a timer interrupt.
|
||||
@ -249,7 +249,7 @@ pub unsafe extern "C" fn usertrap() {
|
||||
|
||||
let which_dev = devintr();
|
||||
if r_scause() != 8 && which_dev == 0 {
|
||||
print!(
|
||||
println!(
|
||||
"usertrap(): unexpected scause {} {}\n\tsepc={} stval={}",
|
||||
r_scause(),
|
||||
(*p).pid,
|
||||
|
Loading…
x
Reference in New Issue
Block a user