From 943cbe37079d3e102cc5a0e7fecfe868d505d262 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 15 Mar 2025 16:27:04 +0100 Subject: [PATCH 1/7] graphics/fbbootlogd: Remove workaround that prevents blocking on the graphics driver Instead logd will no longer block on fbbootlogd to prevent the deadlock that this worked around. --- graphics/fbbootlogd/src/display.rs | 37 ++++-------------------------- graphics/fbbootlogd/src/main.rs | 10 ++++---- 2 files changed, 8 insertions(+), 39 deletions(-) diff --git a/graphics/fbbootlogd/src/display.rs b/graphics/fbbootlogd/src/display.rs index d276a24038..a26f0fc578 100644 --- a/graphics/fbbootlogd/src/display.rs +++ b/graphics/fbbootlogd/src/display.rs @@ -5,7 +5,6 @@ use libredox::errno::ESTALE; use orbclient::Event; use std::mem; use std::os::fd::BorrowedFd; -use std::sync::mpsc::{self, Receiver, Sender}; use std::sync::{Arc, Mutex}; use std::{io, os::unix::io::AsRawFd, slice}; @@ -35,12 +34,7 @@ pub struct DisplayMap { pub inner: graphics_ipc::v1::DisplayMap, } -enum DisplayCommand { - SyncRects(Vec), -} - pub struct Display { - cmd_tx: Sender, pub map: Arc>>, } @@ -67,13 +61,7 @@ impl Display { Self::handle_input_events(map_clone, input_handle); }); - let (cmd_tx, cmd_rx) = mpsc::channel(); - let map_clone = map.clone(); - std::thread::spawn(move || { - Self::handle_sync_rect(map_clone, cmd_rx); - }); - - Ok(Self { cmd_tx, map }) + Ok(Self { map }) } fn handle_input_events(map: Arc>>, input_handle: ConsumerHandle) { @@ -129,26 +117,9 @@ impl Display { } } - fn handle_sync_rect(map: Arc>>, cmd_rx: Receiver) { - while let Ok(cmd) = cmd_rx.recv() { - match cmd { - DisplayCommand::SyncRects(sync_rects) => { - // We may not hold this lock across the write call to avoid deadlocking if the - // graphics driver tries to write to the bootlog. - let display_handle = if let Some(map) = &*map.lock().unwrap() { - map.display_handle.clone() - } else { - continue; - }; - display_handle.sync_rects(&sync_rects).unwrap(); - } - } + pub fn sync_rects(&mut self, sync_rects: Vec) { + if let Some(map) = &*self.map.lock().unwrap() { + map.display_handle.sync_rects(&sync_rects).unwrap(); } } - - pub fn sync_rects(&mut self, sync_rects: Vec) { - self.cmd_tx - .send(DisplayCommand::SyncRects(sync_rects)) - .unwrap(); - } } diff --git a/graphics/fbbootlogd/src/main.rs b/graphics/fbbootlogd/src/main.rs index 1b0d941362..b566a76df4 100644 --- a/graphics/fbbootlogd/src/main.rs +++ b/graphics/fbbootlogd/src/main.rs @@ -1,13 +1,11 @@ //! Fbbootlogd renders the boot log and presents it on VT1. //! -//! While fbbootlogd is superficially similar to fbcond, there are two major differences: +//! While fbbootlogd is superficially similar to fbcond, the major difference is: //! //! * Fbbootlogd doesn't accept input coming from the keyboard. It only allows getting written to. -//! * Writing to fbbootlogd will never block. Not even on the graphics driver or inputd. This makes -//! it safe for graphics drivers and inputd to write to the boot log without risking deadlocks. -//! Fbcond will block on the graphics driver during handoff and will continously block on inputd -//! to get new input. Fbbootlogd does all blocking operations in background threads such that the -//! main thread will always keep accepting new input and writing it to the framebuffer. +//! +//! In the future fbbootlogd may also pull from logd as opposed to have logd push logs to it. And it +//! it could display a boot splash like plymouth instead of a boot log when booting in quiet mode. use redox_scheme::{RequestKind, SignalBehavior, Socket}; From 56808dbfb14babd9a98ba912e8ce99f34571a551 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 15 Mar 2025 16:50:29 +0100 Subject: [PATCH 2/7] graphics/fbbootlogd: Remove input events background thread --- graphics/fbbootlogd/src/display.rs | 56 +++++++-------------- graphics/fbbootlogd/src/main.rs | 81 ++++++++++++++++++++++-------- graphics/fbbootlogd/src/scheme.rs | 6 +-- 3 files changed, 79 insertions(+), 64 deletions(-) diff --git a/graphics/fbbootlogd/src/display.rs b/graphics/fbbootlogd/src/display.rs index a26f0fc578..430bff7c12 100644 --- a/graphics/fbbootlogd/src/display.rs +++ b/graphics/fbbootlogd/src/display.rs @@ -1,12 +1,11 @@ -use event::{user_data, EventQueue}; use graphics_ipc::v1::{Damage, V1GraphicsHandle}; use inputd::ConsumerHandle; use libredox::errno::ESTALE; use orbclient::Event; use std::mem; use std::os::fd::BorrowedFd; -use std::sync::{Arc, Mutex}; -use std::{io, os::unix::io::AsRawFd, slice}; +use std::os::unix::io::AsRawFd; +use std::{io, slice}; fn read_to_slice( file: BorrowedFd, @@ -24,18 +23,19 @@ fn read_to_slice( fn display_fd_map(display_handle: V1GraphicsHandle) -> io::Result { let display_map = display_handle.map_display()?; Ok(DisplayMap { - display_handle: Arc::new(display_handle), + display_handle, inner: display_map, }) } pub struct DisplayMap { - display_handle: Arc, + display_handle: V1GraphicsHandle, pub inner: graphics_ipc::v1::DisplayMap, } pub struct Display { - pub map: Arc>>, + pub input_handle: ConsumerHandle, + pub map: Option, } impl Display { @@ -45,51 +45,28 @@ impl Display { let map = match input_handle.open_display() { Ok(display) => { let display_handle = V1GraphicsHandle::from_file(display)?; - Arc::new(Mutex::new(Some( + Some( display_fd_map(display_handle) .unwrap_or_else(|e| panic!("failed to map display: {e}")), - ))) + ) } Err(err) => { println!("fbbootlogd: No display present yet: {err}"); - Arc::new(Mutex::new(None)) + None } }; - let map_clone = map.clone(); - std::thread::spawn(move || { - Self::handle_input_events(map_clone, input_handle); - }); - - Ok(Self { map }) + Ok(Self { input_handle, map }) } - fn handle_input_events(map: Arc>>, input_handle: ConsumerHandle) { - let event_queue = EventQueue::new().expect("fbbootlogd: failed to create event queue"); - - user_data! { - enum Source { - Input, - } - } - - // FIXME listen for resize events from inputd and handle them - - event_queue - .subscribe( - input_handle.inner().as_raw_fd() as usize, - Source::Input, - event::EventFlags::READ, - ) - .expect("fbbootlogd: failed to subscribe to scheme events"); - + pub fn handle_input_events(&mut self) { let mut events = [Event::new(); 16]; - for Source::Input in event_queue.map(|event| event.unwrap().user_data) { - match read_to_slice(input_handle.inner(), &mut events) { + loop { + match read_to_slice(self.input_handle.inner(), &mut events) { Err(err) if err.errno() == ESTALE => { eprintln!("fbbootlogd: handoff requested"); - let new_display_handle = match input_handle.open_display() { + let new_display_handle = match self.input_handle.open_display() { Ok(display) => V1GraphicsHandle::from_file(display).unwrap(), Err(err) => { println!("fbbootlogd: No display present yet: {err}"); @@ -99,7 +76,7 @@ impl Display { match display_fd_map(new_display_handle) { Ok(ok) => { - *map.lock().unwrap() = Some(ok); + self.map = Some(ok); eprintln!("fbbootlogd: handoff finished"); } @@ -109,6 +86,7 @@ impl Display { } } + Ok(0) => break, Ok(_count) => {} Err(err) => { panic!("fbbootlogd: error while reading events: {err}"); @@ -118,7 +96,7 @@ impl Display { } pub fn sync_rects(&mut self, sync_rects: Vec) { - if let Some(map) = &*self.map.lock().unwrap() { + if let Some(map) = &self.map { map.display_handle.sync_rects(&sync_rects).unwrap(); } } diff --git a/graphics/fbbootlogd/src/main.rs b/graphics/fbbootlogd/src/main.rs index b566a76df4..30e99c9ea0 100644 --- a/graphics/fbbootlogd/src/main.rs +++ b/graphics/fbbootlogd/src/main.rs @@ -7,6 +7,10 @@ //! In the future fbbootlogd may also pull from logd as opposed to have logd push logs to it. And it //! it could display a boot splash like plymouth instead of a boot log when booting in quiet mode. +use std::os::fd::AsRawFd; + +use event::EventQueue; +use libredox::errno::EAGAIN; use redox_scheme::{RequestKind, SignalBehavior, Socket}; use crate::scheme::FbbootlogScheme; @@ -18,41 +22,76 @@ fn main() { redox_daemon::Daemon::new(|daemon| inner(daemon)).expect("failed to create daemon"); } fn inner(daemon: redox_daemon::Daemon) -> ! { + let event_queue = EventQueue::new().expect("fbbootlogd: failed to create event queue"); + + event::user_data! { + enum Source { + Scheme, + Input, + } + } + let socket = - Socket::create("fbbootlog").expect("fbbootlogd: failed to create fbbootlog scheme"); + Socket::nonblock("fbbootlog").expect("fbbootlogd: failed to create fbbootlog scheme"); + + event_queue + .subscribe( + socket.inner().raw(), + Source::Scheme, + event::EventFlags::READ, + ) + .expect("fbcond: failed to subscribe to scheme events"); let mut scheme = FbbootlogScheme::new(); + event_queue + .subscribe( + scheme.display.input_handle.inner().as_raw_fd() as usize, + Source::Input, + event::EventFlags::READ, + ) + .expect("fbbootlogd: failed to subscribe to scheme events"); + // This is not possible for now as fbbootlogd needs to open new displays at runtime for graphics // driver handoff. In the future inputd may directly pass a handle to the display instead. //libredox::call::setrens(0, 0).expect("fbbootlogd: failed to enter null namespace"); daemon.ready().expect("failed to notify parent"); - loop { - let request = match socket - .next_request(SignalBehavior::Restart) - .expect("fbbootlogd: failed to read display scheme") - { - Some(request) => request, - None => { - // Scheme likely got unmounted - std::process::exit(0); - } - }; + for event in event_queue { + match event.expect("fbbootlogd: failed to get event").user_data { + 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!("fbbootlogd: failed to read display scheme: {err:?}"), + }; - match request.kind() { - RequestKind::Call(call) => { - let response = call.handle_scheme(&mut scheme); + match request.kind() { + RequestKind::Call(call) => { + let response = call.handle_scheme(&mut scheme); - socket - .write_responses(&[response], SignalBehavior::Restart) - .expect("pcid: failed to write next scheme response"); + socket + .write_responses(&[response], SignalBehavior::Restart) + .expect("pcid: failed to write next scheme response"); + } + RequestKind::OnClose { id } => { + scheme.on_close(id); + } + _ => (), + } + } } - RequestKind::OnClose { id } => { - scheme.on_close(id); + Source::Input => { + scheme.display.handle_input_events(); } - _ => (), } } + + std::process::exit(0); } diff --git a/graphics/fbbootlogd/src/scheme.rs b/graphics/fbbootlogd/src/scheme.rs index 9fa087f0fa..d4b21ef06c 100644 --- a/graphics/fbbootlogd/src/scheme.rs +++ b/graphics/fbbootlogd/src/scheme.rs @@ -6,7 +6,7 @@ use syscall::{Error, Result, EINVAL, ENOENT}; use crate::display::Display; pub struct FbbootlogScheme { - display: Display, + pub display: Display, text_screen: console_draw::TextScreen, } @@ -55,8 +55,7 @@ impl Scheme for FbbootlogScheme { } fn write(&mut self, _id: usize, buf: &[u8], _offset: u64, _fcntl_flags: u32) -> Result { - let mut map_guard = self.display.map.lock().unwrap(); - if let Some(map) = &mut *map_guard { + if let Some(map) = &mut self.display.map { let damage = self.text_screen.write( &mut console_draw::DisplayMap { offscreen: map.inner.ptr_mut(), @@ -66,7 +65,6 @@ impl Scheme for FbbootlogScheme { buf, &mut VecDeque::new(), ); - drop(map_guard); self.display.sync_rects(damage); } From b9d043f6e22903a2cdbe58ed96ed7cf946b3d13b Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 15 Mar 2025 17:07:22 +0100 Subject: [PATCH 3/7] inputd: Add ConsumerHandle::read_events --- graphics/fbbootlogd/src/display.rs | 40 +++++++--------------- graphics/fbbootlogd/src/main.rs | 2 +- graphics/fbcond/src/main.rs | 41 +++++++--------------- graphics/fbcond/src/scheme.rs | 2 +- inputd/src/lib.rs | 55 +++++++++++++++++++++++------- 5 files changed, 69 insertions(+), 71 deletions(-) diff --git a/graphics/fbbootlogd/src/display.rs b/graphics/fbbootlogd/src/display.rs index 430bff7c12..8ef8c1a558 100644 --- a/graphics/fbbootlogd/src/display.rs +++ b/graphics/fbbootlogd/src/display.rs @@ -1,24 +1,8 @@ -use graphics_ipc::v1::{Damage, V1GraphicsHandle}; -use inputd::ConsumerHandle; -use libredox::errno::ESTALE; -use orbclient::Event; -use std::mem; -use std::os::fd::BorrowedFd; -use std::os::unix::io::AsRawFd; -use std::{io, slice}; +use std::io; -fn read_to_slice( - file: BorrowedFd, - buf: &mut [T], -) -> Result { - unsafe { - libredox::call::read( - file.as_raw_fd() as usize, - slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut u8, buf.len() * mem::size_of::()), - ) - .map(|count| count / mem::size_of::()) - } -} +use graphics_ipc::v1::{Damage, V1GraphicsHandle}; +use inputd::{ConsumerHandle, ConsumerHandleEvent}; +use orbclient::Event; fn display_fd_map(display_handle: V1GraphicsHandle) -> io::Result { let display_map = display_handle.map_display()?; @@ -62,8 +46,14 @@ impl Display { pub fn handle_input_events(&mut self) { let mut events = [Event::new(); 16]; loop { - match read_to_slice(self.input_handle.inner(), &mut events) { - Err(err) if err.errno() == ESTALE => { + match self + .input_handle + .read_events(&mut events) + .expect("fbbootlogd: error while reading events") + { + ConsumerHandleEvent::Events(&[]) => break, + ConsumerHandleEvent::Events(_) => {} + ConsumerHandleEvent::Handoff => { eprintln!("fbbootlogd: handoff requested"); let new_display_handle = match self.input_handle.open_display() { @@ -85,12 +75,6 @@ impl Display { } } } - - Ok(0) => break, - Ok(_count) => {} - Err(err) => { - panic!("fbbootlogd: error while reading events: {err}"); - } } } } diff --git a/graphics/fbbootlogd/src/main.rs b/graphics/fbbootlogd/src/main.rs index 30e99c9ea0..6be03245cf 100644 --- a/graphics/fbbootlogd/src/main.rs +++ b/graphics/fbbootlogd/src/main.rs @@ -46,7 +46,7 @@ fn inner(daemon: redox_daemon::Daemon) -> ! { event_queue .subscribe( - scheme.display.input_handle.inner().as_raw_fd() as usize, + scheme.display.input_handle.event_handle().as_raw_fd() as usize, Source::Input, event::EventFlags::READ, ) diff --git a/graphics/fbcond/src/main.rs b/graphics/fbcond/src/main.rs index 6c4c5c2214..27f81244f4 100644 --- a/graphics/fbcond/src/main.rs +++ b/graphics/fbcond/src/main.rs @@ -1,9 +1,9 @@ use event::EventQueue; -use libredox::errno::{EAGAIN, EINTR, ESTALE}; +use inputd::ConsumerHandleEvent; +use libredox::errno::{EAGAIN, EINTR}; use orbclient::Event; use redox_scheme::{CallRequest, RequestKind, Response, SignalBehavior, Socket}; -use std::os::fd::{AsRawFd, BorrowedFd}; -use std::{env, mem, slice}; +use std::env; use syscall::EVENT_READ; use crate::scheme::{FbconScheme, VtIndex}; @@ -12,19 +12,6 @@ mod display; mod scheme; mod text; -fn read_to_slice( - file: BorrowedFd, - buf: &mut [T], -) -> Result { - unsafe { - libredox::call::read( - file.as_raw_fd() as usize, - slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut u8, buf.len() * mem::size_of::()), - ) - .map(|count| count / mem::size_of::()) - } -} - fn main() { let vt_ids = env::args() .skip(1) @@ -129,21 +116,19 @@ fn handle_event( let mut events = [Event::new(); 16]; loop { - match read_to_slice(vt.display.input_handle.inner(), &mut events) { - Ok(0) => break, - Err(err) if err.errno() == ESTALE => { - vt.handle_handoff(); - } - - Ok(count) => { - let events = &mut events[..count]; - for event in events.iter_mut() { + match vt + .display + .input_handle + .read_events(&mut events) + .expect("fbcond: Error while reading events") + { + ConsumerHandleEvent::Events(&[]) => break, + ConsumerHandleEvent::Events(events) => { + for event in events { vt.input(event) } } - Err(err) => { - panic!("fbcond: Error while reading events: {err}"); - } + ConsumerHandleEvent::Handoff => vt.handle_handoff(), } } } diff --git a/graphics/fbcond/src/scheme.rs b/graphics/fbcond/src/scheme.rs index dd4c957e01..b8393c7b23 100644 --- a/graphics/fbcond/src/scheme.rs +++ b/graphics/fbcond/src/scheme.rs @@ -46,7 +46,7 @@ impl FbconScheme { let display = Display::open_vt(vt_i).expect("Failed to open display for vt"); event_queue .subscribe( - display.input_handle.inner().as_raw_fd() as usize, + display.input_handle.event_handle().as_raw_fd() as usize, VtIndex(vt_i), event::EventFlags::READ, ) diff --git a/inputd/src/lib.rs b/inputd/src/lib.rs index b7ca196db6..0a2559beb9 100644 --- a/inputd/src/lib.rs +++ b/inputd/src/lib.rs @@ -1,23 +1,44 @@ use std::fs::{File, OpenOptions}; -use std::io::{Error, Read, Write}; +use std::io::{self, Read, Write}; use std::mem::size_of; use std::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, RawFd}; use std::os::unix::fs::OpenOptionsExt; +use std::slice; use libredox::flag::{O_CLOEXEC, O_NONBLOCK, O_RDWR}; +use orbclient::Event; +use syscall::ESTALE; + +fn read_to_slice( + file: BorrowedFd, + buf: &mut [T], +) -> Result { + unsafe { + libredox::call::read( + file.as_raw_fd() as usize, + slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut u8, buf.len() * size_of::()), + ) + .map(|count| count / size_of::()) + } +} unsafe fn any_as_u8_slice(p: &T) -> &[u8] { - std::slice::from_raw_parts((p as *const T) as *const u8, size_of::()) + 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::()) + slice::from_raw_parts_mut((p as *mut T) as *mut u8, size_of::()) } pub struct ConsumerHandle(File); +pub enum ConsumerHandleEvent<'a> { + Events(&'a [Event]), + Handoff, +} + impl ConsumerHandle { - pub fn new_vt() -> Result { + pub fn new_vt() -> io::Result { let file = OpenOptions::new() .read(true) .custom_flags(O_NONBLOCK as i32) @@ -25,11 +46,11 @@ impl ConsumerHandle { Ok(Self(file)) } - pub fn inner(&self) -> BorrowedFd<'_> { + pub fn event_handle(&self) -> BorrowedFd<'_> { self.0.as_fd() } - pub fn open_display(&self) -> Result { + pub fn open_display(&self) -> io::Result { let mut buffer = [0; 1024]; let fd = self.0.as_raw_fd(); let written = libredox::call::fpath(fd as usize, &mut buffer)?; @@ -49,6 +70,14 @@ impl ConsumerHandle { Ok(display_file) } + + pub fn read_events<'a>(&self, events: &'a mut [Event]) -> io::Result> { + match read_to_slice(self.0.as_fd(), events) { + Ok(count) => Ok(ConsumerHandleEvent::Events(&events[..count])), + Err(err) if err.errno() == ESTALE => Ok(ConsumerHandleEvent::Handoff), + Err(err) => Err(err.into()), + } + } } #[derive(Debug, Clone)] @@ -60,17 +89,17 @@ pub struct VtActivate { pub struct DisplayHandle(File); impl DisplayHandle { - pub fn new>(device_name: S) -> Result { + pub fn new>(device_name: S) -> io::Result { let path = format!("/scheme/input/handle/display/{}", device_name.into()); Ok(Self(File::open(path)?)) } - pub fn new_early>(device_name: S) -> Result { + pub fn new_early>(device_name: S) -> io::Result { let path = format!("/scheme/input/handle_early/display/{}", device_name.into()); Ok(Self(File::open(path)?)) } - pub fn read_vt_event(&mut self) -> Result, Error> { + pub fn read_vt_event(&mut self) -> io::Result> { let mut event = VtEvent { kind: VtEventKind::Resize, vt: usize::MAX, @@ -97,12 +126,12 @@ impl DisplayHandle { pub struct ControlHandle(File); impl ControlHandle { - pub fn new() -> Result { + pub fn new() -> io::Result { let path = format!("/scheme/input/control"); Ok(Self(File::open(path)?)) } - pub fn activate_vt(&mut self, vt: usize) -> Result { + pub fn activate_vt(&mut self, vt: usize) -> io::Result { let cmd = VtActivate { vt }; self.0.write(unsafe { any_as_u8_slice(&cmd) }) } @@ -129,11 +158,11 @@ pub struct VtEvent { pub struct ProducerHandle(File); impl ProducerHandle { - pub fn new() -> Result { + pub fn new() -> io::Result { File::open("/scheme/input/producer").map(ProducerHandle) } - pub fn write_event(&mut self, event: orbclient::Event) -> Result<(), Error> { + pub fn write_event(&mut self, event: orbclient::Event) -> io::Result<()> { self.0.write(&event)?; Ok(()) } From 9290cffa70305e60960b85e8c49aa0dc1795f1e1 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 15 Mar 2025 17:18:28 +0100 Subject: [PATCH 4/7] graphics/fbbootlogd: Extract handle_handoff method --- graphics/fbbootlogd/src/display.rs | 49 +++++++++++------------------- graphics/fbbootlogd/src/main.rs | 18 ++++++++++- 2 files changed, 34 insertions(+), 33 deletions(-) diff --git a/graphics/fbbootlogd/src/display.rs b/graphics/fbbootlogd/src/display.rs index 8ef8c1a558..4de0db6859 100644 --- a/graphics/fbbootlogd/src/display.rs +++ b/graphics/fbbootlogd/src/display.rs @@ -1,8 +1,7 @@ use std::io; use graphics_ipc::v1::{Damage, V1GraphicsHandle}; -use inputd::{ConsumerHandle, ConsumerHandleEvent}; -use orbclient::Event; +use inputd::ConsumerHandle; fn display_fd_map(display_handle: V1GraphicsHandle) -> io::Result { let display_map = display_handle.map_display()?; @@ -43,38 +42,24 @@ impl Display { Ok(Self { input_handle, map }) } - pub fn handle_input_events(&mut self) { - let mut events = [Event::new(); 16]; - loop { - match self - .input_handle - .read_events(&mut events) - .expect("fbbootlogd: error while reading events") - { - ConsumerHandleEvent::Events(&[]) => break, - ConsumerHandleEvent::Events(_) => {} - ConsumerHandleEvent::Handoff => { - eprintln!("fbbootlogd: handoff requested"); + pub fn handle_handoff(&mut self) { + eprintln!("fbbootlogd: handoff requested"); + let new_display_handle = match self.input_handle.open_display() { + Ok(display) => V1GraphicsHandle::from_file(display).unwrap(), + Err(err) => { + println!("fbbootlogd: No display present yet: {err}"); + return; + } + }; - let new_display_handle = match self.input_handle.open_display() { - Ok(display) => V1GraphicsHandle::from_file(display).unwrap(), - Err(err) => { - println!("fbbootlogd: No display present yet: {err}"); - continue; - } - }; + match display_fd_map(new_display_handle) { + Ok(ok) => { + self.map = Some(ok); - match display_fd_map(new_display_handle) { - Ok(ok) => { - self.map = Some(ok); - - eprintln!("fbbootlogd: handoff finished"); - } - Err(err) => { - eprintln!("fbbootlogd: failed to open display: {}", err); - } - } - } + eprintln!("fbbootlogd: handoff finished"); + } + Err(err) => { + eprintln!("fbbootlogd: failed to open display: {}", err); } } } diff --git a/graphics/fbbootlogd/src/main.rs b/graphics/fbbootlogd/src/main.rs index 6be03245cf..d06faf9170 100644 --- a/graphics/fbbootlogd/src/main.rs +++ b/graphics/fbbootlogd/src/main.rs @@ -10,7 +10,9 @@ use std::os::fd::AsRawFd; use event::EventQueue; +use inputd::ConsumerHandleEvent; use libredox::errno::EAGAIN; +use orbclient::Event; use redox_scheme::{RequestKind, SignalBehavior, Socket}; use crate::scheme::FbbootlogScheme; @@ -88,7 +90,21 @@ fn inner(daemon: redox_daemon::Daemon) -> ! { } } Source::Input => { - scheme.display.handle_input_events(); + let mut events = [Event::new(); 16]; + loop { + match scheme + .display + .input_handle + .read_events(&mut events) + .expect("fbbootlogd: error while reading events") + { + ConsumerHandleEvent::Events(&[]) => break, + ConsumerHandleEvent::Events(_) => {} + ConsumerHandleEvent::Handoff => { + scheme.display.handle_handoff(); + } + } + } } } } From 54113f8fde8daf482d791a1e3a3266e251a8642b Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 15 Mar 2025 17:21:23 +0100 Subject: [PATCH 5/7] graphics/fbbootlogd: Make it robust against initial graphics driver being broken --- graphics/fbbootlogd/src/display.rs | 26 ++++++++------------------ graphics/fbbootlogd/src/main.rs | 1 + 2 files changed, 9 insertions(+), 18 deletions(-) diff --git a/graphics/fbbootlogd/src/display.rs b/graphics/fbbootlogd/src/display.rs index 4de0db6859..f08dba2d5c 100644 --- a/graphics/fbbootlogd/src/display.rs +++ b/graphics/fbbootlogd/src/display.rs @@ -23,31 +23,21 @@ pub struct Display { impl Display { pub fn open_first_vt() -> io::Result { - let input_handle = ConsumerHandle::new_vt()?; - - let map = match input_handle.open_display() { - Ok(display) => { - let display_handle = V1GraphicsHandle::from_file(display)?; - Some( - display_fd_map(display_handle) - .unwrap_or_else(|e| panic!("failed to map display: {e}")), - ) - } - Err(err) => { - println!("fbbootlogd: No display present yet: {err}"); - None - } + let mut display = Self { + input_handle: ConsumerHandle::new_vt()?, + map: None, }; - Ok(Self { input_handle, map }) + display.handle_handoff(); + + Ok(display) } pub fn handle_handoff(&mut self) { - eprintln!("fbbootlogd: handoff requested"); let new_display_handle = match self.input_handle.open_display() { Ok(display) => V1GraphicsHandle::from_file(display).unwrap(), Err(err) => { - println!("fbbootlogd: No display present yet: {err}"); + eprintln!("fbbootlogd: No display present yet: {err}"); return; } }; @@ -56,7 +46,7 @@ impl Display { Ok(ok) => { self.map = Some(ok); - eprintln!("fbbootlogd: handoff finished"); + eprintln!("fbbootlogd: mapped display"); } Err(err) => { eprintln!("fbbootlogd: failed to open display: {}", err); diff --git a/graphics/fbbootlogd/src/main.rs b/graphics/fbbootlogd/src/main.rs index d06faf9170..05bf921685 100644 --- a/graphics/fbbootlogd/src/main.rs +++ b/graphics/fbbootlogd/src/main.rs @@ -101,6 +101,7 @@ fn inner(daemon: redox_daemon::Daemon) -> ! { ConsumerHandleEvent::Events(&[]) => break, ConsumerHandleEvent::Events(_) => {} ConsumerHandleEvent::Handoff => { + eprintln!("fbbootlogd: handoff requested"); scheme.display.handle_handoff(); } } From 87d71bc70802375e9d88547b096d4558e89561ea Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 15 Mar 2025 17:27:08 +0100 Subject: [PATCH 6/7] graphics/fbbootlogd: Merge Display into FbbbootlogScheme --- graphics/fbbootlogd/src/display.rs | 62 ------------------------------ graphics/fbbootlogd/src/main.rs | 6 +-- graphics/fbbootlogd/src/scheme.rs | 49 ++++++++++++++++++++--- 3 files changed, 45 insertions(+), 72 deletions(-) delete mode 100644 graphics/fbbootlogd/src/display.rs diff --git a/graphics/fbbootlogd/src/display.rs b/graphics/fbbootlogd/src/display.rs deleted file mode 100644 index f08dba2d5c..0000000000 --- a/graphics/fbbootlogd/src/display.rs +++ /dev/null @@ -1,62 +0,0 @@ -use std::io; - -use graphics_ipc::v1::{Damage, V1GraphicsHandle}; -use inputd::ConsumerHandle; - -fn display_fd_map(display_handle: V1GraphicsHandle) -> io::Result { - let display_map = display_handle.map_display()?; - Ok(DisplayMap { - display_handle, - inner: display_map, - }) -} - -pub struct DisplayMap { - display_handle: V1GraphicsHandle, - pub inner: graphics_ipc::v1::DisplayMap, -} - -pub struct Display { - pub input_handle: ConsumerHandle, - pub map: Option, -} - -impl Display { - pub fn open_first_vt() -> io::Result { - let mut display = Self { - input_handle: ConsumerHandle::new_vt()?, - map: None, - }; - - display.handle_handoff(); - - Ok(display) - } - - pub fn handle_handoff(&mut self) { - let new_display_handle = match self.input_handle.open_display() { - Ok(display) => V1GraphicsHandle::from_file(display).unwrap(), - Err(err) => { - eprintln!("fbbootlogd: No display present yet: {err}"); - return; - } - }; - - match display_fd_map(new_display_handle) { - Ok(ok) => { - self.map = Some(ok); - - eprintln!("fbbootlogd: mapped display"); - } - Err(err) => { - eprintln!("fbbootlogd: failed to open display: {}", err); - } - } - } - - pub fn sync_rects(&mut self, sync_rects: Vec) { - if let Some(map) = &self.map { - map.display_handle.sync_rects(&sync_rects).unwrap(); - } - } -} diff --git a/graphics/fbbootlogd/src/main.rs b/graphics/fbbootlogd/src/main.rs index 05bf921685..3de5509c2f 100644 --- a/graphics/fbbootlogd/src/main.rs +++ b/graphics/fbbootlogd/src/main.rs @@ -17,7 +17,6 @@ use redox_scheme::{RequestKind, SignalBehavior, Socket}; use crate::scheme::FbbootlogScheme; -mod display; mod scheme; fn main() { @@ -48,7 +47,7 @@ fn inner(daemon: redox_daemon::Daemon) -> ! { event_queue .subscribe( - scheme.display.input_handle.event_handle().as_raw_fd() as usize, + scheme.input_handle.event_handle().as_raw_fd() as usize, Source::Input, event::EventFlags::READ, ) @@ -93,7 +92,6 @@ fn inner(daemon: redox_daemon::Daemon) -> ! { let mut events = [Event::new(); 16]; loop { match scheme - .display .input_handle .read_events(&mut events) .expect("fbbootlogd: error while reading events") @@ -102,7 +100,7 @@ fn inner(daemon: redox_daemon::Daemon) -> ! { ConsumerHandleEvent::Events(_) => {} ConsumerHandleEvent::Handoff => { eprintln!("fbbootlogd: handoff requested"); - scheme.display.handle_handoff(); + scheme.handle_handoff(); } } } diff --git a/graphics/fbbootlogd/src/scheme.rs b/graphics/fbbootlogd/src/scheme.rs index d4b21ef06c..3b66ae5dca 100644 --- a/graphics/fbbootlogd/src/scheme.rs +++ b/graphics/fbbootlogd/src/scheme.rs @@ -1,20 +1,55 @@ use std::collections::VecDeque; +use graphics_ipc::v1::V1GraphicsHandle; +use inputd::ConsumerHandle; use redox_scheme::Scheme; use syscall::{Error, Result, EINVAL, ENOENT}; -use crate::display::Display; +pub struct DisplayMap { + display_handle: V1GraphicsHandle, + inner: graphics_ipc::v1::DisplayMap, +} pub struct FbbootlogScheme { - pub display: Display, + pub input_handle: ConsumerHandle, + display_map: Option, text_screen: console_draw::TextScreen, } impl FbbootlogScheme { pub fn new() -> FbbootlogScheme { - FbbootlogScheme { - display: Display::open_first_vt().expect("Failed to open display for vt"), + let mut scheme = FbbootlogScheme { + input_handle: ConsumerHandle::new_vt().expect("fbbootlogd: Failed to open vt"), + display_map: None, text_screen: console_draw::TextScreen::new(), + }; + + scheme.handle_handoff(); + + scheme + } + + pub fn handle_handoff(&mut self) { + let new_display_handle = match self.input_handle.open_display() { + Ok(display) => V1GraphicsHandle::from_file(display).unwrap(), + Err(err) => { + eprintln!("fbbootlogd: No display present yet: {err}"); + return; + } + }; + + match new_display_handle.map_display() { + Ok(display_map) => { + self.display_map = Some(DisplayMap { + display_handle: new_display_handle, + inner: display_map, + }); + + eprintln!("fbbootlogd: mapped display"); + } + Err(err) => { + eprintln!("fbbootlogd: failed to open display: {}", err); + } } } } @@ -55,7 +90,7 @@ impl Scheme for FbbootlogScheme { } fn write(&mut self, _id: usize, buf: &[u8], _offset: u64, _fcntl_flags: u32) -> Result { - if let Some(map) = &mut self.display.map { + if let Some(map) = &mut self.display_map { let damage = self.text_screen.write( &mut console_draw::DisplayMap { offscreen: map.inner.ptr_mut(), @@ -66,7 +101,9 @@ impl Scheme for FbbootlogScheme { &mut VecDeque::new(), ); - self.display.sync_rects(damage); + if let Some(map) = &self.display_map { + map.display_handle.sync_rects(&damage).unwrap(); + } } Ok(buf.len()) From ffbfecbdb0843dc3a88a7f081e1dc84ac48eeb7b Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 15 Mar 2025 17:30:39 +0100 Subject: [PATCH 7/7] graphics/fbcond: Make it robust against initial graphics driver being broken --- graphics/fbcond/src/display.rs | 28 +++++++--------------------- graphics/fbcond/src/scheme.rs | 2 +- graphics/fbcond/src/text.rs | 1 + 3 files changed, 9 insertions(+), 22 deletions(-) diff --git a/graphics/fbcond/src/display.rs b/graphics/fbcond/src/display.rs index 45ee86d2ca..60d7a18218 100644 --- a/graphics/fbcond/src/display.rs +++ b/graphics/fbcond/src/display.rs @@ -13,33 +13,19 @@ pub struct DisplayMap { } impl Display { - pub fn open_vt(vt: usize) -> io::Result { - let input_handle = ConsumerHandle::new_vt()?; + pub fn open_new_vt() -> io::Result { + let mut display = Self { + input_handle: ConsumerHandle::new_vt()?, + map: None, + }; - if let Ok(display_handle) = Self::open_display(&input_handle) { - let map = display_handle - .map_display() - .unwrap_or_else(|e| panic!("failed to map display for VT #{vt}: {e}")); + display.reopen_for_handoff(); - Ok(Self { - input_handle, - map: Some(DisplayMap { - display_handle, - inner: map, - }), - }) - } else { - Ok(Self { - input_handle, - map: None, - }) - } + Ok(display) } /// Re-open the display after a handoff. pub fn reopen_for_handoff(&mut self) { - eprintln!("fbcond: Performing handoff"); - let new_display_handle = Self::open_display(&self.input_handle).unwrap(); eprintln!("fbcond: Opened new display"); diff --git a/graphics/fbcond/src/scheme.rs b/graphics/fbcond/src/scheme.rs index b8393c7b23..76c17ff210 100644 --- a/graphics/fbcond/src/scheme.rs +++ b/graphics/fbcond/src/scheme.rs @@ -43,7 +43,7 @@ impl FbconScheme { let mut vts = BTreeMap::new(); for &vt_i in vt_ids { - let display = Display::open_vt(vt_i).expect("Failed to open display for vt"); + let display = Display::open_new_vt().expect("Failed to open display for vt"); event_queue .subscribe( display.input_handle.event_handle().as_raw_fd() as usize, diff --git a/graphics/fbcond/src/text.rs b/graphics/fbcond/src/text.rs index 3499316da2..11d4c7ca19 100644 --- a/graphics/fbcond/src/text.rs +++ b/graphics/fbcond/src/text.rs @@ -23,6 +23,7 @@ impl TextScreen { } pub fn handle_handoff(&mut self) { + eprintln!("fbcond: Performing handoff"); self.display.reopen_for_handoff(); }