diff --git a/src/event.rs b/src/event.rs index 2b8fdb2ad1..4cf0887882 100644 --- a/src/event.rs +++ b/src/event.rs @@ -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 { 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, + 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); + } + } +} diff --git a/src/scheme/event.rs b/src/scheme/event.rs index 88ab9c6321..fd9f4e5188 100644 --- a/src/scheme/event.rs +++ b/src/scheme/event.rs @@ -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 { buf.copy_common_bytes_from_slice(b"event:") } + + fn fevent( + &self, + id: usize, + flags: EventFlags, + token: &mut CleanLockToken, + ) -> Result { + 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) + } }