From 7ebb5f2a3d898929e1150cb6ab56f556ebe369eb Mon Sep 17 00:00:00 2001 From: Wildan M Date: Wed, 11 Mar 2026 08:00:48 +0700 Subject: [PATCH] Solve borrow checking by downgrading locks --- src/event.rs | 53 ++++++++++++++++++++++++-------------- src/scheme/event.rs | 2 +- src/scheme/user.rs | 9 +++++-- src/sync/wait_condition.rs | 22 +++++++++------- src/sync/wait_queue.rs | 4 +-- 5 files changed, 56 insertions(+), 34 deletions(-) diff --git a/src/event.rs b/src/event.rs index 44d61fa27b..28763e6d77 100644 --- a/src/event.rs +++ b/src/event.rs @@ -9,7 +9,7 @@ use crate::{ context, scheme::{self, SchemeExt, SchemeId}, sync::{ - CleanLockToken, LockToken, RwLock, RwLockReadGuard, RwLockWriteGuard, WaitQueue, L0, L1, + CleanLockToken, LockToken, RwLock, RwLockReadGuard, RwLockWriteGuard, WaitQueue, L0, L1, L2, }, syscall::{ data::Event, @@ -87,8 +87,8 @@ impl EventQueue { Ok(events.len()) } - pub fn into_drop(self, token: &mut CleanLockToken) { - self.queue.condition.into_drop(token); + pub fn into_drop(self, token: LockToken<'_, L1>) { + self.queue.condition.into_drop_locked(token); } } @@ -103,16 +103,16 @@ pub fn next_queue_id() -> EventQueueId { } // Current event queues -static QUEUES: RwLock = +static QUEUES: RwLock = RwLock::new(EventQueueList::with_hasher(DefaultHashBuilder::new())); /// Get the event queues list, const -pub fn queues(token: LockToken<'_, L0>) -> RwLockReadGuard<'_, L1, EventQueueList> { +pub fn queues(token: LockToken<'_, L0>) -> RwLockReadGuard<'_, L2, EventQueueList> { QUEUES.read(token) } /// Get the event queues list, mutable -pub fn queues_mut(token: LockToken<'_, L0>) -> RwLockWriteGuard<'_, L1, EventQueueList> { +pub fn queues_mut(token: LockToken<'_, L0>) -> RwLockWriteGuard<'_, L2, EventQueueList> { QUEUES.write(token) } @@ -131,20 +131,20 @@ pub struct QueueKey { type Registry = HashMap>; -static REGISTRY: Once> = Once::new(); +static REGISTRY: Once> = Once::new(); /// Initialize registry, called if needed -fn init_registry() -> RwLock { +fn init_registry() -> RwLock { RwLock::new(Registry::new()) } /// Get the global schemes list, const -fn registry(token: &'_ mut CleanLockToken) -> RwLockReadGuard<'_, L1, Registry> { +fn registry<'a>(token: &'a mut LockToken<'a, L1>) -> RwLockReadGuard<'a, L2, Registry> { REGISTRY.call_once(init_registry).read(token.token()) } /// Get the global schemes list, mutable -pub fn registry_mut(token: &'_ mut CleanLockToken) -> RwLockWriteGuard<'_, L1, Registry> { +pub fn registry_mut<'a>(token: &'a mut LockToken<'a, L1>) -> RwLockWriteGuard<'a, L2, Registry> { REGISTRY.call_once(init_registry).write(token.token()) } @@ -154,7 +154,8 @@ pub fn register( flags: EventFlags, token: &mut CleanLockToken, ) { - let mut registry = registry_mut(token); + let mut token = token.downgrade(); + let mut registry = registry_mut(&mut token); let entry = registry.entry(reg_key).or_default(); @@ -169,7 +170,8 @@ pub fn sync(reg_key: RegKey, token: &mut CleanLockToken) -> Result { let mut flags = EventFlags::empty(); { - let registry = registry(token); + let mut token = token.downgrade(); + let registry = registry(&mut token); if let Some(queue_list) = registry.get(®_key) { for (_queue_key, &queue_flags) in queue_list.iter() { @@ -184,7 +186,8 @@ pub fn sync(reg_key: RegKey, token: &mut CleanLockToken) -> Result { } pub fn unregister_file(scheme: SchemeId, number: usize, token: &mut CleanLockToken) { - let mut registry = registry_mut(token); + let mut token = token.downgrade(); + let mut registry = registry_mut(&mut token); registry.remove(&RegKey { scheme, number }); } @@ -203,13 +206,14 @@ fn trigger_inner( flags: EventFlags, todo: &mut SmallVec<[EventQueueId; MAX_EVENT]>, offset: &mut usize, - token: &mut CleanLockToken, + mut token: LockToken<'_, L1>, ) -> bool { let mut matching_keys: SmallVec<[(QueueKey, EventFlags); MAX_EVENT]> = SmallVec::new(); let mut full = false; { - let registry = registry(token); + let mut token = token.token(); + let registry = registry(&mut token); if let Some(queue_list) = registry.get(&RegKey { scheme, number }) { for (queue_key, &queue_flags) in queue_list.iter().skip(*offset) { let common_flags = flags & queue_flags; @@ -226,7 +230,7 @@ fn trigger_inner( } while let Some((queue_key, common_flags)) = matching_keys.pop() { - let Some(queue) = queues(token.token()).get(&queue_key.queue).cloned() else { + let Some(queue) = QUEUES.read(token.token()).get(&queue_key.queue).cloned() else { continue; }; @@ -237,9 +241,9 @@ fn trigger_inner( }; todo.push(queue_key.queue); - queue.queue.send(event, token); + queue.queue.send_locked(event, token.token()); if let Some(queue) = Arc::into_inner(queue) { - queue.into_drop(token); + queue.into_drop(token.token()); } } @@ -247,12 +251,21 @@ fn trigger_inner( } pub fn trigger(scheme: SchemeId, number: usize, flags: EventFlags, token: &mut CleanLockToken) { + trigger_locked(scheme, number, flags, token.token().downgrade()); +} + +pub fn trigger_locked( + scheme: SchemeId, + number: usize, + flags: EventFlags, + mut token: LockToken<'_, L1>, +) { let mut todo = SmallVec::<[EventQueueId; MAX_EVENT]>::new(); let mut done = SmallVec::<[EventQueueId; MAX_EVENT]>::new(); // First trigger with the original file let mut offset = 0; - while trigger_inner(scheme, number, flags, &mut todo, &mut offset, token) {} + while trigger_inner(scheme, number, flags, &mut todo, &mut offset, token.token()) {} // Handle triggers on queues while let Some(queue_id) = todo.pop() { @@ -265,7 +278,7 @@ pub fn trigger(scheme: SchemeId, number: usize, flags: EventFlags, token: &mut C EventFlags::EVENT_READ, &mut todo, &mut offset, - token, + token.token(), ) {} } } diff --git a/src/scheme/event.rs b/src/scheme/event.rs index 4f4bf763c2..706d8f8c02 100644 --- a/src/scheme/event.rs +++ b/src/scheme/event.rs @@ -47,7 +47,7 @@ impl KernelScheme for EventScheme { .remove(&id) .ok_or(Error::new(EBADF))?; if let Some(queue) = Arc::into_inner(queue) { - queue.into_drop(token); + queue.into_drop(token.downgrade()); } Ok(()) } diff --git a/src/scheme/user.rs b/src/scheme/user.rs index 0344f6005f..b73222d23a 100644 --- a/src/scheme/user.rs +++ b/src/scheme/user.rs @@ -329,9 +329,14 @@ impl UserInner { tag: sqe.tag, ..Default::default() }, - &mut token.token(), + token.token(), + ); + event::trigger_locked( + self.root_id, + self.scheme_id.get(), + EVENT_READ, + token.token(), ); - event::trigger(self.root_id, self.scheme_id.get(), EVENT_READ, token); // 1. If cancellation was requested and arrived // before the scheme processed the request, an diff --git a/src/sync/wait_condition.rs b/src/sync/wait_condition.rs index d37c040cfc..3b5abdf305 100644 --- a/src/sync/wait_condition.rs +++ b/src/sync/wait_condition.rs @@ -7,12 +7,12 @@ use alloc::{ use crate::{ context::{self, ContextLock, PreemptGuard}, - sync::{CleanLockToken, LockToken, Mutex, L1, L2}, + sync::{CleanLockToken, LockToken, Mutex, L1, L3}, }; #[derive(Debug)] pub struct WaitCondition { - contexts: Mutex>>, + contexts: Mutex>>, } impl WaitCondition { @@ -24,11 +24,11 @@ impl WaitCondition { // Notify all waiters pub fn notify(&self, token: &mut CleanLockToken) -> usize { - self.notify_locked(&mut token.token().downgrade()) + self.notify_locked(token.token().downgrade()) } - pub fn notify_locked<'a>(&self, token: &'a mut LockToken<'a, L1>) -> usize { - let mut contexts = self.contexts.lock(token.token()); + pub fn notify_locked(&self, token: LockToken<'_, L1>) -> usize { + let mut contexts = self.contexts.lock(token); let (contexts, mut token) = contexts.token_split(); let len = contexts.len(); while let Some(context_weak) = contexts.pop() { @@ -40,8 +40,8 @@ impl WaitCondition { } // Notify as though a signal woke the waiters - pub unsafe fn notify_signal(&self, token: &mut CleanLockToken) -> usize { - let mut contexts = self.contexts.lock(token.token()); + pub unsafe fn notify_signal(&self, token: LockToken<'_, L1>) -> usize { + let mut contexts = self.contexts.lock(token); let (contexts, mut token) = contexts.token_split(); let len = contexts.len(); for context_weak in contexts.iter() { @@ -99,10 +99,14 @@ impl WaitCondition { } pub fn into_drop(self, token: &mut CleanLockToken) { + self.into_drop_locked(token.token().downgrade()); + } + + pub fn into_drop_locked(self, token: LockToken<'_, L1>) { ManuallyDrop::new(self).inner_drop(token); } - fn inner_drop(&mut self, token: &mut CleanLockToken) { + fn inner_drop(&mut self, token: LockToken<'_, L1>) { unsafe { self.notify_signal(token); } @@ -113,7 +117,7 @@ impl Drop for WaitCondition { fn drop(&mut self) { //TODO: drop violates lock tokens let mut token = unsafe { CleanLockToken::new() }; - self.inner_drop(&mut token); + self.inner_drop(token.downgrade()); #[cfg(feature = "drop_panic")] { panic!("WaitCondition dropped"); diff --git a/src/sync/wait_queue.rs b/src/sync/wait_queue.rs index 73d8f08620..08fd1eae60 100644 --- a/src/sync/wait_queue.rs +++ b/src/sync/wait_queue.rs @@ -73,10 +73,10 @@ impl WaitQueue { } pub fn send(&self, value: T, token: &mut CleanLockToken) -> usize { - self.send_locked(value, &mut token.token().downgrade()) + self.send_locked(value, token.token().downgrade()) } - pub fn send_locked<'a>(&self, value: T, token: &'a mut LockToken<'a, L1>) -> usize { + pub fn send_locked(&self, value: T, token: LockToken<'_, L1>) -> usize { let len = { let mut inner = self.inner.lock(); inner.push_back(value);