Lock wait queue together when receive_into_user

This commit is contained in:
Wildan M
2026-04-26 00:58:47 +07:00
committed by Jeremy Soller
parent 746c158465
commit b8615790ea
2 changed files with 61 additions and 29 deletions
+21 -29
View File
@@ -2,7 +2,7 @@ use alloc::collections::VecDeque;
use syscall::{EAGAIN, EINTR};
use crate::{
sync::{CleanLockToken, LockToken, Mutex, WaitCondition, L1, L2},
sync::{CleanLockToken, LockToken, Mutex, MutexGuard, WaitCondition, L1, L2},
syscall::{
error::{Error, Result, EINVAL},
usercopy::UserSliceWo,
@@ -36,38 +36,34 @@ impl<T> WaitQueue<T> {
reason: &'static str,
token: &mut CleanLockToken,
) -> Result<usize> {
let mut out_guard = self.outgoing.lock(token.token());
loop {
let mut tmp_queue = VecDeque::new();
{
let mut out = self.outgoing.lock(token.token());
if !out.is_empty() {
let (s1, s2) = out.as_slices();
let s1_bytes = unsafe {
core::slice::from_raw_parts(s1.as_ptr().cast::<u8>(), size_of_val(s1))
};
let s2_bytes = unsafe {
core::slice::from_raw_parts(s2.as_ptr().cast::<u8>(), size_of_val(s2))
};
let (mut outgoing, mut token) = out_guard.into_split();
if !outgoing.is_empty() {
let (s1, s2) = outgoing.as_slices();
let s1_bytes = unsafe {
core::slice::from_raw_parts(s1.as_ptr().cast::<u8>(), size_of_val(s1))
};
let s2_bytes = unsafe {
core::slice::from_raw_parts(s2.as_ptr().cast::<u8>(), size_of_val(s2))
};
let mut bytes_copied = buf.copy_common_bytes_from_slice(s1_bytes)?;
let mut bytes_copied = buf.copy_common_bytes_from_slice(s1_bytes)?;
if let Some(buf_for_s2) = buf.advance(s1_bytes.len()) {
bytes_copied += buf_for_s2.copy_common_bytes_from_slice(s2_bytes)?;
}
let _ = out.drain(..bytes_copied / size_of::<T>());
return Ok(bytes_copied);
if let Some(buf_for_s2) = buf.advance(s1_bytes.len()) {
bytes_copied += buf_for_s2.copy_common_bytes_from_slice(s2_bytes)?;
}
// Act as tmp_queue.drain(..), but much faster
core::mem::swap(&mut *out, &mut tmp_queue);
let _ = outgoing.drain(..bytes_copied / size_of::<T>());
return Ok(bytes_copied);
}
let incoming_guard = self.incoming.lock(token.token());
let incoming_guard = unsafe { self.incoming.relock(token.token()) };
let (mut incoming, mut split_token) = incoming_guard.into_split();
if incoming.is_empty() {
if block {
drop(outgoing);
// SAFETY: Uses wait_inner because this inner is L2. It's guaranteed there's no other
// lock held at this point because clean token is provided from caller.
if !self
@@ -76,6 +72,7 @@ impl<T> WaitQueue<T> {
{
return Err(Error::new(EINTR));
}
out_guard = unsafe { self.outgoing.relock(token) };
continue;
} else if buf.is_empty() {
return Ok(0);
@@ -87,15 +84,10 @@ impl<T> WaitQueue<T> {
}
}
// Act as incoming.drain(..), but much faster
core::mem::swap(&mut *incoming, &mut tmp_queue);
core::mem::swap(&mut *incoming, &mut outgoing);
drop(incoming);
{
let mut out = self.outgoing.lock(token.token());
// outgoing = incoming
*out = tmp_queue;
}
out_guard = MutexGuard::from_split(outgoing, token);
}
}