Recursively trigger event queues

This commit is contained in:
Jeremy Soller
2025-11-06 22:14:13 -07:00
parent c3437ab6eb
commit 8ae1ced55d
2 changed files with 69 additions and 9 deletions
+41 -8
View File
@@ -1,11 +1,11 @@
use alloc::sync::Arc;
use alloc::{sync::Arc, vec::Vec};
use core::sync::atomic::{AtomicUsize, Ordering};
use hashbrown::HashMap;
use hashbrown::{HashMap, HashSet};
use spin::Once;
use crate::{
context,
scheme::{self, SchemeId},
scheme::{self, GlobalSchemes, SchemeId},
sync::{
CleanLockToken, LockToken, RwLock, RwLockReadGuard, RwLockWriteGuard, WaitQueue, L0, L1,
},
@@ -32,6 +32,10 @@ impl EventQueue {
}
}
pub fn is_currently_empty(&self) -> bool {
self.queue.is_currently_empty()
}
pub fn read(&self, buf: UserSliceWo, block: bool, token: &mut CleanLockToken) -> Result<usize> {
self.queue
.receive_into_user(buf, block, "EventQueue::read", token)
@@ -179,10 +183,13 @@ pub fn unregister_file(scheme: SchemeId, number: usize) {
//
// }
pub fn trigger(scheme: SchemeId, number: usize, flags: EventFlags) {
//TODO: propogate this lock token
let mut token = unsafe { CleanLockToken::new() };
fn trigger_inner(
scheme: SchemeId,
number: usize,
flags: EventFlags,
todo: &mut Vec<EventQueueId>,
token: &mut CleanLockToken,
) {
let registry = registry();
if let Some(queue_list) = registry.get(&RegKey { scheme, number }) {
for (queue_key, &queue_flags) in queue_list.iter() {
@@ -199,10 +206,36 @@ pub fn trigger(scheme: SchemeId, number: usize, flags: EventFlags) {
flags: common_flags,
data: queue_key.data,
},
&mut token,
token,
);
todo.push(queue_key.queue);
}
}
}
}
}
pub fn trigger(scheme: SchemeId, number: usize, flags: EventFlags) {
//TODO: propogate this lock token
let mut token = unsafe { CleanLockToken::new() };
// First trigger with the original file
let mut todo = Vec::new();
trigger_inner(scheme, number, flags, &mut todo, &mut token);
// Handle triggers on queues
//TODO: can this be done with limited allocations?
let mut done = HashSet::new();
while let Some(queue_id) = todo.pop() {
if !done.contains(&queue_id) {
trigger_inner(
GlobalSchemes::Event.scheme_id(),
queue_id.into(),
EventFlags::EVENT_READ,
&mut todo,
&mut token,
);
done.insert(queue_id);
}
}
}
+28 -1
View File
@@ -1,6 +1,6 @@
use alloc::sync::Arc;
use core::mem;
use syscall::O_NONBLOCK;
use syscall::{EventFlags, O_NONBLOCK};
use crate::{
context::file::InternalFlags,
@@ -38,6 +38,7 @@ impl KernelScheme for EventScheme {
.ok_or(Error::new(EBADF))
.and(Ok(()))
}
fn kread(
&self,
id: usize,
@@ -88,4 +89,30 @@ impl KernelScheme for EventScheme {
fn kfpath(&self, _id: usize, buf: UserSliceWo, _token: &mut CleanLockToken) -> Result<usize> {
buf.copy_common_bytes_from_slice(b"event:")
}
fn fevent(
&self,
id: usize,
flags: EventFlags,
token: &mut CleanLockToken,
) -> Result<EventFlags> {
let id = EventQueueId::from(id);
let queue = {
let handles = queues(token.token());
let handle = handles.get(&id).ok_or(Error::new(EBADF))?;
handle.clone()
};
let mut ready = EventFlags::empty();
if flags.contains(EventFlags::EVENT_WRITE) {
// It is always possible to write events
ready |= EventFlags::EVENT_WRITE;
}
if flags.contains(EventFlags::EVENT_READ) && !queue.is_currently_empty() {
// It is possible to read if queue is not empty
ready |= EventFlags::EVENT_READ;
}
Ok(ready)
}
}