From 0e8487cf83e97911b00d185d0c03631c3f9d45e3 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 23 Sep 2016 17:54:39 -0600 Subject: [PATCH] Event support - demonstration in example scheme --- drivers/vesad/src/main.rs | 27 +++++++++-- kernel/context/context.rs | 6 ++- kernel/context/event.rs | 80 +++++++++++++++++++++++++++++++ kernel/context/mod.rs | 3 ++ kernel/scheme/debug.rs | 16 ++++++- kernel/scheme/event.rs | 93 ++++++++++++++++++++++++++++++------- kernel/scheme/mod.rs | 16 ++++--- kernel/scheme/root.rs | 3 +- kernel/scheme/user.rs | 13 +++++- kernel/syscall/fs.rs | 6 ++- schemes/example/src/main.rs | 6 +++ syscall/src/scheme.rs | 1 + 12 files changed, 239 insertions(+), 31 deletions(-) create mode 100644 kernel/context/event.rs diff --git a/drivers/vesad/src/main.rs b/drivers/vesad/src/main.rs index 41c01ba..cb45f39 100644 --- a/drivers/vesad/src/main.rs +++ b/drivers/vesad/src/main.rs @@ -13,7 +13,7 @@ use std::fs::File; use std::io::{Read, Write}; use std::{slice, thread}; use ransid::{Console, Event}; -use syscall::{physmap, physunmap, Packet, Result, Scheme, MAP_WRITE, MAP_WRITE_COMBINE}; +use syscall::{physmap, physunmap, Packet, Result, Scheme, EVENT_READ, MAP_WRITE, MAP_WRITE_COMBINE}; use display::Display; use mode_info::VBEModeInfo; @@ -26,7 +26,8 @@ pub mod primitive; struct DisplayScheme { console: RefCell, display: RefCell, - input: RefCell> + input: RefCell>, + requested: RefCell } impl Scheme for DisplayScheme { @@ -43,6 +44,7 @@ impl Scheme for DisplayScheme { } fn fevent(&self, _id: usize, flags: usize) -> Result { + *self.requested.borrow_mut() = flags; println!("fevent {:X}", flags); Ok(0) } @@ -126,7 +128,8 @@ fn main() { unsafe { slice::from_raw_parts_mut(onscreen as *mut u32, size) }, unsafe { slice::from_raw_parts_mut(offscreen as *mut u32, size) } )), - input: RefCell::new(VecDeque::new()) + input: RefCell::new(VecDeque::new()), + requested: RefCell::new(0) }; let mut blocked = VecDeque::new(); @@ -134,18 +137,36 @@ fn main() { let mut packet = Packet::default(); socket.read(&mut packet).expect("vesad: failed to read display scheme"); //println!("vesad: {:?}", packet); + + // If it is a read packet, and there is no data, block it. Otherwise, handle packet if packet.a == syscall::number::SYS_READ && packet.d > 0 && scheme.input.borrow().is_empty() { blocked.push_back(packet); } else { scheme.handle(&mut packet); socket.write(&packet).expect("vesad: failed to write display scheme"); } + + // If there are blocked readers, and data is available, handle them while ! scheme.input.borrow().is_empty() { if let Some(mut packet) = blocked.pop_front() { scheme.handle(&mut packet); socket.write(&packet).expect("vesad: failed to write display scheme"); + } else { + break; } } + + // If there are requested events, and data is available, send a notification + if ! scheme.input.borrow().is_empty() && *scheme.requested.borrow() & EVENT_READ == EVENT_READ { + let event_packet = Packet { + id: 0, + a: syscall::number::SYS_FEVENT, + b: 0, + c: EVENT_READ, + d: scheme.input.borrow().len() + }; + socket.write(&event_packet).expect("vesad: failed to write display scheme"); + } } }); } diff --git a/kernel/context/context.rs b/kernel/context/context.rs index 504b5e4..a2ab64b 100644 --- a/kernel/context/context.rs +++ b/kernel/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>>, /// The current working directory pub cwd: Arc>>, + /// Kernel events + pub events: Arc>>, /// The process environment pub env: Arc, Arc>>>>>, /// 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/kernel/context/event.rs b/kernel/context/event.rs new file mode 100644 index 0000000..06fea60 --- /dev/null +++ b/kernel/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>>; + +type Registry = BTreeMap<(usize, usize), BTreeMap<(usize, usize), EventList>>; + +static REGISTRY: Once> = Once::new(); + +/// Initialize registry, called if needed +fn init_registry() -> RwLock { + 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/kernel/context/mod.rs b/kernel/context/mod.rs index 597c301..9da1259 100644 --- a/kernel/context/mod.rs +++ b/kernel/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/kernel/scheme/debug.rs b/kernel/scheme/debug.rs index 9b630b4..52b88e5 100644 --- a/kernel/scheme/debug.rs +++ b/kernel/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>> = Once::new(); @@ -17,7 +21,13 @@ fn init_input() -> Mutex> { /// 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 { + Ok(0) + } + fn fsync(&self, _file: usize) -> Result { Ok(0) } diff --git a/kernel/scheme/event.rs b/kernel/scheme/event.rs index 7801d74..2dead8d 100644 --- a/kernel/scheme/event.rs +++ b/kernel/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>>>> +} + +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 { - 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() + }; + + let id = self.next_id.fetch_add(1, Ordering::SeqCst); + self.handles.write().insert(id, Arc::downgrade(&handle)); + + Ok(id) } - fn dup(&self, file: usize) -> Result { - Ok(file) + fn dup(&self, id: usize) -> Result { + 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 read(&self, file: usize, buffer: &mut [u8]) -> Result { - Ok(0) + fn read(&self, id: usize, buf: &mut [u8]) -> Result { + 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::(); + 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 write(&self, file: usize, buffer: &[u8]) -> Result { - Ok(0) + fn fsync(&self, id: usize) -> Result { + 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 fsync(&self, _file: usize) -> Result { - Ok(0) - } - - fn close(&self, _file: usize) -> Result { - Ok(0) + fn close(&self, id: usize) -> Result { + self.handles.write().remove(&id).ok_or(Error::new(EBADF)).and(Ok(0)) } } diff --git a/kernel/scheme/mod.rs b/kernel/scheme/mod.rs index 4d0580a..7d3e25e 100644 --- a/kernel/scheme/mod.rs +++ b/kernel/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>) -> Result<&Arc>> { + pub fn insert(&mut self, name: Box<[u8]>, scheme: Arc>) -> Result { 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> = Once::new(); fn init_schemes() -> RwLock { 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/kernel/scheme/root.rs b/kernel/scheme/root.rs index a2e0060..e982c8f 100644 --- a/kernel/scheme/root.rs +++ b/kernel/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/kernel/scheme/user.rs b/kernel/scheme/user.rs index c355456..a02b2b7 100644 --- a/kernel/scheme/user.rs +++ b/kernel/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>, todo: Mutex>, @@ -24,7 +25,8 @@ pub struct UserInner { impl UserInner { pub fn new(context: Weak>) -> 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/kernel/syscall/fs.rs b/kernel/syscall/fs.rs index ca88b26..91c36e4 100644 --- a/kernel/syscall/fs.rs +++ b/kernel/syscall/fs.rs @@ -72,6 +72,8 @@ pub fn close(fd: usize) -> Result { 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 { 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 diff --git a/schemes/example/src/main.rs b/schemes/example/src/main.rs index 3dd9c70..d854ced 100644 --- a/schemes/example/src/main.rs +++ b/schemes/example/src/main.rs @@ -30,11 +30,17 @@ fn main(){ let a = syscall::open("display:", 0).unwrap(); syscall::fevent(a, syscall::EVENT_READ).unwrap(); + let b = syscall::open("debug:", 0).unwrap(); + syscall::fevent(b, syscall::EVENT_READ).unwrap(); loop { let mut event = syscall::Event::default(); syscall::read(events, &mut event).unwrap(); println!("{:?}", event); + + let mut buf = vec![0; event.data]; + syscall::read(event.id, &mut buf).unwrap(); + println!("{}", unsafe { ::std::str::from_utf8_unchecked(&buf) }); } let _ = syscall::close(events); diff --git a/syscall/src/scheme.rs b/syscall/src/scheme.rs index 5c6099d..43d1899 100644 --- a/syscall/src/scheme.rs +++ b/syscall/src/scheme.rs @@ -14,6 +14,7 @@ pub trait Scheme { SYS_READ => self.read(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }), SYS_WRITE => self.write(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }), SYS_LSEEK => self.seek(packet.b, packet.c, packet.d), + SYS_FEVENT => self.fevent(packet.b, packet.c), SYS_FPATH => self.fpath(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }), SYS_FSTAT => self.fstat(packet.b, unsafe { &mut *(packet.c as *mut Stat) }), SYS_FSYNC => self.fsync(packet.b),