Add ordered lock for WaitQueue mutex

This commit is contained in:
Wildan M
2026-02-25 09:41:34 +07:00
parent bf396c7f61
commit 735c68ec30
9 changed files with 109 additions and 47 deletions
+42 -12
View File
@@ -1,9 +1,9 @@
use alloc::collections::VecDeque;
use spin::Mutex;
use syscall::{EAGAIN, EINTR};
use crate::{
sync::{CleanLockToken, WaitCondition},
context::{self, PreemptGuard},
sync::{CleanLockToken, Mutex, WaitCondition, L1},
syscall::{
error::{Error, Result, EINVAL},
usercopy::UserSliceWo,
@@ -12,7 +12,7 @@ use crate::{
#[derive(Debug)]
pub struct WaitQueue<T> {
pub inner: Mutex<VecDeque<T>>,
pub inner: Mutex<L1, VecDeque<T>>,
pub condition: WaitCondition,
}
@@ -23,8 +23,8 @@ impl<T> WaitQueue<T> {
condition: WaitCondition::new(),
}
}
pub fn is_currently_empty(&self) -> bool {
self.inner.lock().is_empty()
pub fn is_currently_empty(&self, token: &mut CleanLockToken) -> bool {
self.inner.lock(token.token()).is_empty()
}
pub fn receive(
@@ -33,8 +33,12 @@ impl<T> WaitQueue<T> {
reason: &'static str,
token: &mut CleanLockToken,
) -> Result<T> {
let current_context_ref = context::current();
loop {
let mut inner = self.inner.lock();
let mut preempt = PreemptGuard::new(&current_context_ref, token);
let mut inner = self.inner.lock(preempt.token().token());
match inner.pop_front() {
Some(t) => {
@@ -42,9 +46,23 @@ impl<T> WaitQueue<T> {
}
_ => {
if block {
if !self.condition.wait(inner, reason, token) {
let (_, mut inner_token) = inner.token_split();
if !self.condition.wait_setup(
&current_context_ref,
reason,
inner_token.token(),
) {
return Err(Error::new(EINTR));
}
drop(inner);
drop(preempt);
context::switch(token);
self.condition
.wait_cleanup(&current_context_ref, token.token());
continue;
} else {
return Err(Error::new(EAGAIN));
@@ -53,22 +71,34 @@ impl<T> WaitQueue<T> {
}
}
}
pub fn receive_into_user(
pub fn receive_into_user(
&self,
buf: UserSliceWo,
block: bool,
reason: &'static str,
token: &mut CleanLockToken,
) -> Result<usize> {
let current_context_ref = context::current();
loop {
let mut inner = self.inner.lock();
let mut preempt = PreemptGuard::new(&current_context_ref, token);
let mut inner = self.inner.lock(preempt.token().token());
if inner.is_empty() {
if block {
if !self.condition.wait(inner, reason, token) {
let (_, mut inner_token) = inner.token_split();
if !self.condition.wait_setup(&current_context_ref, reason, inner_token.token()) {
return Err(Error::new(EINTR));
}
drop(inner);
drop(preempt);
context::switch(token);
self.condition.wait_cleanup(&current_context_ref, token.token());
continue;
} else if buf.is_empty() {
return Ok(0);
@@ -102,7 +132,7 @@ impl<T> WaitQueue<T> {
pub fn send(&self, value: T, token: &mut CleanLockToken) -> usize {
let len = {
let mut inner = self.inner.lock();
let mut inner = self.inner.lock(token.token());
inner.push_back(value);
inner.len()
};