diff --git a/Cargo.lock b/Cargo.lock index 639bf4af21..e19f9fdb99 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1681,6 +1681,7 @@ dependencies = [ "ransid", "redox-daemon", "redox-scheme", + "redox_event", "redox_syscall", ] diff --git a/graphics/fbcond/src/main.rs b/graphics/fbcond/src/main.rs index 4393c9185c..7449d5a4d7 100644 --- a/graphics/fbcond/src/main.rs +++ b/graphics/fbcond/src/main.rs @@ -53,11 +53,13 @@ fn inner(daemon: redox_daemon::Daemon, vt_ids: &[usize]) -> ! { let mut scheme = FbconScheme::new(vt_ids, &mut event_queue); + let mut inputd_control_handle = inputd::ControlHandle::new().unwrap(); + libredox::call::setrens(0, 0).expect("fbcond: failed to enter null namespace"); daemon.ready().expect("failed to notify parent"); - scheme.inputd_handle.activate(1).unwrap(); + inputd_control_handle.activate_vt(1).unwrap(); let mut blocked = Vec::new(); diff --git a/graphics/fbcond/src/scheme.rs b/graphics/fbcond/src/scheme.rs index bd128f2e5a..9ff10d4dbe 100644 --- a/graphics/fbcond/src/scheme.rs +++ b/graphics/fbcond/src/scheme.rs @@ -36,13 +36,10 @@ pub struct FbconScheme { pub vts: BTreeMap, next_id: usize, pub handles: BTreeMap, - pub inputd_handle: inputd::Handle, } impl FbconScheme { pub fn new(vt_ids: &[usize], event_queue: &mut EventQueue) -> FbconScheme { - let inputd_handle = inputd::Handle::new("vesa").unwrap(); - let mut vts = BTreeMap::new(); for &vt_i in vt_ids { @@ -61,7 +58,6 @@ impl FbconScheme { vts, next_id: 0, handles: BTreeMap::new(), - inputd_handle, } } diff --git a/graphics/vesad/Cargo.toml b/graphics/vesad/Cargo.toml index 0361c8bf7d..eeb5bc77ed 100644 --- a/graphics/vesad/Cargo.toml +++ b/graphics/vesad/Cargo.toml @@ -1,13 +1,14 @@ [package] name = "vesad" version = "0.1.0" -edition = "2018" +edition = "2021" [dependencies] orbclient = "0.3.27" ransid = "0.4" redox_syscall = "0.5" redox-daemon = "0.1" +redox_event = "0.4.1" common = { path = "../../common" } inputd = { path = "../../inputd" } diff --git a/graphics/vesad/src/main.rs b/graphics/vesad/src/main.rs index 9b01e97624..b028a9ba84 100644 --- a/graphics/vesad/src/main.rs +++ b/graphics/vesad/src/main.rs @@ -2,15 +2,15 @@ extern crate orbclient; extern crate syscall; -use redox_scheme::{RequestKind, SignalBehavior, Socket, V2}; +use event::{user_data, EventQueue}; +use libredox::errno::{EAGAIN, EINTR}; +use redox_scheme::{RequestKind, Response, SignalBehavior, Socket, V2}; use std::env; use std::fs::File; +use std::os::fd::AsRawFd; use syscall::EVENT_READ; -use crate::{ - framebuffer::FrameBuffer, - scheme::{DisplayScheme, HandleKind}, -}; +use crate::{framebuffer::FrameBuffer, scheme::DisplayScheme}; mod display; mod framebuffer; @@ -80,80 +80,138 @@ fn main() { } fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec, spec: &[()]) -> ! { let socket: Socket = - Socket::create("display.vesa").expect("vesad: failed to create display scheme"); + Socket::nonblock("display.vesa").expect("vesad: failed to create display scheme"); let mut scheme = DisplayScheme::new(framebuffers, &spec); + let mut inputd_control_handle = inputd::ControlHandle::new().unwrap(); + + user_data! { + enum Source { + Input, + Scheme, + } + } + + let event_queue: EventQueue = + EventQueue::new().expect("vesad: failed to create event queue"); + event_queue + .subscribe( + scheme.inputd_handle.inner().as_raw_fd() as usize, + Source::Input, + event::EventFlags::READ, + ) + .unwrap(); + event_queue + .subscribe( + socket.inner().raw(), + Source::Scheme, + event::EventFlags::READ, + ) + .unwrap(); + let _ = File::open("/scheme/debug/disable-graphical-debug"); libredox::call::setrens(0, 0).expect("vesad: failed to enter null namespace"); daemon.ready().expect("failed to notify parent"); - scheme.inputd_handle.activate(1).unwrap(); + inputd_control_handle.activate_vt(1).unwrap(); let mut blocked = Vec::new(); - loop { - let Some(request) = socket - .next_request(SignalBehavior::Restart) - .expect("vesad: failed to read display scheme") - else { - // Scheme likely got unmounted - std::process::exit(0); - }; - - match request.kind() { - RequestKind::Call(call_request) => { - if let Some(resp) = call_request.handle_scheme_block_mut(&mut scheme) { - socket - .write_response(resp, SignalBehavior::Restart) - .expect("vesad: failed to write display scheme"); - } else { - blocked.push(call_request); + let all = [Source::Input, Source::Scheme]; + for event in all + .into_iter() + .chain(event_queue.map(|e| e.expect("vesad: failed to get next event").user_data)) + { + match event { + Source::Input => { + while let Some(vt_event) = scheme + .inputd_handle + .read_vt_event() + .expect("vesad: failed to read display handle") + { + scheme.handle_vt_event(vt_event); } } - RequestKind::Cancellation(_cancellation_request) => {} - RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => unreachable!(), - } + Source::Scheme => { + loop { + let request = match socket.next_request(SignalBehavior::Restart) { + Ok(Some(request)) => request, + Ok(None) => { + // Scheme likely got unmounted + std::process::exit(0); + } + Err(err) if err.errno == EAGAIN => break, + Err(err) => panic!("vesad: failed to read display scheme: {err}"), + }; - // If there are blocked readers, try to handle them. - { - let mut i = 0; - while i < blocked.len() { - if let Some(resp) = blocked[i].handle_scheme_block_mut(&mut scheme) { - socket - .write_response(resp, SignalBehavior::Restart) - .expect("vesad: failed to write display scheme"); - blocked.remove(i); - } else { - i += 1; + match request.kind() { + RequestKind::Call(call_request) => { + if let Some(resp) = call_request.handle_scheme_block_mut(&mut scheme) { + socket + .write_response(resp, SignalBehavior::Restart) + .expect("vesad: failed to write display scheme"); + } else { + blocked.push(call_request); + } + } + RequestKind::Cancellation(cancellation_request) => { + if let Some(i) = blocked.iter().position(|req| { + req.request().request_id() == cancellation_request.id + }) { + let blocked_req = blocked.remove(i); + let resp = + Response::new(&blocked_req, Err(syscall::Error::new(EINTR))); + socket + .write_response(resp, SignalBehavior::Restart) + .expect("vesad: failed to write display scheme"); + } + } + RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => { + unreachable!() + } + } + + // If there are blocked readers, try to handle them. + { + let mut i = 0; + while i < blocked.len() { + if let Some(resp) = blocked[i].handle_scheme_block_mut(&mut scheme) { + socket + .write_response(resp, SignalBehavior::Restart) + .expect("vesad: failed to write display scheme"); + blocked.remove(i); + } else { + i += 1; + } + } + } + + for (handle_id, handle) in scheme.handles.iter_mut() { + if handle.notified_read || !handle.events.contains(EVENT_READ) { + continue; + } + + let can_read = scheme + .vts + .get(&handle.vt) + .and_then(|screens| screens.get(&handle.screen)) + .map_or(false, |screen| screen.can_read()); + + if can_read { + handle.notified_read = true; + socket + .post_fevent(*handle_id, EVENT_READ.bits()) + .expect("vesad: failed to write display event"); + } else { + handle.notified_read = false; + } + } } } } - - for (handle_id, handle) in scheme.handles.iter_mut() { - if handle.notified_read || !handle.events.contains(EVENT_READ) { - continue; - } - - let can_read = if let HandleKind::Screen(vt_i, screen_i) = handle.kind { - scheme - .vts - .get(&vt_i) - .and_then(|screens| screens.get(&screen_i)) - .map_or(false, |screen| screen.can_read()) - } else { - false - }; - - if can_read { - handle.notified_read = true; - socket - .post_fevent(*handle_id, EVENT_READ.bits()) - .expect("vesad: failed to write display event"); - } else { - handle.notified_read = false; - } - } } + + panic!(); } diff --git a/graphics/vesad/src/scheme.rs b/graphics/vesad/src/scheme.rs index 65baf8dace..3dd2b3a9ef 100644 --- a/graphics/vesad/src/scheme.rs +++ b/graphics/vesad/src/scheme.rs @@ -1,6 +1,7 @@ use std::collections::BTreeMap; use std::str; +use inputd::{VtEvent, VtEventKind}; use redox_scheme::SchemeBlockMut; use syscall::{Error, EventFlags, MapFlags, Result, EBADF, EINVAL, ENOENT, O_NONBLOCK}; @@ -12,15 +13,11 @@ pub struct VtIndex(usize); #[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd, Debug)] pub struct ScreenIndex(usize); -#[derive(Clone)] -pub enum HandleKind { - Input, - Screen(VtIndex, ScreenIndex), -} - #[derive(Clone)] pub struct Handle { - pub kind: HandleKind, + pub vt: VtIndex, + pub screen: ScreenIndex, + pub flags: usize, pub events: EventFlags, pub notified_read: bool, @@ -32,12 +29,12 @@ pub struct DisplayScheme { pub vts: BTreeMap>, next_id: usize, pub handles: BTreeMap, - pub inputd_handle: inputd::Handle, + pub inputd_handle: inputd::DisplayHandle, } impl DisplayScheme { pub fn new(framebuffers: Vec, spec: &[()]) -> DisplayScheme { - let mut inputd_handle = inputd::Handle::new("vesa").unwrap(); + let mut inputd_handle = inputd::DisplayHandle::new("vesa").unwrap(); let mut vts = BTreeMap::>::new(); @@ -47,7 +44,7 @@ impl DisplayScheme { let fb = &framebuffers[fb_i]; screens.insert(ScreenIndex(fb_i), GraphicScreen::new(fb.width, fb.height)); } - vts.insert(VtIndex(inputd_handle.register().unwrap()), screens); + vts.insert(VtIndex(inputd_handle.register_vt().unwrap()), screens); } DisplayScheme { @@ -84,6 +81,32 @@ impl DisplayScheme { } } } + + pub fn handle_vt_event(&mut self, vt_event: VtEvent) { + match vt_event.kind { + VtEventKind::Activate => { + let vt_i = VtIndex(vt_event.vt); + + if let Some(screens) = self.vts.get_mut(&vt_i) { + for (screen_i, screen) in screens.iter_mut() { + screen.redraw(&mut self.framebuffers[screen_i.0]); + } + } + + self.active = vt_i; + } + VtEventKind::Deactivate => { + // Nothing to do for deactivate :) + } + VtEventKind::Resize => { + self.resize( + vt_event.width as usize, + vt_event.height as usize, + vt_event.stride as usize, + ); + } + } + } } impl SchemeBlockMut for DisplayScheme { @@ -94,21 +117,6 @@ impl SchemeBlockMut for DisplayScheme { _uid: u32, _gid: u32, ) -> Result> { - if path_str == "handle" { - let id = self.next_id; - self.next_id += 1; - self.handles.insert( - id, - Handle { - kind: HandleKind::Input, - flags, - events: EventFlags::empty(), - notified_read: false, - }, - ); - return Ok(Some(id)); - } - let mut parts = path_str.split('/'); let mut vt_screen = parts.next().unwrap_or("").split('.'); let vt_i = VtIndex(vt_screen.next().unwrap_or("").parse::().unwrap_or(1)); @@ -121,7 +129,9 @@ impl SchemeBlockMut for DisplayScheme { self.handles.insert( id, Handle { - kind: HandleKind::Screen(vt_i, screen_i), + vt: vt_i, + screen: screen_i, + flags, events: EventFlags::empty(), notified_read: false, @@ -164,39 +174,25 @@ impl SchemeBlockMut for DisplayScheme { let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; handle.notified_read = false; - - if let HandleKind::Screen(_vt_i, _screen_i) = handle.kind { - handle.events = flags; - Ok(Some(syscall::EventFlags::empty())) - } else { - Err(Error::new(EBADF)) - } + handle.events = flags; + Ok(Some(syscall::EventFlags::empty())) } fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - let path_str = match handle.kind { - HandleKind::Input => { - //TODO: allow inputs associated with other framebuffers? - format!( - "display:input/{}/{}", - self.framebuffers[0].width, self.framebuffers[0].height - ) - } - HandleKind::Screen(vt_i, screen_i) => { - if let Some(screens) = self.vts.get(&vt_i) { - if let Some(screen) = screens.get(&screen_i) { - format!( - "display:{}.{}/{}/{}", - vt_i.0, screen_i.0, screen.width, screen.height - ) - } else { - return Err(Error::new(EBADF)); - } + let path_str = { + if let Some(screens) = self.vts.get(&handle.vt) { + if let Some(screen) = screens.get(&handle.screen) { + format!( + "display:{}.{}/{}/{}", + handle.vt.0, handle.screen.0, screen.width, screen.height + ) } else { return Err(Error::new(EBADF)); } + } else { + return Err(Error::new(EBADF)); } }; @@ -214,14 +210,12 @@ impl SchemeBlockMut for DisplayScheme { fn fsync(&mut self, id: usize) -> Result> { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - if let HandleKind::Screen(vt_i, screen_i) = handle.kind { - if let Some(screens) = self.vts.get_mut(&vt_i) { - if let Some(screen) = screens.get_mut(&screen_i) { - if vt_i == self.active { - screen.sync(&mut self.framebuffers[screen_i.0]); - } - return Ok(Some(0)); + if let Some(screens) = self.vts.get_mut(&handle.vt) { + if let Some(screen) = screens.get_mut(&handle.screen) { + if handle.vt == self.active { + screen.sync(&mut self.framebuffers[handle.screen.0]); } + return Ok(Some(0)); } } @@ -237,18 +231,16 @@ impl SchemeBlockMut for DisplayScheme { ) -> Result> { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - if let HandleKind::Screen(vt_i, screen_i) = handle.kind { - if let Some(screens) = self.vts.get_mut(&vt_i) { - if let Some(screen) = screens.get_mut(&screen_i) { - let nread = screen.read(buf)?; - if nread != 0 { - return Ok(Some(nread)); + if let Some(screens) = self.vts.get_mut(&handle.vt) { + if let Some(screen) = screens.get_mut(&handle.screen) { + let nread = screen.read(buf)?; + if nread != 0 { + return Ok(Some(nread)); + } else { + if handle.flags & O_NONBLOCK == O_NONBLOCK { + return Ok(Some(0)); } else { - if handle.flags & O_NONBLOCK == O_NONBLOCK { - return Ok(Some(0)); - } else { - return Ok(None); - } + return Ok(None); } } } @@ -266,56 +258,18 @@ impl SchemeBlockMut for DisplayScheme { ) -> Result> { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - match handle.kind { - HandleKind::Input => { - use inputd::Cmd as DisplayCommand; - - let command = inputd::parse_command(buf).unwrap(); - - match command { - DisplayCommand::Activate { vt } => { - let vt_i = VtIndex(vt); - - if let Some(screens) = self.vts.get_mut(&vt_i) { - for (screen_i, screen) in screens.iter_mut() { - screen.redraw(&mut self.framebuffers[screen_i.0]); - } - } - - self.active = vt_i; - } - - DisplayCommand::Resize { - width, - height, - stride, - .. - } => { - self.resize(width as usize, height as usize, stride as usize); - } - - // Nothing to do for deactivate :) - DisplayCommand::Deactivate(_) => {} - } - - Ok(Some(buf.len())) - } - - HandleKind::Screen(vt_i, screen_i) => { - if let Some(screens) = self.vts.get_mut(&vt_i) { - if let Some(screen) = screens.get_mut(&screen_i) { - let count = screen.write(buf)?; - if vt_i == self.active { - screen.sync(&mut self.framebuffers[screen_i.0]); - } - Ok(Some(count)) - } else { - Err(Error::new(EBADF)) - } - } else { - Err(Error::new(EBADF)) + if let Some(screens) = self.vts.get_mut(&handle.vt) { + if let Some(screen) = screens.get_mut(&handle.screen) { + let count = screen.write(buf)?; + if handle.vt == self.active { + screen.sync(&mut self.framebuffers[handle.screen.0]); } + Ok(Some(count)) + } else { + Err(Error::new(EBADF)) } + } else { + Err(Error::new(EBADF)) } } @@ -332,14 +286,12 @@ impl SchemeBlockMut for DisplayScheme { ) -> Result> { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - if let HandleKind::Screen(vt_i, screen_i) = handle.kind { - if let Some(screens) = self.vts.get(&vt_i) { - if let Some(screen) = screens.get(&screen_i) { - if off as usize + size <= screen.offscreen.len() * 4 { - return Ok(Some(screen.offscreen.as_ptr() as usize + off as usize)); - } else { - return Err(Error::new(EINVAL)); - } + if let Some(screens) = self.vts.get(&handle.vt) { + if let Some(screen) = screens.get(&handle.screen) { + if off as usize + size <= screen.offscreen.len() * 4 { + return Ok(Some(screen.offscreen.as_ptr() as usize + off as usize)); + } else { + return Err(Error::new(EINVAL)); } } } diff --git a/graphics/virtio-gpud/src/scheme.rs b/graphics/virtio-gpud/src/scheme.rs index 462a29070c..84c2da348f 100644 --- a/graphics/virtio-gpud/src/scheme.rs +++ b/graphics/virtio-gpud/src/scheme.rs @@ -5,7 +5,7 @@ use std::sync::atomic::{AtomicBool, AtomicU32, AtomicUsize, Ordering}; use std::sync::Arc; use common::{dma::Dma, sgl}; -use inputd::Damage; +use inputd::{Damage, VtEvent, VtEventKind}; use redox_scheme::SchemeMut; use syscall::{Error as SysError, MapFlags, EAGAIN, EINVAL, PAGE_SIZE}; @@ -246,12 +246,9 @@ impl<'a> Display<'a> { } } -enum Handle<'a> { - Vt { - display: Arc>, - vt: usize, - }, - Input, +struct Handle<'a> { + display: Arc>, + vt: usize, } pub struct Scheme<'a> { @@ -331,17 +328,52 @@ impl<'a> Scheme<'a> { Ok(response) } + + // FIXME wire this up + fn handle_vt_event(&mut self, vt_event: VtEvent) { + match vt_event.kind { + VtEventKind::Activate => { + log::info!("activate {}", vt_event.vt); + + for handle in self.handles.values() { + if handle.vt != vt_event.vt { + continue; + } + + log::warn!("virtio-gpu: activating"); + + futures::executor::block_on(handle.display.init()).unwrap(); + } + } + + VtEventKind::Deactivate => { + log::info!("deactivate {}", vt_event.vt); + + for handle in self.handles.values() { + if handle.vt != vt_event.vt { + continue; + } + + log::warn!("virtio-gpu: deactivating"); + + futures::executor::block_on(handle.display.detach()).unwrap(); + break; + } + + // for display in self.displays.iter() { + // futures::executor::block_on(display.detach()).unwrap(); + // } + } + + VtEventKind::Resize => { + log::warn!("virtio-gpu: resize is not implemented yet") + } + } + } } impl<'a> SchemeMut for Scheme<'a> { fn open(&mut self, path: &str, _flags: usize, _uid: u32, _gid: u32) -> syscall::Result { - if path == "handle" { - let fd = self.next_id.fetch_add(1, Ordering::SeqCst); - self.handles.insert(fd, Handle::Input); - - return Ok(fd); - } - let mut parts = path.split('/'); let mut screen = parts.next().unwrap_or("").split('.'); @@ -355,7 +387,7 @@ impl<'a> SchemeMut for Scheme<'a> { let fd = self.next_id.fetch_add(1, Ordering::SeqCst); self.handles.insert( fd, - Handle::Vt { + Handle { display: display.clone(), vt, }, @@ -364,25 +396,15 @@ impl<'a> SchemeMut for Scheme<'a> { } fn fpath(&mut self, id: usize, buf: &mut [u8]) -> syscall::Result { - match self.handles.get(&id).unwrap() { - Handle::Vt { display, .. } => { - let bytes_copied = futures::executor::block_on(display.get_fpath(buf)).unwrap(); - Ok(bytes_copied) - } - - Handle::Input => unreachable!(), - } + let handle = self.handles.get(&id).unwrap(); + let bytes_copied = futures::executor::block_on(handle.display.get_fpath(buf)).unwrap(); + Ok(bytes_copied) } fn fsync(&mut self, id: usize) -> syscall::Result { - match self.handles.get(&id).ok_or(SysError::new(EINVAL))? { - Handle::Vt { display, .. } => { - futures::executor::block_on(display.flush(None)).unwrap(); - Ok(0) - } - - _ => unreachable!(), - } + let handle = self.handles.get(&id).ok_or(SysError::new(EINVAL))?; + futures::executor::block_on(handle.display.flush(None)).unwrap(); + Ok(0) } fn read( @@ -404,73 +426,26 @@ impl<'a> SchemeMut for Scheme<'a> { _offset: u64, _fcntl_flags: u32, ) -> syscall::Result { - match self.handles.get(&id).ok_or(SysError::new(EINVAL))? { - Handle::Vt { display, .. } => { - // The VT is not active and the device is reseted. Ask them to try - // again later. - if display.is_reseted.load(Ordering::SeqCst) { - return Err(SysError::new(EAGAIN)); - } + let handle = self.handles.get(&id).ok_or(SysError::new(EINVAL))?; - let damages = unsafe { - core::slice::from_raw_parts( - buf.as_ptr() as *const Damage, - buf.len() / core::mem::size_of::(), - ) - }; - - for damage in damages { - futures::executor::block_on(display.flush(Some(damage))).unwrap(); - } - - Ok(buf.len()) - } - - Handle::Input => { - use inputd::Cmd as DisplayCommand; - - let command = inputd::parse_command(buf).unwrap(); - - match command { - DisplayCommand::Activate { vt } => { - let target_vt = vt; - - for handle in self.handles.values() { - if let Handle::Vt { display, vt } = handle { - if *vt != target_vt { - continue; - } - - futures::executor::block_on(display.init()).unwrap(); - } - } - } - - DisplayCommand::Deactivate(target_vt) => { - for handle in self.handles.values() { - if let Handle::Vt { display, vt } = handle { - if *vt != target_vt { - continue; - } - - futures::executor::block_on(display.detach()).unwrap(); - break; - } - } - - // for display in self.displays.iter() { - // futures::executor::block_on(display.detach()).unwrap(); - // } - } - - DisplayCommand::Resize { .. } => { - log::warn!("virtio-gpu: resize is not implemented yet") - } - } - - Ok(buf.len()) - } + // The VT is not active and the device is reseted. Ask them to try + // again later. + if handle.display.is_reseted.load(Ordering::SeqCst) { + return Err(SysError::new(EAGAIN)); } + + let damages = unsafe { + core::slice::from_raw_parts( + buf.as_ptr() as *const Damage, + buf.len() / core::mem::size_of::(), + ) + }; + + for damage in damages { + futures::executor::block_on(handle.display.flush(Some(damage))).unwrap(); + } + + Ok(buf.len()) } fn close(&mut self, _id: usize) -> syscall::Result { @@ -484,12 +459,8 @@ impl<'a> SchemeMut for Scheme<'a> { flags: MapFlags, ) -> syscall::Result { log::info!("KSMSG MMAP {} {:?} {} {}", id, flags, offset, size); - match self.handles.get(&id).ok_or(SysError::new(EINVAL))? { - Handle::Vt { display, .. } => Ok(futures::executor::block_on( - display.map_screen(offset as usize), - ) - .unwrap() as usize), - _ => unreachable!(), - } + let handle = self.handles.get(&id).ok_or(SysError::new(EINVAL))?; + let ptr = futures::executor::block_on(handle.display.map_screen(offset as usize)).unwrap(); + Ok(ptr as usize) } } diff --git a/inputd/src/lib.rs b/inputd/src/lib.rs index 6c55e96949..e48539f683 100644 --- a/inputd/src/lib.rs +++ b/inputd/src/lib.rs @@ -2,9 +2,15 @@ use std::fs::File; use std::io::{Error, Read, Write}; +use std::mem::size_of; +use std::os::fd::{AsFd, BorrowedFd}; unsafe fn any_as_u8_slice(p: &T) -> &[u8] { - ::core::slice::from_raw_parts((p as *const T) as *const u8, ::core::mem::size_of::()) + std::slice::from_raw_parts((p as *const T) as *const u8, size_of::()) +} + +unsafe fn any_as_u8_slice_mut(p: &mut T) -> &mut [u8] { + std::slice::from_raw_parts_mut((p as *mut T) as *mut u8, size_of::()) } #[derive(Debug, Clone)] @@ -13,9 +19,9 @@ pub struct VtActivate { pub vt: usize, } -pub struct Handle(File); +pub struct DisplayHandle(File); -impl Handle { +impl DisplayHandle { pub fn new>(device_name: S) -> Result { let path = format!("/scheme/input/handle/display/{}", device_name.into()); Ok(Self(File::open(path)?)) @@ -23,131 +29,65 @@ impl Handle { // The return value is the display identifier. It will be used to uniquely // identify the display on activation events. - pub fn register(&mut self) -> Result { + pub fn register_vt(&mut self) -> Result { self.0.read(&mut []) } - pub fn activate(&mut self, vt: usize) -> Result { + pub fn read_vt_event(&mut self) -> Result, Error> { + let mut event = VtEvent { + kind: VtEventKind::Resize, + vt: usize::MAX, + width: u32::MAX, + height: u32::MAX, + stride: u32::MAX, + }; + + let nread = self.0.read(unsafe { any_as_u8_slice_mut(&mut event) })?; + + if nread == 0 { + Ok(None) + } else { + assert_eq!(nread, size_of::()); + Ok(Some(event)) + } + } + + pub fn inner(&self) -> BorrowedFd<'_> { + self.0.as_fd() + } +} + +pub struct ControlHandle(File); + +impl ControlHandle { + pub fn new() -> Result { + let path = format!("/scheme/input/control"); + Ok(Self(File::open(path)?)) + } + + pub fn activate_vt(&mut self, vt: usize) -> Result { let cmd = VtActivate { vt }; self.0.write(unsafe { any_as_u8_slice(&cmd) }) } } -#[derive(Debug, Copy, Clone, PartialEq)] -#[repr(u8)] -enum CmdTy { - Unknown = 0, - +#[derive(Debug)] +#[repr(usize)] +pub enum VtEventKind { Activate, Deactivate, Resize, } -impl From for CmdTy { - fn from(value: u8) -> Self { - match value { - 1 => CmdTy::Activate, - 2 => CmdTy::Deactivate, - 3 => CmdTy::Resize, - _ => CmdTy::Unknown, - } - } -} - #[derive(Debug)] -pub enum Cmd { - // TODO(andypython): #VT should really need to be a `u8`. - Activate { - vt: usize, - }, +#[repr(C)] +pub struct VtEvent { + pub kind: VtEventKind, + pub vt: usize, - Deactivate(usize /* #VT */), - Resize { - // TODO(andypython): do we really need to pass the VT here? - vt: usize, - - width: u32, - height: u32, - stride: u32, - }, -} - -impl Cmd { - fn ty(&self) -> CmdTy { - match self { - Cmd::Activate { .. } => CmdTy::Activate, - Cmd::Deactivate(_) => CmdTy::Deactivate, - Cmd::Resize { .. } => CmdTy::Resize, - } - } -} - -pub fn send_comand(file: &mut File, command: Cmd) -> Result<(), libredox::error::Error> { - use std::os::fd::AsRawFd; - - let mut result = vec![]; - result.push(command.ty() as u8); - - match command { - Cmd::Activate { vt } => { - let cmd = VtActivate { vt }; - let bytes = unsafe { any_as_u8_slice(&cmd) }; - - result.extend_from_slice(bytes); - } - - Cmd::Deactivate(vt) => result.extend_from_slice(&vt.to_le_bytes()), - Cmd::Resize { - vt, - width, - height, - stride, - } => { - result.extend_from_slice(&vt.to_le_bytes()); - result.extend(width.to_le_bytes()); - result.extend(height.to_le_bytes()); - result.extend(stride.to_le_bytes()); - } - }; - - let written = libredox::call::write(file.as_raw_fd() as usize, &result)?; - - // XXX: Ensure all of the data is written. - assert_eq!(written, result.len()); - Ok(()) -} - -pub fn parse_command(buffer: &[u8]) -> Option { - const U32_SIZE: usize = core::mem::size_of::(); - const USIZE_SIZE: usize = core::mem::size_of::(); - - let mut parser = buffer.iter().cloned(); - - let command = CmdTy::from(parser.next()?); - let vt = usize::from_le_bytes(parser.next_chunk::().ok()?); - - match command { - CmdTy::Activate => { - let cmd = unsafe { &*buffer.as_ptr().offset(1).cast::() }; - Some(Cmd::Activate { vt: cmd.vt }) - } - - CmdTy::Deactivate => Some(Cmd::Deactivate(vt)), - CmdTy::Resize => { - let width = parser.next_chunk::().ok()?; - let height = parser.next_chunk::().ok()?; - let stride = parser.next_chunk::().ok()?; - - Some(Cmd::Resize { - vt, - width: u32::from_le_bytes(width), - height: u32::from_le_bytes(height), - stride: u32::from_le_bytes(stride), - }) - } - - CmdTy::Unknown => None, - } + pub width: u32, + pub height: u32, + pub stride: u32, } #[repr(packed)] diff --git a/inputd/src/main.rs b/inputd/src/main.rs index 8aa562a888..569e1d80e4 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -11,12 +11,12 @@ //! Read events from `input:consumer`. Optionally, set the `EVENT_READ` flag to be notified when //! events are available. +use core::mem::size_of; use std::collections::BTreeMap; -use std::fs::File; -use std::os::fd::AsRawFd; +use std::mem::transmute; use std::sync::atomic::{AtomicUsize, Ordering}; -use inputd::{Cmd, VtActivate}; +use inputd::{VtActivate, VtEvent, VtEventKind}; use redox_scheme::{RequestKind, SchemeMut, SignalBehavior, Socket, V2}; @@ -31,9 +31,13 @@ enum Handle { notified: bool, vt: usize, }, - Device { + Display { + events: EventFlags, + pending: Vec, + notified: bool, device: String, }, + Control, } impl Handle { @@ -44,28 +48,14 @@ impl Handle { struct Vt { display: String, - index: usize, - - /// This is *required* to be lazily initialized since opening the handle to the display - /// requires the system call to return first. Otherwise, it will block indefinitely. - handle_file: Option, } impl Vt { - fn new(display: impl Into, index: usize) -> Self { + fn new(display: impl Into) -> Self { Self { display: display.into(), - handle_file: None, - index, } } - - fn send_command(&mut self, cmd: Cmd) -> Result<(), libredox::error::Error> { - let handle_file = self - .handle_file - .get_or_insert_with(|| File::open(format!("/scheme/{}/handle", self.display)).unwrap()); - inputd::send_comand(handle_file, cmd) - } } struct InputScheme { @@ -78,7 +68,6 @@ struct InputScheme { super_key: bool, active_vt: Option, - pending_activate: Option, has_new_events: bool, } @@ -93,10 +82,67 @@ impl InputScheme { super_key: false, active_vt: None, - pending_activate: None, has_new_events: false, } } + + fn switch_vt(&mut self, new_active: usize) -> syscall::Result<()> { + if let Some(active_vt) = self.active_vt { + if new_active == active_vt { + return Ok(()); + } + } + + if !self.vts.contains_key(&new_active) { + log::warn!("inputd: switch to non-existent VT #{new_active} was requested"); + return Ok(()); + } + + log::info!( + "inputd: switching from VT #{} to VT #{new_active}", + self.active_vt.unwrap_or(0) + ); + + for handle in self.handles.values_mut() { + match handle { + Handle::Display { + pending, + notified, + device, + .. + } => { + if let Some(active_vt) = self.active_vt { + if &self.vts[&active_vt].display == &*device { + pending.push(VtEvent { + kind: VtEventKind::Deactivate, + vt: self.active_vt.unwrap(), + width: 0, + height: 0, + stride: 0, + }); + *notified = false; + } + } + + if &self.vts[&new_active].display == &*device { + pending.push(VtEvent { + kind: VtEventKind::Activate, + vt: new_active, + width: 0, + height: 0, + stride: 0, + }); + *notified = false; + } + } + _ => continue, + } + } + + self.active_vt = Some(new_active); + + Ok(()) + } } impl SchemeMut for InputScheme { @@ -123,8 +169,14 @@ impl SchemeMut for InputScheme { } "handle" => { let display = path_parts.collect::>().join("."); - Handle::Device { device: display } + Handle::Display { + events: EventFlags::empty(), + pending: Vec::new(), + notified: false, + device: display, + } } + "control" => Handle::Control, _ => { log::error!("inputd: invalid path {path}"); @@ -174,18 +226,42 @@ impl SchemeMut for InputScheme { Ok(copy) } - Handle::Device { device } => { - assert!(buf.is_empty()); + Handle::Display { + pending, device, .. + } => { + // FIXME Create new VT through a write instead and return a NewVt event on read + // This allows also returning events for VT (de)activation from the display handle + // rather than pushing them to the graphics driver. + if buf.is_empty() { + // Trying to do an empty read creates a new VT. + let vt = self.next_vt_id.fetch_add(1, Ordering::SeqCst); + log::info!("inputd: created VT #{vt} for {device}"); + self.vts.insert(vt, Vt::new(device.clone())); + Ok(vt) + } else if buf.len() % size_of::() == 0 { + let copy = core::cmp::min(pending.len(), buf.len() / size_of::()); - let vt = self.next_vt_id.fetch_add(1, Ordering::SeqCst); - self.vts.insert(vt, Vt::new(device.clone(), vt)); - Ok(vt) + for (i, event) in pending.drain(..copy).enumerate() { + buf[i * size_of::()..(i + 1) * size_of::()] + .copy_from_slice(&unsafe { + transmute::()]>(event) + }); + } + Ok(copy * size_of::()) + } else { + log::error!("inputd: display tried to read incorrectly sized event"); + return Err(SysError::new(EINVAL)); + } } Handle::Producer => { log::error!("inputd: producer tried to read"); return Err(SysError::new(EINVAL)); } + Handle::Control => { + log::error!("inputd: control tried to read"); + return Err(SysError::new(EINVAL)); + } } } @@ -201,17 +277,16 @@ impl SchemeMut for InputScheme { let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; match handle { - Handle::Device { device } => { - if buf.len() != core::mem::size_of::() { - log::error!("inputd: device tried to write incorrectly sized command"); + Handle::Control => { + if buf.len() != size_of::() { + log::error!("inputd: control tried to write incorrectly sized command"); return Err(SysError::new(EINVAL)); } // SAFETY: We have verified the size of the buffer above. let cmd = unsafe { &*buf.as_ptr().cast::() }; - self.vts.insert(cmd.vt, Vt::new(device.clone(), cmd.vt)); - self.pending_activate = Some(cmd.clone()); + self.switch_vt(cmd.vt)?; return Ok(buf.len()); } @@ -220,6 +295,10 @@ impl SchemeMut for InputScheme { log::error!("inputd: consumer tried to write"); return Err(SysError::new(EINVAL)); } + Handle::Display { .. } => { + log::error!("inputd: display tried to write"); + return Err(SysError::new(EINVAL)); + } Handle::Producer => {} } @@ -230,11 +309,11 @@ impl SchemeMut for InputScheme { let events = unsafe { core::slice::from_raw_parts( buf.as_ptr() as *const Event, - buf.len() / core::mem::size_of::(), + buf.len() / size_of::(), ) }; - 'out: for event in events.iter() { + for event in events.iter() { let mut new_active_opt = None; match event.to_option() { EventOption::Key(key_event) => match key_event.scancode { @@ -262,42 +341,41 @@ impl SchemeMut for InputScheme { }, EventOption::Resize(resize_event) => { - let active_vt = self.vts.get_mut(&self.active_vt.unwrap()).unwrap(); - active_vt.send_command(Cmd::Resize { - vt: active_vt.index, - width: resize_event.width, - height: resize_event.height, + for handle in self.handles.values_mut() { + match handle { + Handle::Display { + pending, + notified, + device, + .. + } => { + if &self.vts[&self.active_vt.unwrap()].display == &*device { + pending.push(VtEvent { + kind: VtEventKind::Resize, + vt: self.active_vt.unwrap(), + width: resize_event.width, + height: resize_event.height, - // TODO(andypython): Figure out how to get the stride. - stride: resize_event.width, - })?; + // TODO(andypython): Figure out how to get the stride. + stride: resize_event.width, + }); + *notified = false; + } + } + _ => continue, + } + } } _ => continue, } if let Some(new_active) = new_active_opt { - if new_active == self.vts[&self.active_vt.unwrap()].index { - continue 'out; - } - - if self.vts.contains_key(&new_active) { - let active_vt = self.vts.get_mut(&self.active_vt.unwrap()).unwrap(); - - active_vt.send_command(Cmd::Deactivate(active_vt.index))?; - } - - if let Some(new_active) = self.vts.get_mut(&new_active) { - new_active.send_command(Cmd::Activate { - vt: new_active.index, - })?; - self.active_vt = Some(new_active.index); - } else { - log::warn!("inputd: switch to non-existent VT #{new_active} was requested"); - } + self.switch_vt(new_active)?; } } + let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; assert!(handle.is_producer()); let active_vt = self.active_vt.unwrap(); @@ -340,8 +418,17 @@ impl SchemeMut for InputScheme { *notified = false; Ok(EventFlags::empty()) } - Handle::Producer | Handle::Device { .. } => { - log::error!("inputd: producer or device tried to use an event queue"); + Handle::Display { + ref mut events, + ref mut notified, + .. + } => { + *events = flags; + *notified = false; + Ok(EventFlags::empty()) + } + Handle::Producer | Handle::Control => { + log::error!("inputd: producer or control tried to use an event queue"); Err(SysError::new(EINVAL)) } } @@ -377,44 +464,51 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => unreachable!(), } - if let Some(cmd) = scheme.pending_activate.take() { - let vt = scheme.vts.get_mut(&cmd.vt).unwrap(); - // Failing to activate a VT is not a fatal error. - if let Err(err) = vt.send_command(Cmd::Activate { vt: vt.index }) { - log::error!("inputd: failed to activate VT #{}: {err}", vt.index) - } - - scheme.active_vt = Some(vt.index); - } - if !scheme.has_new_events { continue; } for (id, handle) in scheme.handles.iter_mut() { - if let Handle::Consumer { - events, - pending, - ref mut notified, - vt, - } = handle - { - if pending.is_empty() || *notified || !events.contains(EventFlags::EVENT_READ) { - continue; + match handle { + Handle::Consumer { + events, + pending, + ref mut notified, + vt, + } => { + if pending.is_empty() || *notified || !events.contains(EventFlags::EVENT_READ) { + continue; + } + + let active_vt = scheme.active_vt.unwrap(); + + // The activate VT is not the same as the VT that the consumer is listening to + // for events. + if active_vt != *vt { + continue; + } + + // Notify the consumer that we have some events to read. Yum yum. + socket_file.post_fevent(*id, EventFlags::EVENT_READ.bits())?; + + *notified = true; } + Handle::Display { + events, + pending, + ref mut notified, + .. + } => { + if pending.is_empty() || *notified || !events.contains(EventFlags::EVENT_READ) { + continue; + } - let active_vt = scheme.active_vt.unwrap(); + // Notify the consumer that we have some events to read. Yum yum. + socket_file.post_fevent(*id, EventFlags::EVENT_READ.bits())?; - // The activate VT is not the same as the VT that the consumer is listening to - // for events. - if active_vt != *vt { - continue; + *notified = true; } - - // Notify the consumer that we have some events to read. Yum yum. - socket_file.post_fevent(*id, EventFlags::EVENT_READ.bits())?; - - *notified = true; + _ => {} } } } @@ -442,31 +536,11 @@ fn main() { "-A" => { let vt = args.next().unwrap().parse::().unwrap(); - let handle = File::open(format!("/scheme/input/consumer/{vt}")) - .expect("inputd: failed to open consumer handle"); - let mut display_path = [0; 4096]; - - let written = libredox::call::fpath(handle.as_raw_fd() as usize, &mut display_path) - .expect("inputd: fpath() failed"); - - assert!(written <= display_path.len()); - drop(handle); - - let display_path = std::str::from_utf8(&display_path[..written]) - .expect("inputd: display path UTF-8 validation failed"); - let display_name = display_path - .split('.') - .skip(1) - .next() - .expect("inputd: invalid display path"); - let display_scheme = display_name - .split(':') - .next() - .expect("inputd: invalid display path"); - - let mut handle = inputd::Handle::new(display_scheme) - .expect("inputd: failed to open display handle"); - handle.activate(vt).expect("inputd: failed to activate VT"); + let mut handle = + inputd::ControlHandle::new().expect("inputd: failed to open display handle"); + handle + .activate_vt(vt) + .expect("inputd: failed to activate VT"); } _ => panic!("inputd: invalid argument: {}", val),