diff --git a/context/context.rs b/context/context.rs index 504b5e4666378715a4e2aeed67b795f4c4ead548..a2ab64b9ff556fe887d8d32a2b1d768edc8d33be 100644 --- a/context/context.rs +++ b/context/context.rs @@ -1,9 +1,10 @@ use alloc::arc::Arc; use alloc::boxed::Box; -use collections::{BTreeMap, Vec}; +use collections::{BTreeMap, Vec, VecDeque}; use spin::Mutex; use arch; +use syscall::data::Event; use super::file::File; use super::memory::{Grant, Memory, SharedMemory}; @@ -39,6 +40,8 @@ pub struct Context { pub grants: Arc<Mutex<Vec<Grant>>>, /// The current working directory pub cwd: Arc<Mutex<Vec<u8>>>, + /// Kernel events + pub events: Arc<Mutex<VecDeque<Event>>>, /// The process environment pub env: Arc<Mutex<BTreeMap<Box<[u8]>, Arc<Mutex<Vec<u8>>>>>>, /// The open files in the scheme @@ -60,6 +63,7 @@ impl Context { stack: None, grants: Arc::new(Mutex::new(Vec::new())), cwd: Arc::new(Mutex::new(Vec::new())), + events: Arc::new(Mutex::new(VecDeque::new())), env: Arc::new(Mutex::new(BTreeMap::new())), files: Arc::new(Mutex::new(Vec::new())) } diff --git a/context/event.rs b/context/event.rs new file mode 100644 index 0000000000000000000000000000000000000000..06fea60e4fa6ee7a246c7f0d80aac2f080834ae1 --- /dev/null +++ b/context/event.rs @@ -0,0 +1,80 @@ +use alloc::arc::{Arc, Weak}; +use collections::{BTreeMap, VecDeque}; +use spin::{Mutex, Once, RwLock, RwLockReadGuard, RwLockWriteGuard}; + +use context; +use syscall::data::Event; + +type EventList = Weak<Mutex<VecDeque<Event>>>; + +type Registry = BTreeMap<(usize, usize), BTreeMap<(usize, usize), EventList>>; + +static REGISTRY: Once<RwLock<Registry>> = Once::new(); + +/// Initialize registry, called if needed +fn init_registry() -> RwLock<Registry> { + RwLock::new(Registry::new()) +} + +/// Get the global schemes list, const +fn registry() -> RwLockReadGuard<'static, Registry> { + REGISTRY.call_once(init_registry).read() +} + +/// Get the global schemes list, mutable +pub fn registry_mut() -> RwLockWriteGuard<'static, Registry> { + REGISTRY.call_once(init_registry).write() +} + +pub fn register(fd: usize, scheme_id: usize, id: usize) -> bool { + let (context_id, events) = { + let contexts = context::contexts(); + let context_lock = contexts.current().expect("event::register: No context"); + let context = context_lock.read(); + (context.id, Arc::downgrade(&context.events)) + }; + + let mut registry = registry_mut(); + let entry = registry.entry((scheme_id, id)).or_insert_with(|| { + BTreeMap::new() + }); + if entry.contains_key(&(context_id, fd)) { + false + } else { + entry.insert((context_id, fd), events); + true + } +} + +pub fn unregister(fd: usize, scheme_id: usize, id: usize) { + let mut registry = registry_mut(); + + let mut remove = false; + if let Some(entry) = registry.get_mut(&(scheme_id, id)) { + entry.remove(&(context::context_id(), fd)); + + if entry.is_empty() { + remove = true; + } + } + + if remove { + registry.remove(&(scheme_id, id)); + } +} + +pub fn trigger(scheme_id: usize, id: usize, flags: usize, data: usize) { + let registry = registry(); + if let Some(event_lists) = registry.get(&(scheme_id, id)) { + for entry in event_lists.iter() { + if let Some(event_list_lock) = entry.1.upgrade() { + let mut event_list = event_list_lock.lock(); + event_list.push_back(Event { + id: (entry.0).1, + flags: flags, + data: data + }); + } + } + } +} diff --git a/context/mod.rs b/context/mod.rs index 597c301c0cca936f45457136399793218de7e81c..9da1259c1746e687a227ff72857e66dc215f3cc7 100644 --- a/context/mod.rs +++ b/context/mod.rs @@ -16,6 +16,9 @@ mod list; /// Context switch function mod switch; +/// Event handling +pub mod event; + /// File struct - defines a scheme and a file number pub mod file; diff --git a/scheme/debug.rs b/scheme/debug.rs index 9b630b4bc7142da3565dab8edba0c77feb0d5f66..52b88e52c886f91e740f5ac70efd5c1944d6c187 100644 --- a/scheme/debug.rs +++ b/scheme/debug.rs @@ -1,11 +1,15 @@ use collections::VecDeque; use core::str; +use core::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; use spin::{Mutex, Once}; use context; use syscall::error::*; +use syscall::flag::EVENT_READ; use syscall::scheme::Scheme; +pub static DEBUG_SCHEME_ID: AtomicUsize = ATOMIC_USIZE_INIT; + /// Input static INPUT: Once<Mutex<VecDeque<u8>>> = Once::new(); @@ -17,7 +21,13 @@ fn init_input() -> Mutex<VecDeque<u8>> { /// Get the global schemes list, const #[no_mangle] pub extern fn debug_input(b: u8) { - INPUT.call_once(init_input).lock().push_back(b) + let len = { + let mut input = INPUT.call_once(init_input).lock(); + input.push_back(b); + input.len() + }; + + context::event::trigger(DEBUG_SCHEME_ID.load(Ordering::SeqCst), 0, EVENT_READ, len); } pub struct DebugScheme; @@ -62,6 +72,10 @@ impl Scheme for DebugScheme { Ok(buffer.len()) } + fn fevent(&self, _file: usize, flags: usize) -> Result<usize> { + Ok(0) + } + fn fsync(&self, _file: usize) -> Result<usize> { Ok(0) } diff --git a/scheme/event.rs b/scheme/event.rs index 7801d74885ae3d0d5ffe5bd479b06c90e743b5ea..2dead8d3696e4381bae10c391eee17fb93f49ea0 100644 --- a/scheme/event.rs +++ b/scheme/event.rs @@ -1,33 +1,94 @@ -use core::{mem, str}; +use alloc::arc::{Arc, Weak}; +use collections::{BTreeMap, VecDeque}; +use core::mem; +use core::sync::atomic::{AtomicUsize, Ordering}; +use spin::{Mutex, RwLock}; -use arch::interrupt::irq::{ACKS, COUNTS, acknowledge}; +use context; +use syscall::data::Event; use syscall::error::*; use syscall::scheme::Scheme; -pub struct EventScheme; +pub struct EventScheme { + next_id: AtomicUsize, + handles: RwLock<BTreeMap<usize, Weak<Mutex<VecDeque<Event>>>>> +} + +impl EventScheme { + pub fn new() -> EventScheme { + EventScheme { + next_id: AtomicUsize::new(0), + handles: RwLock::new(BTreeMap::new()) + } + } +} impl Scheme for EventScheme { fn open(&self, _path: &[u8], _flags: usize) -> Result<usize> { - Ok( - } + let handle = { + let contexts = context::contexts(); + let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; + let context = context_lock.read(); + context.events.clone() + }; - fn dup(&self, file: usize) -> Result<usize> { - Ok(file) + let id = self.next_id.fetch_add(1, Ordering::SeqCst); + self.handles.write().insert(id, Arc::downgrade(&handle)); + + Ok(id) } - fn read(&self, file: usize, buffer: &mut [u8]) -> Result<usize> { - Ok(0) + fn dup(&self, id: usize) -> Result<usize> { + let handle = { + let handles = self.handles.read(); + let handle_weak = handles.get(&id).ok_or(Error::new(EBADF))?; + handle_weak.upgrade().ok_or(Error::new(EBADF))? + }; + + let new_id = self.next_id.fetch_add(1, Ordering::SeqCst); + self.handles.write().insert(new_id, Arc::downgrade(&handle)); + Ok(new_id) } - fn write(&self, file: usize, buffer: &[u8]) -> Result<usize> { - Ok(0) + fn read(&self, id: usize, buf: &mut [u8]) -> Result<usize> { + let handle = { + let handles = self.handles.read(); + let handle_weak = handles.get(&id).ok_or(Error::new(EBADF))?; + handle_weak.upgrade().ok_or(Error::new(EBADF))? + }; + + let event_size = mem::size_of::<Event>(); + let len = buf.len()/event_size; + if len > 0 { + loop { + let mut i = 0; + { + let mut events = handle.lock(); + while ! events.is_empty() && i < len { + let event = events.pop_front().unwrap(); + unsafe { *(buf.as_mut_ptr() as *mut Event).offset(i as isize) = event; } + i += 1; + } + } + + if i > 0 { + return Ok(i * event_size); + } else { + unsafe { context::switch(); } //TODO: Block + } + } + } else { + Ok(0) + } } - fn fsync(&self, _file: usize) -> Result<usize> { - Ok(0) + fn fsync(&self, id: usize) -> Result<usize> { + let handles = self.handles.read(); + let handle_weak = handles.get(&id).ok_or(Error::new(EBADF))?; + handle_weak.upgrade().ok_or(Error::new(EBADF)).and(Ok(0)) } - fn close(&self, _file: usize) -> Result<usize> { - Ok(0) + fn close(&self, id: usize) -> Result<usize> { + self.handles.write().remove(&id).ok_or(Error::new(EBADF)).and(Ok(0)) } } diff --git a/scheme/mod.rs b/scheme/mod.rs index 4d0580ac07f4aae1566d7c8085d24c9c2e86a32e..7d3e25e8070619d8766f7ec6b7618c24f9ae0ba3 100644 --- a/scheme/mod.rs +++ b/scheme/mod.rs @@ -8,15 +8,15 @@ use alloc::arc::Arc; use alloc::boxed::Box; - use collections::BTreeMap; - +use core::sync::atomic::Ordering; use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard}; use syscall::error::*; use syscall::scheme::Scheme; -use self::debug::DebugScheme; +use self::debug::{DEBUG_SCHEME_ID, DebugScheme}; +use self::event::EventScheme; use self::env::EnvScheme; use self::initfs::InitFsScheme; use self::irq::IrqScheme; @@ -25,6 +25,9 @@ use self::root::RootScheme; /// Debug scheme pub mod debug; +/// Kernel events +pub mod event; + /// Environmental variables pub mod env; @@ -74,7 +77,7 @@ impl SchemeList { } /// Create a new scheme. - pub fn insert(&mut self, name: Box<[u8]>, scheme: Arc<Box<Scheme + Send + Sync>>) -> Result<&Arc<Box<Scheme + Send + Sync>>> { + pub fn insert(&mut self, name: Box<[u8]>, scheme: Arc<Box<Scheme + Send + Sync>>) -> Result<usize> { if self.names.contains_key(&name) { return Err(Error::new(EEXIST)); } @@ -97,7 +100,7 @@ impl SchemeList { assert!(self.map.insert(id, scheme).is_none()); assert!(self.names.insert(name, id).is_none()); - Ok(self.map.get(&id).expect("Failed to insert new scheme. ID is out of bounds.")) + Ok(id) } } @@ -108,7 +111,8 @@ static SCHEMES: Once<RwLock<SchemeList>> = Once::new(); fn init_schemes() -> RwLock<SchemeList> { let mut list: SchemeList = SchemeList::new(); list.insert(Box::new(*b""), Arc::new(Box::new(RootScheme::new()))).expect("failed to insert root scheme"); - list.insert(Box::new(*b"debug"), Arc::new(Box::new(DebugScheme))).expect("failed to insert debug scheme"); + DEBUG_SCHEME_ID.store(list.insert(Box::new(*b"debug"), Arc::new(Box::new(DebugScheme))).expect("failed to insert debug scheme"), Ordering::SeqCst); + list.insert(Box::new(*b"event"), Arc::new(Box::new(EventScheme::new()))).expect("failed to insert event scheme"); list.insert(Box::new(*b"env"), Arc::new(Box::new(EnvScheme::new()))).expect("failed to insert env scheme"); list.insert(Box::new(*b"initfs"), Arc::new(Box::new(InitFsScheme::new()))).expect("failed to insert initfs scheme"); list.insert(Box::new(*b"irq"), Arc::new(Box::new(IrqScheme))).expect("failed to insert irq scheme"); diff --git a/scheme/root.rs b/scheme/root.rs index a2e006009fd30fbd567c515b8dce406797cc43b5..e982c8f41b92c294d2c1b7827a01dc602efee7d1 100644 --- a/scheme/root.rs +++ b/scheme/root.rs @@ -38,7 +38,8 @@ impl Scheme for RootScheme { return Err(Error::new(EEXIST)); } let inner = Arc::new(UserInner::new(context)); - schemes.insert(path.to_vec().into_boxed_slice(), Arc::new(Box::new(UserScheme::new(Arc::downgrade(&inner))))).expect("failed to insert user scheme"); + let id = schemes.insert(path.to_vec().into_boxed_slice(), Arc::new(Box::new(UserScheme::new(Arc::downgrade(&inner))))).expect("failed to insert user scheme"); + inner.scheme_id.store(id, Ordering::SeqCst); inner }; diff --git a/scheme/user.rs b/scheme/user.rs index c3554562372d25feaea753f53a0dcf9c907502b6..a02b2b7bf11725a52f1b1468feb684716ad4d88e 100644 --- a/scheme/user.rs +++ b/scheme/user.rs @@ -15,6 +15,7 @@ use syscall::number::*; use syscall::scheme::Scheme; pub struct UserInner { + pub scheme_id: AtomicUsize, next_id: AtomicUsize, context: Weak<RwLock<Context>>, todo: Mutex<VecDeque<Packet>>, @@ -24,7 +25,8 @@ pub struct UserInner { impl UserInner { pub fn new(context: Weak<RwLock<Context>>) -> UserInner { UserInner { - next_id: AtomicUsize::new(0), + scheme_id: AtomicUsize::new(0), + next_id: AtomicUsize::new(1), context: context, todo: Mutex::new(VecDeque::new()), done: Mutex::new(BTreeMap::new()) @@ -177,7 +179,14 @@ impl UserInner { let mut i = 0; while i < len { let packet = unsafe { *(buf.as_ptr() as *const Packet).offset(i as isize) }; - self.done.lock().insert(packet.id, packet.a); + if packet.id == 0 { + match packet.a { + SYS_FEVENT => context::event::trigger(self.scheme_id.load(Ordering::SeqCst), packet.b, packet.c, packet.d), + _ => println!("Unknown scheme -> kernel message {}", packet.a) + } + } else { + self.done.lock().insert(packet.id, packet.a); + } i += 1; } diff --git a/syscall/fs.rs b/syscall/fs.rs index ca88b267fce6398bf95bc121fdc1612584a72912..91c36e4944ebac2f30836848d98d4c5274b9ebc8 100644 --- a/syscall/fs.rs +++ b/syscall/fs.rs @@ -72,6 +72,8 @@ pub fn close(fd: usize) -> Result<usize> { file }; + context::event::unregister(fd, file.scheme, file.number); + let scheme = { let schemes = scheme::schemes(); let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?; @@ -113,7 +115,9 @@ pub fn fevent(fd: usize, flags: usize) -> Result<usize> { let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?; scheme.clone() }; - scheme.fevent(file.number, flags) + scheme.fevent(file.number, flags)?; + context::event::register(fd, file.scheme, file.number); + Ok(0) } /// Get the canonical path of the file