add generic Lock struct and println macro

This commit is contained in:
Garen Tyler 2023-10-30 19:15:58 -06:00
parent b3be1f8d47
commit bc8aa35180
Signed by: garentyler
GPG Key ID: D7A048C454CB7054
10 changed files with 238 additions and 143 deletions

View File

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

View File

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

View File

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

View File

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

View 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() }
}
}

View File

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

View 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() }
}
}

View File

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

View File

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

View File

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