graphics/fbcond: Move blocking operations back to the main thread

With fbbootlogd split out it is no longer essential to avoid blocking
operations on the main thread of fbcond. Moving them back to the main
thread simplifies things a fair bit.
This commit is contained in:
bjorn3
2024-12-24 21:39:31 +01:00
parent 4e2f1a730c
commit 12fc959737
2 changed files with 63 additions and 115 deletions
+60 -110
View File
@@ -1,15 +1,14 @@
use inputd::{ConsumerHandle, Damage};
use libredox::flag;
use std::mem;
use std::sync::mpsc::{self, Sender};
use std::sync::{Arc, Mutex};
use std::{fs::File, io, os::unix::io::AsRawFd, slice};
use std::fs::File;
use std::os::unix::io::AsRawFd;
use std::{io, mem, ptr, slice};
fn display_fd_map(
width: usize,
height: usize,
display_file: &mut File,
) -> syscall::Result<DisplayMap> {
) -> syscall::Result<*mut [u32]> {
unsafe {
let display_ptr = libredox::call::mmap(libredox::call::MmapArgs {
fd: display_file.as_raw_fd() as usize,
@@ -19,12 +18,10 @@ fn display_fd_map(
flags: flag::MAP_SHARED,
addr: core::ptr::null_mut(),
})?;
let display_slice = slice::from_raw_parts_mut(display_ptr as *mut u32, width * height);
Ok(DisplayMap {
offscreen: display_slice,
width,
height,
})
Ok(ptr::slice_from_raw_parts_mut(
display_ptr as *mut u32,
width * height,
))
}
}
@@ -32,118 +29,51 @@ unsafe fn display_fd_unmap(image: *mut [u32]) {
let _ = libredox::call::munmap(image as *mut (), image.len());
}
pub struct DisplayMap {
pub struct Display {
pub input_handle: ConsumerHandle,
pub display_file: File,
pub offscreen: *mut [u32],
pub width: usize,
pub height: usize,
}
unsafe impl Send for DisplayMap {}
unsafe impl Sync for DisplayMap {}
impl Drop for DisplayMap {
fn drop(&mut self) {
unsafe {
display_fd_unmap(self.offscreen);
}
}
}
enum DisplayCommand {
Resize { width: usize, height: usize },
ReopenForHandoff,
SyncRects(Vec<Damage>),
}
pub struct Display {
pub input_handle: Arc<ConsumerHandle>,
cmd_tx: Sender<DisplayCommand>,
pub map: Arc<Mutex<DisplayMap>>,
}
impl Display {
pub fn open_vt(vt: usize) -> io::Result<Self> {
let input_handle = Arc::new(ConsumerHandle::for_vt(vt)?);
let input_handle = ConsumerHandle::for_vt(vt)?;
let (mut display_file, width, height) = Self::open_display(&input_handle)?;
let map = Arc::new(Mutex::new(
display_fd_map(width, height, &mut display_file)
.unwrap_or_else(|e| panic!("failed to map display for VT #{vt}: {e}")),
));
let (cmd_tx, cmd_rx) = mpsc::channel();
let input_handle_clone = input_handle.clone();
let map_clone = map.clone();
std::thread::spawn(move || {
while let Ok(cmd) = cmd_rx.recv() {
match cmd {
DisplayCommand::Resize { width, height } => {
match display_fd_map(width, height, &mut display_file) {
Ok(ok) => {
*map_clone.lock().unwrap() = ok;
}
Err(err) => {
eprintln!(
"failed to resize display to {}x{}: {}",
width, height, err
);
}
}
}
DisplayCommand::ReopenForHandoff => {
eprintln!("fbcond: Performing handoff");
let (mut new_display_file, width, height) =
Self::open_display(&input_handle_clone).unwrap();
eprintln!("fbcond: Opened new display for VT #{vt}");
match display_fd_map(width, height, &mut new_display_file) {
Ok(ok) => {
*map_clone.lock().unwrap() = ok;
display_file = new_display_file;
eprintln!("fbcond: Mapped new display for VT #{vt}");
}
Err(err) => {
eprintln!(
"failed to resize display to {}x{}: {}",
width, height, err
);
}
}
}
DisplayCommand::SyncRects(sync_rects) => unsafe {
libredox::call::write(
display_file.as_raw_fd() as usize,
slice::from_raw_parts(
sync_rects.as_ptr() as *const u8,
sync_rects.len() * mem::size_of::<Damage>(),
),
)
.unwrap();
},
}
}
});
let offscreen = display_fd_map(width, height, &mut display_file)
.unwrap_or_else(|e| panic!("failed to map display for VT #{vt}: {e}"));
Ok(Self {
input_handle,
cmd_tx,
map,
display_file,
offscreen,
width,
height,
})
}
/// Re-open the display after a handoff.
///
/// Once re-opening is finished, you must call [`resize`] to map the new framebuffer.
///
/// Warning: This must be called in a background thread to avoid a deadlock when the
/// graphics driver (indirectly) writes logs to fbcond.
pub fn reopen_for_handoff(&mut self) {
self.cmd_tx.send(DisplayCommand::ReopenForHandoff).unwrap();
eprintln!("fbcond: Performing handoff");
let (mut new_display_file, width, height) = Self::open_display(&self.input_handle).unwrap();
eprintln!("fbcond: Opened new display");
match display_fd_map(width, height, &mut new_display_file) {
Ok(offscreen) => {
self.offscreen = offscreen;
self.display_file = new_display_file;
eprintln!("fbcond: Mapped new display");
}
Err(err) => {
eprintln!("failed to resize display to {}x{}: {}", width, height, err);
}
}
}
fn open_display(input_handle: &ConsumerHandle) -> io::Result<(File, usize, usize)> {
@@ -175,14 +105,34 @@ impl Display {
}
pub fn resize(&mut self, width: usize, height: usize) {
self.cmd_tx
.send(DisplayCommand::Resize { width, height })
.unwrap();
match display_fd_map(width, height, &mut self.display_file) {
Ok(offscreen) => {
self.offscreen = offscreen;
}
Err(err) => {
eprintln!("failed to resize display to {}x{}: {}", width, height, err);
}
}
}
pub fn sync_rects(&mut self, sync_rects: Vec<Damage>) {
self.cmd_tx
.send(DisplayCommand::SyncRects(sync_rects))
unsafe {
libredox::call::write(
self.display_file.as_raw_fd() as usize,
slice::from_raw_parts(
sync_rects.as_ptr() as *const u8,
sync_rects.len() * mem::size_of::<Damage>(),
),
)
.unwrap();
}
}
}
impl Drop for Display {
fn drop(&mut self) {
unsafe {
display_fd_unmap(self.offscreen);
}
}
}
+3 -5
View File
@@ -128,17 +128,15 @@ impl TextScreen {
}
pub fn write(&mut self, buf: &[u8]) -> Result<usize> {
let map = self.display.map.lock().unwrap();
let damage = self.inner.write(
&mut console_draw::DisplayMap {
offscreen: map.offscreen,
width: map.width,
height: map.height,
offscreen: self.display.offscreen,
width: self.display.width,
height: self.display.height,
},
buf,
&mut self.input,
);
drop(map);
self.display.sync_rects(damage);