From d06d271c9edea88124bca8f966d25046e551223d Mon Sep 17 00:00:00 2001 From: Garen Tyler Date: Sat, 21 Oct 2023 22:44:06 -0600 Subject: [PATCH] rename sleep to sleep_lock --- kernel/rustkernel/src/bio.rs | 34 ++++------ kernel/rustkernel/src/console.rs | 2 + kernel/rustkernel/src/pipe.rs | 18 ++++++ kernel/rustkernel/src/proc.rs | 24 +++++-- kernel/rustkernel/src/sync/mod.rs | 1 + kernel/rustkernel/src/sync/mutex.rs | 85 +++++++++++++++++++++++++ kernel/rustkernel/src/sync/sleeplock.rs | 19 ++++-- kernel/rustkernel/src/sync/spinlock.rs | 2 +- kernel/rustkernel/src/sysproc.rs | 4 +- kernel/rustkernel/src/uart.rs | 4 +- kernel/rustkernel/src/virtio_disk.rs | 77 +++++++++++----------- 11 files changed, 193 insertions(+), 77 deletions(-) create mode 100644 kernel/rustkernel/src/pipe.rs create mode 100644 kernel/rustkernel/src/sync/mutex.rs diff --git a/kernel/rustkernel/src/bio.rs b/kernel/rustkernel/src/bio.rs index 2fb579b..565ff20 100644 --- a/kernel/rustkernel/src/bio.rs +++ b/kernel/rustkernel/src/bio.rs @@ -1,10 +1,10 @@ //! Buffer cache. -//! +//! //! The buffer cache is a linked list of buf strctures holding //! cached copies of disk block contents. Caching disk blocks //! in memory reduces the number of disk reads and also provides //! a synchronization point for disk blocks used by multiple processes. -//! +//! //! Interface: //! - To get a buffer for a particular disk block, call bread. //! - After changing buffer data, call bwrite to write it to disk. @@ -13,28 +13,20 @@ //! - Only one process at a time can use a buffer, //! so do not keep them longer than necessary. -use crate::{ - sync::sleeplock::{holdingsleep, acquiresleep, releasesleep}, - sync::spinlock::Spinlock, - buf::Buffer, - param::NBUF, - virtio_disk::virtio_disk_rw, -}; -use core::ptr::addr_of_mut; +use crate::{buf::Buffer, param::NBUF, sync::spinlock::Spinlock}; pub struct BufferCache { pub buffers: [Buffer; NBUF], } impl BufferCache { /// Look through the buffer cache for block on device dev. - /// + /// /// If not found, allocate a buffer. /// In either case, return locked buffer. fn get(&mut self, dev: u32, blockno: u32) { for buf in &mut self.buffers { if buf.dev == dev && buf.blockno == blockno { buf.refcnt += 1; - } } } @@ -64,7 +56,7 @@ extern "C" { // pub unsafe extern "C" fn bget(dev: u32, blockno: u32) -> *mut Buffer { // let mut b: *mut Buffer; // let _guard = bcache.lock.lock(); -// +// // // Is the block already cached? // b = bcache.head.next; // while b != addr_of_mut!(bcache.head) { @@ -77,7 +69,7 @@ extern "C" { // b = (*b).next; // } // } -// +// // // Not cached. // // Recycle the least recently used unused buffer. // b = bcache.head.prev; @@ -92,7 +84,7 @@ extern "C" { // return b; // } // } -// +// // panic!("bget: no buffers"); // } @@ -100,22 +92,22 @@ extern "C" { // #[no_mangle] // pub unsafe extern "C" fn bread(dev: u32, blockno: u32) -> *mut Buffer { // let b = bget(dev, blockno); -// +// // if (*b).valid == 0 { // virtio_disk_rw(b, 0); // (*b).valid = 1; // } -// +// // b // } -// +// // #[no_mangle] // pub unsafe extern "C" fn bwrite(b: *mut Buffer) { // if holdingsleep(addr_of_mut!((*b).lock)) == 0 { // // if !(*b).lock.held_by_current_proc() { // panic!("bwrite"); // } -// +// // virtio_disk_rw(b, 1); // } @@ -125,11 +117,11 @@ extern "C" { // (*b).refcnt += 1; // // bcache.lock.unlock(); // } -// +// // #[no_mangle] // pub unsafe extern "C" fn bunpin(b: *mut Buffer) { // let _guard = bcache.lock.lock(); // (*b).refcnt -= 1; // // bcache.lock.unlock(); // } -// \ No newline at end of file +// diff --git a/kernel/rustkernel/src/console.rs b/kernel/rustkernel/src/console.rs index 316227d..fcb8a60 100644 --- a/kernel/rustkernel/src/console.rs +++ b/kernel/rustkernel/src/console.rs @@ -108,6 +108,8 @@ pub unsafe extern "C" fn consoleread(user_dst: i32, mut dst: u64, mut n: i32) -> // cons.lock.unlock(); return -1; } + // let channel = addr_of_mut!(console.read_index).cast(); + // console.sleep(channel); sleep_mutex(addr_of_mut!(console.read_index).cast(), &mut console); } diff --git a/kernel/rustkernel/src/pipe.rs b/kernel/rustkernel/src/pipe.rs new file mode 100644 index 0000000..c6c1aa5 --- /dev/null +++ b/kernel/rustkernel/src/pipe.rs @@ -0,0 +1,18 @@ +use crate::sync::spinlock::Spinlock; +use core::ffi::c_char; + +pub const PIPESIZE: usize = 512usize; + +#[repr(C)] +pub struct Pipe { + lock: Spinlock, + data: [c_char; PIPESIZE], + /// Number of bytes read. + nread: u32, + /// Number of bytes written. + nwrite: u32, + /// Read fd is still open. + readopen: i32, + /// Write fd is still open. + writeopen: i32, +} diff --git a/kernel/rustkernel/src/proc.rs b/kernel/rustkernel/src/proc.rs index f9f54f4..8be4f23 100644 --- a/kernel/rustkernel/src/proc.rs +++ b/kernel/rustkernel/src/proc.rs @@ -4,7 +4,7 @@ use crate::{ kalloc::kfree, param::*, riscv::{self, Pagetable, PTE_W}, - sync::spinlock::{pop_off, push_off, Spinlock}, + sync::spinlock::Spinlock, sync::spinmutex::SpinMutexGuard, }; use core::{ @@ -241,8 +241,7 @@ pub unsafe extern "C" fn mycpu() -> *mut Cpu { pub unsafe extern "C" fn myproc() -> *mut Proc { let _ = crate::trap::InterruptBlocker::new(); let c = mycpu(); - let p = (*c).proc; - p + (*c).proc } #[no_mangle] @@ -408,7 +407,7 @@ pub unsafe extern "C" fn sched() { /// Atomically release lock and sleep on chan. /// Reacquires lock when awakened. #[no_mangle] -pub unsafe extern "C" fn sleep(chan: *mut c_void, lock: *mut Spinlock) { +pub unsafe extern "C" fn sleep_lock(chan: *mut c_void, lock: *mut Spinlock) { let p = myproc(); // Must acquire p->lock in order to @@ -455,6 +454,20 @@ pub unsafe fn sleep_mutex(chan: *mut c_void, mutex: &mut SpinMutexGuard) { core::mem::forget(guard); } +// pub unsafe fn sleep(chan: *mut c_void) { +// let p = myproc(); +// let _guard = (*p).lock.lock(); +// +// // Go to sleep. +// (*p).chan = chan; +// (*p).state = ProcState::Sleeping; +// +// sched(); +// +// // Clean up. +// (*p).chan = null_mut(); +// } + /// Kill the process with the given pid. /// The victim won't exit until it tries to return /// to user space (see usertrap() in trap.c). @@ -486,6 +499,5 @@ pub unsafe extern "C" fn setkilled(p: *mut Proc) { #[no_mangle] pub unsafe extern "C" fn killed(p: *mut Proc) -> i32 { let _guard = (*p).lock.lock(); - let k = (*p).killed; - k + (*p).killed } diff --git a/kernel/rustkernel/src/sync/mod.rs b/kernel/rustkernel/src/sync/mod.rs index 3d543ce..cc007cb 100644 --- a/kernel/rustkernel/src/sync/mod.rs +++ b/kernel/rustkernel/src/sync/mod.rs @@ -1,3 +1,4 @@ +pub(crate) mod mutex; pub mod sleeplock; pub mod spinlock; pub mod spinmutex; diff --git a/kernel/rustkernel/src/sync/mutex.rs b/kernel/rustkernel/src/sync/mutex.rs new file mode 100644 index 0000000..89c664a --- /dev/null +++ b/kernel/rustkernel/src/sync/mutex.rs @@ -0,0 +1,85 @@ +// use core::{ +// cell::UnsafeCell, +// ops::{Deref, DerefMut, Drop}, +// sync::atomic::{AtomicBool, Ordering}, +// ffi::c_void, +// ptr::addr_of, +// }; +// use crate::proc::{sleep, wakeup, sched, myproc, ProcState}; +// +// pub struct Mutex { +// locked: AtomicBool, +// inner: UnsafeCell, +// } +// impl Mutex { +// pub const fn new(value: T) -> Mutex { +// Mutex { +// locked: AtomicBool::new(false), +// inner: UnsafeCell::new(value), +// } +// } +// pub unsafe fn get_inner(&self) -> *mut T { +// self.inner.get() +// } +// /// Spin until the mutex is unlocked, acquiring afterwards. +// pub fn spin_lock(&self) -> MutexGuard<'_, T> { +// while self.locked.swap(true, Ordering::Acquire) { +// core::hint::spin_loop(); +// } +// +// MutexGuard { mutex: self } +// } +// /// Sleep until the mutex is unlocked, acquiring afterwards. +// pub fn sleep_lock(&self) -> MutexGuard<'_, T> { +// while self.locked.swap(true, Ordering::Acquire) { +// unsafe { +// sleep(addr_of!(*self).cast_mut().cast()); +// } +// } +// +// MutexGuard { mutex: self } +// } +// pub unsafe fn unlock(&self) { +// self.locked.store(false, Ordering::Release); +// wakeup(addr_of!(*self).cast_mut().cast()); +// } +// } +// unsafe impl Sync for Mutex where T: Send {} +// +// pub struct MutexGuard<'m, T> { +// pub mutex: &'m Mutex, +// } +// impl<'m, T> MutexGuard<'m, T> { +// pub unsafe fn sleep(&mut self, channel: *mut c_void){ +// let p = myproc(); +// let _guard = (*p).lock.lock(); +// self.mutex.unlock(); +// +// // Go to sleep. +// (*p).chan = channel; +// (*p).state = ProcState::Sleeping; +// sched(); +// +// // Clean up. +// let guard = self.mutex.spin_lock(); +// core::mem::forget(guard); +// } +// } +// impl<'m, T> Deref for MutexGuard<'m, T> { +// type Target = T; +// +// fn deref(&self) -> &Self::Target { +// unsafe { &*self.mutex.get_inner() } +// } +// } +// impl<'m, T> DerefMut for MutexGuard<'m, T> { +// fn deref_mut(&mut self) -> &mut Self::Target { +// unsafe { &mut *self.mutex.get_inner() } +// } +// } +// impl<'m, T> Drop for MutexGuard<'m, T> { +// fn drop(&mut self) { +// unsafe { self.mutex.unlock() } +// } +// } +// diff --git a/kernel/rustkernel/src/sync/sleeplock.rs b/kernel/rustkernel/src/sync/sleeplock.rs index eb8a176..c2f767c 100644 --- a/kernel/rustkernel/src/sync/sleeplock.rs +++ b/kernel/rustkernel/src/sync/sleeplock.rs @@ -1,8 +1,11 @@ use crate::{ - proc::{myproc, sleep, wakeup}, - sync::spinlock::{self, Spinlock}, + proc::{myproc, sleep_lock, wakeup}, + sync::spinlock::Spinlock, +}; +use core::{ + ffi::c_char, + ptr::{addr_of, null_mut}, }; -use core::{ffi::c_char, ptr::{addr_of, null_mut}}; #[repr(C)] pub struct Sleeplock { @@ -31,12 +34,16 @@ impl Sleeplock { } /// Check whether this proc is holding the lock. pub fn held_by_current_proc(&self) -> bool { - self.locked > 0 && self.pid == unsafe { (*myproc()).pid } - } + self.locked > 0 && self.pid == unsafe { (*myproc()).pid } + } + #[allow(clippy::while_immutable_condition)] pub unsafe fn lock_unguarded(&self) { let _guard = self.inner.lock(); while self.locked > 0 { - sleep(addr_of!(*self).cast_mut().cast(), addr_of!(self.inner).cast_mut().cast()); + sleep_lock( + addr_of!(*self).cast_mut().cast(), + addr_of!(self.inner).cast_mut().cast(), + ); } let this: &mut Self = &mut *addr_of!(*self).cast_mut(); this.locked = 1; diff --git a/kernel/rustkernel/src/sync/spinlock.rs b/kernel/rustkernel/src/sync/spinlock.rs index a13c964..5e7835d 100644 --- a/kernel/rustkernel/src/sync/spinlock.rs +++ b/kernel/rustkernel/src/sync/spinlock.rs @@ -4,7 +4,7 @@ use crate::{ }; use core::{ ffi::c_char, - ptr::{null_mut, addr_of}, + ptr::{addr_of, null_mut}, sync::atomic::{AtomicBool, Ordering}, }; diff --git a/kernel/rustkernel/src/sysproc.rs b/kernel/rustkernel/src/sysproc.rs index 964d0d0..b74ecb6 100644 --- a/kernel/rustkernel/src/sysproc.rs +++ b/kernel/rustkernel/src/sysproc.rs @@ -1,5 +1,5 @@ use crate::{ - proc::{exit, fork, growproc, kill, killed, myproc, sleep, wait}, + proc::{exit, fork, growproc, kill, killed, myproc, sleep_lock, wait}, syscall::{argaddr, argint}, }; use core::ptr::addr_of_mut; @@ -53,7 +53,7 @@ pub unsafe extern "C" fn sys_sleep() -> u64 { crate::trap::tickslock.unlock(); return -1i64 as u64; } - sleep( + sleep_lock( addr_of_mut!(crate::trap::ticks).cast(), addr_of_mut!(crate::trap::tickslock).cast(), ) diff --git a/kernel/rustkernel/src/uart.rs b/kernel/rustkernel/src/uart.rs index a042180..020bd2b 100644 --- a/kernel/rustkernel/src/uart.rs +++ b/kernel/rustkernel/src/uart.rs @@ -3,7 +3,7 @@ use crate::{ console::consoleintr, - proc::{sleep, sleep_mutex, wakeup}, + proc::{sleep_lock, wakeup}, riscv::memlayout::UART0, sync::spinlock::Spinlock, sync::spinmutex::SpinMutex, @@ -171,7 +171,7 @@ pub(crate) unsafe fn uartputc(c: u8) { while uart_tx_w == uart_tx_r + UART_TX_BUF_SIZE { // Buffer is full. // Wait for uartstart() to open up space in the buffer. - sleep( + sleep_lock( addr_of_mut!(uart_tx_r).cast(), addr_of_mut!(uart_tx_lock).cast(), ); diff --git a/kernel/rustkernel/src/virtio_disk.rs b/kernel/rustkernel/src/virtio_disk.rs index 24be969..959714d 100644 --- a/kernel/rustkernel/src/virtio_disk.rs +++ b/kernel/rustkernel/src/virtio_disk.rs @@ -1,12 +1,12 @@ //! Virtio device driver. -//! +//! //! For both the MMIO interface, and virtio descriptors. //! Only tested with qemu. -//! +//! //! The virtio spec: https://docs.oasis-open.org/virtio/virtio/v1.1/virtio-v1.1.pdf //! qemu ... -drive file=fs.img,if=none,format=raw,id=x0 -device virtio-blk-device,drive=x0,bus=virtio-mmio-bus.0 -use crate::{sync::spinlock::Spinlock, buf::Buffer}; +use crate::{buf::Buffer, sync::spinlock::Spinlock}; use core::ffi::c_char; // Virtio MMIO control registers, mapped starting at 0x10001000 @@ -17,61 +17,61 @@ pub const VIRTIO_MMIO_MAGIC_VALUE: u64 = 0x000u64; /// Version - should be 2. pub const VIRTIO_MMIO_VERSION: u64 = 0x004u64; /// Device type. -/// +/// /// 1: Network /// 2: Disk -pub const VIRTIO_MMIO_DEVICE_ID: u64 = 0x008u64; +pub const VIRTIO_MMIO_DEVICE_ID: u64 = 0x008u64; /// 0x554d4551 -pub const VIRTIO_MMIO_VENDOR_ID: u64 = 0x00cu64; -pub const VIRTIO_MMIO_DEVICE_FEATURES: u64 = 0x010u64; -pub const VIRTIO_MMIO_DRIVER_FEATURES: u64 = 0x020u64; +pub const VIRTIO_MMIO_VENDOR_ID: u64 = 0x00cu64; +pub const VIRTIO_MMIO_DEVICE_FEATURES: u64 = 0x010u64; +pub const VIRTIO_MMIO_DRIVER_FEATURES: u64 = 0x020u64; /// Select queue, write-only. -pub const VIRTIO_MMIO_QUEUE_SEL: u64 = 0x030u64; +pub const VIRTIO_MMIO_QUEUE_SEL: u64 = 0x030u64; /// Max size of current queue, read-only. -pub const VIRTIO_MMIO_QUEUE_NUM_MAX: u64 = 0x034u64; +pub const VIRTIO_MMIO_QUEUE_NUM_MAX: u64 = 0x034u64; /// Size of current queue, write-only. -pub const VIRTIO_MMIO_QUEUE_NUM: u64 = 0x038u64; +pub const VIRTIO_MMIO_QUEUE_NUM: u64 = 0x038u64; /// Ready bit. -pub const VIRTIO_MMIO_QUEUE_READY: u64 = 0x044u64; +pub const VIRTIO_MMIO_QUEUE_READY: u64 = 0x044u64; /// Write-only. -pub const VIRTIO_MMIO_QUEUE_NOTIFY: u64 = 0x050u64; +pub const VIRTIO_MMIO_QUEUE_NOTIFY: u64 = 0x050u64; /// Read-only. -pub const VIRTIO_MMIO_INTERRUPT_STATUS: u64 = 0x060u64; +pub const VIRTIO_MMIO_INTERRUPT_STATUS: u64 = 0x060u64; /// Write-only. -pub const VIRTIO_MMIO_INTERRUPT_ACK: u64 = 0x064u64; +pub const VIRTIO_MMIO_INTERRUPT_ACK: u64 = 0x064u64; /// Read/write. -pub const VIRTIO_MMIO_STATUS: u64 = 0x070u64; +pub const VIRTIO_MMIO_STATUS: u64 = 0x070u64; /// Physical address for descriptor table, write-only. -pub const VIRTIO_MMIO_QUEUE_DESC_LOW: u64 = 0x080u64; -pub const VIRTIO_MMIO_QUEUE_DESC_HIGH: u64 = 0x084u64; +pub const VIRTIO_MMIO_QUEUE_DESC_LOW: u64 = 0x080u64; +pub const VIRTIO_MMIO_QUEUE_DESC_HIGH: u64 = 0x084u64; /// Physical address for available ring, write-only. -pub const VIRTIO_MMIO_DRIVER_DESC_LOW: u64 = 0x090u64; -pub const VIRTIO_MMIO_DRIVER_DESC_HIGH: u64 = 0x094u64; +pub const VIRTIO_MMIO_DRIVER_DESC_LOW: u64 = 0x090u64; +pub const VIRTIO_MMIO_DRIVER_DESC_HIGH: u64 = 0x094u64; /// Physical address for used ring, write-only. -pub const VIRTIO_MMIO_DEVICE_DESC_LOW: u64 = 0x0a0u64; -pub const VIRTIO_MMIO_DEVICE_DESC_HIGH: u64 = 0x0a4u64; +pub const VIRTIO_MMIO_DEVICE_DESC_LOW: u64 = 0x0a0u64; +pub const VIRTIO_MMIO_DEVICE_DESC_HIGH: u64 = 0x0a4u64; // Status register bits, from qemu virtio_config.h. -pub const VIRTIO_CONFIG_S_ACKNOWLEDGE: u8 = 0x01u8; -pub const VIRTIO_CONFIG_S_DRIVER: u8 = 0x02u8; -pub const VIRTIO_CONFIG_S_DRIVER_OK: u8 = 0x04u8; -pub const VIRTIO_CONFIG_S_FEATURES_OK: u8 = 0x08u8; +pub const VIRTIO_CONFIG_S_ACKNOWLEDGE: u8 = 0x01u8; +pub const VIRTIO_CONFIG_S_DRIVER: u8 = 0x02u8; +pub const VIRTIO_CONFIG_S_DRIVER_OK: u8 = 0x04u8; +pub const VIRTIO_CONFIG_S_FEATURES_OK: u8 = 0x08u8; // Device feature bits /// Disk is read-only. -pub const VIRTIO_BLK_F_RO: u8 = 5u8; +pub const VIRTIO_BLK_F_RO: u8 = 5u8; /// Supports SCSI command passthrough. -pub const VIRTIO_BLK_F_SCSI: u8 = 7u8; +pub const VIRTIO_BLK_F_SCSI: u8 = 7u8; /// Writeback mode available in config. -pub const VIRTIO_BLK_F_CONFIG_WCE: u8 = 11u8; +pub const VIRTIO_BLK_F_CONFIG_WCE: u8 = 11u8; /// Support more than one vq. -pub const VIRTIO_BLK_F_MQ: u8 = 12u8; -pub const VIRTIO_F_ANY_LAYOUT: u8 = 27u8; -pub const VIRTIO_RING_F_INDIRECT_DESC: u8 = 28u8; -pub const VIRTIO_RING_F_EVENT_IDX: u8 = 29u8; +pub const VIRTIO_BLK_F_MQ: u8 = 12u8; +pub const VIRTIO_F_ANY_LAYOUT: u8 = 27u8; +pub const VIRTIO_RING_F_INDIRECT_DESC: u8 = 28u8; +pub const VIRTIO_RING_F_EVENT_IDX: u8 = 29u8; /// This many virtio descriptors. -/// +/// /// Must be a power of two. pub const NUM_DESCRIPTORS: usize = 8usize; @@ -123,12 +123,12 @@ pub struct VirtqUsed { // Described in section 5.2 of the spec. /// Read the disk. -pub const VIRTIO_BLK_T_IN: u32 = 0u32; +pub const VIRTIO_BLK_T_IN: u32 = 0u32; /// Write the disk. pub const VIRTIO_BLK_T_OUT: u32 = 1u32; /// The format of the first descriptor in a disk request. -/// +/// /// To be followed by two more descriptors containing /// the block, and a one-byte status. #[repr(C)] @@ -151,7 +151,7 @@ pub struct Disk { /// A set (not a ring) of DMA descriptors, with which the /// driver tells the device where to read and write individual /// disk operations. There are NUM descriptors. - /// + /// /// Most commands consist of a "chain" (linked list) /// of a couple of these descriptors. pub descriptors: *mut VirtqDescriptor, @@ -173,11 +173,10 @@ pub struct Disk { /// Track info about in-flight operations, /// for use when completion interrupt arrives. - /// + /// /// Indexed by first descriptor index of chain. pub info: [DiskInfo; NUM_DESCRIPTORS], - /// Disk command headers. /// One-for-one with descriptors, for convenience. pub ops: [VirtioBlockRequest; NUM_DESCRIPTORS],