Refactor sleeplock to remove raw pointers
This commit is contained in:
parent
36d7724fb8
commit
9f23b68c00
@ -106,8 +106,6 @@ bread(uint dev, uint blockno)
|
|||||||
void
|
void
|
||||||
bwrite(struct buf *b)
|
bwrite(struct buf *b)
|
||||||
{
|
{
|
||||||
if(!holdingsleep(&b->lock))
|
|
||||||
panic("bwrite");
|
|
||||||
virtio_disk_rw(b, 1);
|
virtio_disk_rw(b, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,9 +114,6 @@ bwrite(struct buf *b)
|
|||||||
void
|
void
|
||||||
brelse(struct buf *b)
|
brelse(struct buf *b)
|
||||||
{
|
{
|
||||||
if(!holdingsleep(&b->lock))
|
|
||||||
panic("brelse");
|
|
||||||
|
|
||||||
releasesleep(&b->lock);
|
releasesleep(&b->lock);
|
||||||
|
|
||||||
acquire(&bcache.lock);
|
acquire(&bcache.lock);
|
||||||
|
@ -125,8 +125,7 @@ void pop_off(void);
|
|||||||
|
|
||||||
// sleeplock.c
|
// sleeplock.c
|
||||||
void acquiresleep(struct sleeplock*);
|
void acquiresleep(struct sleeplock*);
|
||||||
void releasesleep(struct sleeplock*);
|
void releasesleep(struct sleeplock *);
|
||||||
int holdingsleep(struct sleeplock*);
|
|
||||||
void initsleeplock(struct sleeplock*, char*);
|
void initsleeplock(struct sleeplock*, char*);
|
||||||
|
|
||||||
// string.c
|
// string.c
|
||||||
|
@ -317,10 +317,11 @@ ilock(struct inode *ip)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Unlock the given inode.
|
// Unlock the given inode.
|
||||||
|
// Caller should hold ip->lock
|
||||||
void
|
void
|
||||||
iunlock(struct inode *ip)
|
iunlock(struct inode *ip)
|
||||||
{
|
{
|
||||||
if(ip == 0 || !holdingsleep(&ip->lock) || ip->ref < 1)
|
if (ip == 0 || ip->ref < 1)
|
||||||
panic("iunlock");
|
panic("iunlock");
|
||||||
|
|
||||||
releasesleep(&ip->lock);
|
releasesleep(&ip->lock);
|
||||||
|
@ -16,11 +16,10 @@ void ramdiskinit(void);
|
|||||||
|
|
||||||
// If B_DIRTY is set, write buf to disk, clear B_DIRTY, set B_VALID.
|
// If B_DIRTY is set, write buf to disk, clear B_DIRTY, set B_VALID.
|
||||||
// Else if B_VALID is not set, read buf from disk, set B_VALID.
|
// Else if B_VALID is not set, read buf from disk, set B_VALID.
|
||||||
|
// Caller should hold b->lock
|
||||||
void
|
void
|
||||||
ramdiskrw(struct buf *b)
|
ramdiskrw(struct buf *b)
|
||||||
{
|
{
|
||||||
if(!holdingsleep(&b->lock))
|
|
||||||
panic("ramdiskrw: buf not locked");
|
|
||||||
if((b->flags & (B_VALID|B_DIRTY)) == B_VALID)
|
if((b->flags & (B_VALID|B_DIRTY)) == B_VALID)
|
||||||
panic("ramdiskrw: nothing to do");
|
panic("ramdiskrw: nothing to do");
|
||||||
|
|
||||||
|
@ -391,6 +391,21 @@ pub unsafe fn sleep_mutex<T>(chan: *mut c_void, mutex: &mut SpinMutexGuard<T>) {
|
|||||||
core::mem::forget(guard);
|
core::mem::forget(guard);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sleep until `wakeup(chan)` is called somewhere else.
|
||||||
|
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();
|
||||||
|
|
||||||
|
// Tidy up.
|
||||||
|
(*p).chan = null_mut();
|
||||||
|
}
|
||||||
|
|
||||||
/// Kill the process with the given pid.
|
/// Kill the process with the given pid.
|
||||||
/// The victim won't exit until it tries to return
|
/// The victim won't exit until it tries to return
|
||||||
/// to user space (see usertrap() in trap.c).
|
/// to user space (see usertrap() in trap.c).
|
||||||
|
@ -1,53 +1,27 @@
|
|||||||
use crate::{
|
use crate::proc::{wakeup, sleep};
|
||||||
proc::{myproc, sleep_lock, wakeup},
|
|
||||||
sync::spinlock::Spinlock,
|
|
||||||
};
|
|
||||||
use core::{
|
use core::{
|
||||||
ffi::c_char,
|
ffi::c_char,
|
||||||
ptr::{addr_of, null_mut},
|
ptr::addr_of,
|
||||||
|
sync::atomic::{AtomicBool, Ordering},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
#[derive(Default)]
|
||||||
pub struct Sleeplock {
|
pub struct Sleeplock {
|
||||||
pub locked: u32,
|
pub locked: AtomicBool,
|
||||||
pub inner: Spinlock,
|
|
||||||
pub name: *mut c_char,
|
|
||||||
pub pid: i32,
|
|
||||||
}
|
}
|
||||||
impl Sleeplock {
|
impl Sleeplock {
|
||||||
pub const unsafe fn uninitialized() -> Sleeplock {
|
pub const fn new() -> Sleeplock {
|
||||||
Sleeplock {
|
Sleeplock {
|
||||||
locked: 0,
|
locked: AtomicBool::new(false),
|
||||||
inner: Spinlock::new(),
|
|
||||||
name: null_mut(),
|
|
||||||
pid: 0,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Initializes a `Sleeplock`.
|
|
||||||
pub const fn new(name: *mut c_char) -> Sleeplock {
|
|
||||||
Sleeplock {
|
|
||||||
locked: 0,
|
|
||||||
inner: Spinlock::new(),
|
|
||||||
name,
|
|
||||||
pid: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// Check whether this proc is holding the lock.
|
|
||||||
pub fn held_by_current_proc(&self) -> bool {
|
|
||||||
self.locked > 0 && self.pid == unsafe { (*myproc()).pid }
|
|
||||||
}
|
|
||||||
#[allow(clippy::while_immutable_condition)]
|
#[allow(clippy::while_immutable_condition)]
|
||||||
pub unsafe fn lock_unguarded(&self) {
|
pub unsafe fn lock_unguarded(&self) {
|
||||||
let _guard = self.inner.lock();
|
while self.locked.swap(true, Ordering::Acquire) {
|
||||||
while self.locked > 0 {
|
// Put the process to sleep until it gets released.
|
||||||
sleep_lock(
|
sleep(addr_of!(*self).cast_mut().cast());
|
||||||
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;
|
|
||||||
this.pid = (*myproc()).pid;
|
|
||||||
}
|
}
|
||||||
pub fn lock(&self) -> SleeplockGuard<'_> {
|
pub fn lock(&self) -> SleeplockGuard<'_> {
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -56,10 +30,7 @@ impl Sleeplock {
|
|||||||
SleeplockGuard { lock: self }
|
SleeplockGuard { lock: self }
|
||||||
}
|
}
|
||||||
pub unsafe fn unlock(&self) {
|
pub unsafe fn unlock(&self) {
|
||||||
let _guard = self.inner.lock();
|
self.locked.store(false, Ordering::Release);
|
||||||
let this: &mut Self = &mut *addr_of!(*self).cast_mut();
|
|
||||||
this.locked = 0;
|
|
||||||
this.pid = 0;
|
|
||||||
wakeup(addr_of!(*self).cast_mut().cast());
|
wakeup(addr_of!(*self).cast_mut().cast());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -74,8 +45,8 @@ impl<'l> Drop for SleeplockGuard<'l> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn initsleeplock(lock: *mut Sleeplock, name: *mut c_char) {
|
pub unsafe extern "C" fn initsleeplock(lock: *mut Sleeplock, _name: *mut c_char) {
|
||||||
(*lock) = Sleeplock::new(name);
|
(*lock) = Sleeplock::new();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@ -87,12 +58,3 @@ pub unsafe extern "C" fn acquiresleep(lock: *mut Sleeplock) {
|
|||||||
pub unsafe extern "C" fn releasesleep(lock: *mut Sleeplock) {
|
pub unsafe extern "C" fn releasesleep(lock: *mut Sleeplock) {
|
||||||
(*lock).unlock();
|
(*lock).unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn holdingsleep(lock: *mut Sleeplock) -> i32 {
|
|
||||||
if (*lock).held_by_current_proc() {
|
|
||||||
1
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -4,11 +4,7 @@
|
|||||||
|
|
||||||
// Long-term locks for processes
|
// Long-term locks for processes
|
||||||
struct sleeplock {
|
struct sleeplock {
|
||||||
uint locked; // Is the lock held?
|
// Is the lock held?
|
||||||
struct spinlock lk; // spinlock protecting this sleep lock
|
uint8 locked;
|
||||||
|
|
||||||
// For debugging:
|
|
||||||
char *name; // Name of lock.
|
|
||||||
int pid; // Process holding lock
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user