From 84754dfc5df5eded038e7dc67ec14aad54501d51 Mon Sep 17 00:00:00 2001 From: Wildan M Date: Wed, 11 Mar 2026 09:42:06 +0700 Subject: [PATCH] Solve borrow checking by downgrading waitqueue lock --- src/context/mod.rs | 26 +++++++++++++++++++++++++- src/sync/wait_condition.rs | 16 +++++++++++++--- src/sync/wait_queue.rs | 6 +++--- 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/src/context/mod.rs b/src/context/mod.rs index 07126c10f1..62a0a575b5 100644 --- a/src/context/mod.rs +++ b/src/context/mod.rs @@ -12,7 +12,7 @@ use crate::{ percpu::PercpuBlock, sync::{ ArcRwLockWriteGuard, CleanLockToken, LockToken, RwLock, RwLockReadGuard, RwLockWriteGuard, - L0, L1, L4, + L0, L1, L2, L4, }, syscall::error::Result, }; @@ -234,3 +234,27 @@ impl Drop for PreemptGuardL1<'_> { self.context.write(self.token.token()).preempt_locks -= 1; } } + +/// Variant of PreemptGuard behind a one-level token +pub struct PreemptGuardL2<'a> { + context: &'a ContextLock, + token: &'a mut LockToken<'a, L2>, +} + +impl<'a> PreemptGuardL2<'a> { + pub fn new(context: &'a ContextLock, token: &'a mut LockToken<'a, L2>) -> PreemptGuardL2<'a> { + context.write(token.token()).preempt_locks += 1; + PreemptGuardL2 { context, token } + } + + /// Get a mutable reference to the underlying `LockToken`. + pub fn token(&mut self) -> &mut LockToken<'a, L2> { + self.token + } +} + +impl Drop for PreemptGuardL2<'_> { + fn drop(&mut self) { + self.context.write(self.token.token()).preempt_locks -= 1; + } +} diff --git a/src/sync/wait_condition.rs b/src/sync/wait_condition.rs index 956cdcbcfd..bda7a8cabc 100644 --- a/src/sync/wait_condition.rs +++ b/src/sync/wait_condition.rs @@ -6,8 +6,8 @@ use alloc::{ }; use crate::{ - context::{self, ContextLock, PreemptGuard, PreemptGuardL1}, - sync::{CleanLockToken, LockToken, Mutex, L1, L3}, + context::{self, ContextLock, PreemptGuard, PreemptGuardL1, PreemptGuardL2}, + sync::{CleanLockToken, LockToken, Mutex, L1, L2, L3}, }; #[derive(Debug)] @@ -59,6 +59,16 @@ impl WaitCondition { guard: T, reason: &'static str, token: &'a mut LockToken<'a, L1>, + ) -> bool { + let mut token = token.downgrade(); + self.wait_inner(guard, reason, &mut token) + } + + pub fn wait_inner<'a, T>( + &self, + guard: T, + reason: &'static str, + token: &'a mut LockToken<'a, L2>, ) -> bool { let current_context_ref = context::current(); { @@ -67,7 +77,7 @@ impl WaitCondition { // We cannot add ourselves to the wait list first as that would lead // to deadlock if we were woken up immediately. let mut token = token.token(); - let mut preempt = PreemptGuardL1::new(¤t_context_ref, &mut token); + let mut preempt = PreemptGuardL2::new(¤t_context_ref, &mut token); let token = preempt.token(); { let mut context = current_context_ref.write(token.token()); diff --git a/src/sync/wait_queue.rs b/src/sync/wait_queue.rs index 52bd81734d..3c0411a129 100644 --- a/src/sync/wait_queue.rs +++ b/src/sync/wait_queue.rs @@ -2,7 +2,7 @@ use alloc::collections::VecDeque; use syscall::{EAGAIN, EINTR}; use crate::{ - sync::{CleanLockToken, LockToken, Mutex, WaitCondition, L1}, + sync::{CleanLockToken, LockToken, Mutex, WaitCondition, L1, L2}, syscall::{ error::{Error, Result, EINVAL}, usercopy::UserSliceWo, @@ -11,7 +11,7 @@ use crate::{ #[derive(Debug)] pub struct WaitQueue { - inner: Mutex>, + inner: Mutex>, pub condition: WaitCondition, } @@ -38,7 +38,7 @@ impl WaitQueue { if inner.is_empty() { if block { - if !self.condition.wait(inner, reason, &mut token) { + if !self.condition.wait_inner(inner, reason, &mut token) { return Err(Error::new(EINTR)); } continue;