From 273cbda8725e0e9594c0f3d66ba89a2fc1ba28bb Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 21 Dec 2024 17:08:15 +0100 Subject: [PATCH 1/2] inputd: Split ControlHandle and DisplayHandle ControlHandle is used to switch the active vt, while DisplayHandle is used by display drivers to register new vt's. There are entirely unrelated tasks and the fact that they had been merged together has been confusing me for a while. Also changed activating a VT to no longer create a new vt when none existed previously. The target graphics driver may not be able to handle the new VT. inputd -A already didn't allow activating non-existent VT's as it first tried to open a consumer handle for the target VT. --- graphics/fbcond/src/main.rs | 4 +- graphics/fbcond/src/scheme.rs | 4 -- graphics/vesad/src/main.rs | 4 +- graphics/vesad/src/scheme.rs | 8 ++-- inputd/src/lib.rs | 18 +++++++-- inputd/src/main.rs | 71 +++++++++++++++-------------------- 6 files changed, 55 insertions(+), 54 deletions(-) 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/src/main.rs b/graphics/vesad/src/main.rs index 9b01e97624..6bbab330e1 100644 --- a/graphics/vesad/src/main.rs +++ b/graphics/vesad/src/main.rs @@ -86,11 +86,13 @@ fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec, spec: &[( let _ = File::open("/scheme/debug/disable-graphical-debug"); + let mut inputd_control_handle = inputd::ControlHandle::new().unwrap(); + 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 { diff --git a/graphics/vesad/src/scheme.rs b/graphics/vesad/src/scheme.rs index 65baf8dace..b3218b2834 100644 --- a/graphics/vesad/src/scheme.rs +++ b/graphics/vesad/src/scheme.rs @@ -32,12 +32,12 @@ pub struct DisplayScheme { pub vts: BTreeMap>, next_id: usize, pub handles: BTreeMap, - pub inputd_handle: inputd::Handle, + _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 +47,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 { @@ -56,7 +56,7 @@ impl DisplayScheme { vts, next_id: 0, handles: BTreeMap::new(), - inputd_handle, + _inputd_handle: inputd_handle, } } diff --git a/inputd/src/lib.rs b/inputd/src/lib.rs index 6c55e96949..1b1dc3a2ff 100644 --- a/inputd/src/lib.rs +++ b/inputd/src/lib.rs @@ -13,9 +13,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,11 +23,21 @@ 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 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) }) } diff --git a/inputd/src/main.rs b/inputd/src/main.rs index 8aa562a888..66f204adae 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -13,7 +13,6 @@ use std::collections::BTreeMap; use std::fs::File; -use std::os::fd::AsRawFd; use std::sync::atomic::{AtomicUsize, Ordering}; use inputd::{Cmd, VtActivate}; @@ -31,9 +30,10 @@ enum Handle { notified: bool, vt: usize, }, - Device { + Display { device: String, }, + Control, } impl Handle { @@ -123,8 +123,9 @@ impl SchemeMut for InputScheme { } "handle" => { let display = path_parts.collect::>().join("."); - Handle::Device { device: display } + Handle::Display { device: display } } + "control" => Handle::Control, _ => { log::error!("inputd: invalid path {path}"); @@ -174,7 +175,7 @@ impl SchemeMut for InputScheme { Ok(copy) } - Handle::Device { device } => { + Handle::Display { device } => { assert!(buf.is_empty()); let vt = self.next_vt_id.fetch_add(1, Ordering::SeqCst); @@ -186,6 +187,10 @@ impl SchemeMut for InputScheme { 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,16 +206,15 @@ impl SchemeMut for InputScheme { let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; match handle { - Handle::Device { device } => { + Handle::Control => { if buf.len() != core::mem::size_of::() { - log::error!("inputd: device tried to write incorrectly sized command"); + 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()); return Ok(buf.len()); @@ -220,6 +224,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 => {} } @@ -340,8 +348,8 @@ 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::Producer | Handle::Control | Handle::Display { .. } => { + log::error!("inputd: producer, control or display tried to use an event queue"); Err(SysError::new(EINVAL)) } } @@ -378,13 +386,16 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { } 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) - } + if let Some(vt) = scheme.vts.get_mut(&cmd.vt) { + // 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); + scheme.active_vt = Some(vt.index); + } else { + log::error!("inputd: failed to activate non-existent VT #{}", cmd.vt) + } } if !scheme.has_new_events { @@ -442,31 +453,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), From 8e92e2c74387663d3fae2499e974b7c1bf6f3ad6 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 21 Dec 2024 18:09:15 +0100 Subject: [PATCH 2/2] inputd: Let graphics drivers pull vt activation events from inputd Previously inputd would directly push vt activation events to the graphics driver, which required being quite lazy to prevent deadlocks as well as the graphics driver having a location where events can be pushed to. By having graphics drivers pull the vt activation events instead, the effective control flow becomes simpler and it becomes easier to correctly handle multiple graphics drivers on the system. For example it becomes possible for multiple graphics drivers to present displays for a single VT as well as making it easier to provide a handoff from the early framebuffer to a real graphics driver. --- Cargo.lock | 1 + graphics/vesad/Cargo.toml | 3 +- graphics/vesad/src/main.rs | 184 +++++++++++++------- graphics/vesad/src/scheme.rs | 200 +++++++++------------- graphics/virtio-gpud/src/scheme.rs | 177 ++++++++----------- inputd/src/lib.rs | 148 +++++----------- inputd/src/main.rs | 261 +++++++++++++++++++---------- 7 files changed, 484 insertions(+), 490 deletions(-) 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/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 6bbab330e1..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,14 +80,38 @@ 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 _ = File::open("/scheme/debug/disable-graphical-debug"); - 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"); @@ -95,67 +119,99 @@ fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec, spec: &[( 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 b3218b2834..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,7 +29,7 @@ pub struct DisplayScheme { pub vts: BTreeMap>, next_id: usize, pub handles: BTreeMap, - _inputd_handle: inputd::DisplayHandle, + pub inputd_handle: inputd::DisplayHandle, } impl DisplayScheme { @@ -56,7 +53,7 @@ impl DisplayScheme { vts, next_id: 0, handles: BTreeMap::new(), - _inputd_handle: inputd_handle, + inputd_handle, } } @@ -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 1b1dc3a2ff..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)] @@ -27,6 +33,28 @@ impl DisplayHandle { self.0.read(&mut []) } + 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); @@ -43,121 +71,23 @@ impl ControlHandle { } } -#[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 66f204adae..569e1d80e4 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -11,11 +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::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,6 +32,9 @@ enum Handle { vt: usize, }, Display { + events: EventFlags, + pending: Vec, + notified: bool, device: String, }, Control, @@ -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,7 +169,12 @@ impl SchemeMut for InputScheme { } "handle" => { let display = path_parts.collect::>().join("."); - Handle::Display { device: display } + Handle::Display { + events: EventFlags::empty(), + pending: Vec::new(), + notified: false, + device: display, + } } "control" => Handle::Control, @@ -175,12 +226,32 @@ impl SchemeMut for InputScheme { Ok(copy) } - Handle::Display { 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 => { @@ -207,7 +278,7 @@ impl SchemeMut for InputScheme { match handle { Handle::Control => { - if buf.len() != core::mem::size_of::() { + if buf.len() != size_of::() { log::error!("inputd: control tried to write incorrectly sized command"); return Err(SysError::new(EINVAL)); } @@ -215,7 +286,7 @@ impl SchemeMut for InputScheme { // SAFETY: We have verified the size of the buffer above. let cmd = unsafe { &*buf.as_ptr().cast::() }; - self.pending_activate = Some(cmd.clone()); + self.switch_vt(cmd.vt)?; return Ok(buf.len()); } @@ -238,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 { @@ -270,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(); @@ -348,8 +418,17 @@ impl SchemeMut for InputScheme { *notified = false; Ok(EventFlags::empty()) } - Handle::Producer | Handle::Control | Handle::Display { .. } => { - log::error!("inputd: producer, control or display 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)) } } @@ -385,47 +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() { - if let Some(vt) = scheme.vts.get_mut(&cmd.vt) { - // 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); - } else { - log::error!("inputd: failed to activate non-existent VT #{}", cmd.vt) - } - } - 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; + _ => {} } } }