Solve borrow checking by downgrading locks

This commit is contained in:
Wildan M
2026-03-11 08:00:48 +07:00
parent 44f2214971
commit 7ebb5f2a3d
5 changed files with 56 additions and 34 deletions
+33 -20
View File
@@ -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<L1, EventQueueList> =
static QUEUES: RwLock<L2, EventQueueList> =
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<RegKey, HashMap<QueueKey, EventFlags>>;
static REGISTRY: Once<RwLock<L1, Registry>> = Once::new();
static REGISTRY: Once<RwLock<L2, Registry>> = Once::new();
/// Initialize registry, called if needed
fn init_registry() -> RwLock<L1, Registry> {
fn init_registry() -> RwLock<L2, Registry> {
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<EventFlags> {
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(&reg_key) {
for (_queue_key, &queue_flags) in queue_list.iter() {
@@ -184,7 +186,8 @@ pub fn sync(reg_key: RegKey, token: &mut CleanLockToken) -> Result<EventFlags> {
}
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(),
) {}
}
}
+1 -1
View File
@@ -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(())
}
+7 -2
View File
@@ -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
+13 -9
View File
@@ -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<L2, Vec<Weak<ContextLock>>>,
contexts: Mutex<L3, Vec<Weak<ContextLock>>>,
}
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");
+2 -2
View File
@@ -73,10 +73,10 @@ impl<T> WaitQueue<T> {
}
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);