fbcond: Make sure we never block on the graphics driver
To prevent deadlocks if the graphics driver in turn tries to write to fbcond for log messages.
This commit is contained in:
@@ -3,6 +3,8 @@ use libredox::flag;
|
||||
use std::fs::OpenOptions;
|
||||
use std::mem;
|
||||
use std::os::unix::fs::OpenOptionsExt;
|
||||
use std::sync::mpsc::{self, Sender};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::{
|
||||
fs::File,
|
||||
io,
|
||||
@@ -12,10 +14,14 @@ use std::{
|
||||
};
|
||||
use syscall::{O_CLOEXEC, O_NONBLOCK, O_RDWR};
|
||||
|
||||
fn display_fd_map(width: usize, height: usize, display_fd: usize) -> syscall::Result<*mut [u32]> {
|
||||
fn display_fd_map(
|
||||
width: usize,
|
||||
height: usize,
|
||||
display_file: &mut File,
|
||||
) -> syscall::Result<DisplayMap> {
|
||||
unsafe {
|
||||
let display_ptr = libredox::call::mmap(libredox::call::MmapArgs {
|
||||
fd: display_fd,
|
||||
fd: display_file.as_raw_fd() as usize,
|
||||
offset: 0,
|
||||
length: (width * height * 4),
|
||||
prot: flag::PROT_READ | flag::PROT_WRITE,
|
||||
@@ -23,7 +29,11 @@ fn display_fd_map(width: usize, height: usize, display_fd: usize) -> syscall::Re
|
||||
addr: core::ptr::null_mut(),
|
||||
})?;
|
||||
let display_slice = slice::from_raw_parts_mut(display_ptr as *mut u32, width * height);
|
||||
Ok(display_slice)
|
||||
Ok(DisplayMap {
|
||||
offscreen: display_slice,
|
||||
width,
|
||||
height,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,14 +41,34 @@ unsafe fn display_fd_unmap(image: *mut [u32]) {
|
||||
let _ = libredox::call::munmap(image as *mut (), image.len());
|
||||
}
|
||||
|
||||
pub struct Display {
|
||||
pub input_handle: File,
|
||||
pub display_file: File,
|
||||
pub struct DisplayMap {
|
||||
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 },
|
||||
SyncRects(Vec<Damage>),
|
||||
}
|
||||
|
||||
pub struct Display {
|
||||
pub input_handle: File,
|
||||
cmd_tx: Sender<DisplayCommand>,
|
||||
pub map: Arc<Mutex<DisplayMap>>,
|
||||
}
|
||||
|
||||
impl Display {
|
||||
pub fn open_vt(vt: usize) -> io::Result<Self> {
|
||||
let mut input_handle = OpenOptions::new()
|
||||
@@ -48,16 +78,55 @@ impl Display {
|
||||
|
||||
let display_path = Self::display_path(&mut input_handle)?;
|
||||
|
||||
let (display_file, width, height) = Self::open_display(&display_path)?;
|
||||
let (mut display_file, width, height) = Self::open_display(&display_path)?;
|
||||
|
||||
let map = Arc::new(Mutex::new(
|
||||
display_fd_map(width, height, &mut display_file)
|
||||
.unwrap_or_else(|e| panic!("failed to map display '{display_path}: {e}")),
|
||||
));
|
||||
|
||||
let (cmd_tx, cmd_rx) = mpsc::channel();
|
||||
|
||||
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::SyncRects(sync_rects) => {
|
||||
for sync_rect in sync_rects {
|
||||
unsafe {
|
||||
libredox::call::write(
|
||||
display_file.as_raw_fd() as usize,
|
||||
slice::from_raw_parts(
|
||||
&sync_rect as *const Damage as *const u8,
|
||||
mem::size_of::<Damage>(),
|
||||
),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
libredox::call::fsync(display_file.as_raw_fd() as usize).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let offscreen_buffer = display_fd_map(width, height, display_file.as_raw_fd() as usize)
|
||||
.unwrap_or_else(|e| panic!("failed to map display '{display_path}: {e}"));
|
||||
Ok(Self {
|
||||
input_handle,
|
||||
display_file,
|
||||
offscreen: offscreen_buffer,
|
||||
width,
|
||||
height,
|
||||
cmd_tx,
|
||||
map,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -122,39 +191,14 @@ impl Display {
|
||||
}
|
||||
|
||||
pub fn resize(&mut self, width: usize, height: usize) {
|
||||
match display_fd_map(width, height, self.display_file.as_raw_fd() as usize) {
|
||||
Ok(ok) => {
|
||||
unsafe {
|
||||
display_fd_unmap(self.offscreen);
|
||||
}
|
||||
self.offscreen = ok;
|
||||
self.width = width;
|
||||
self.height = height;
|
||||
}
|
||||
Err(err) => {
|
||||
eprintln!("failed to resize display to {}x{}: {}", width, height, err);
|
||||
}
|
||||
}
|
||||
self.cmd_tx
|
||||
.send(DisplayCommand::Resize { width, height })
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
pub fn sync_rect(&mut self, sync_rect: Damage) -> syscall::Result<()> {
|
||||
unsafe {
|
||||
libredox::call::write(
|
||||
self.display_file.as_raw_fd().as_raw_fd() as usize,
|
||||
slice::from_raw_parts(
|
||||
&sync_rect as *const Damage as *const u8,
|
||||
mem::size_of::<Damage>(),
|
||||
),
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Display {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
display_fd_unmap(self.offscreen);
|
||||
}
|
||||
pub fn sync_rects(&mut self, sync_rects: Vec<Damage>) {
|
||||
self.cmd_tx
|
||||
.send(DisplayCommand::SyncRects(sync_rects))
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
+43
-40
@@ -2,14 +2,13 @@ extern crate ransid;
|
||||
|
||||
use std::collections::{BTreeSet, VecDeque};
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use std::os::fd::AsRawFd;
|
||||
use std::{cmp, ptr};
|
||||
|
||||
use inputd::Damage;
|
||||
use orbclient::{Event, EventOption, FONT};
|
||||
use syscall::error::*;
|
||||
|
||||
use crate::display::Display;
|
||||
use crate::display::{Display, DisplayMap};
|
||||
|
||||
pub struct TextScreen {
|
||||
console: ransid::Console,
|
||||
@@ -32,16 +31,16 @@ impl TextScreen {
|
||||
}
|
||||
|
||||
/// Draw a rectangle
|
||||
fn rect(display: &mut Display, x: usize, y: usize, w: usize, h: usize, color: u32) {
|
||||
let start_y = cmp::min(display.height, y);
|
||||
let end_y = cmp::min(display.height, y + h);
|
||||
fn rect(map: &mut DisplayMap, x: usize, y: usize, w: usize, h: usize, color: u32) {
|
||||
let start_y = cmp::min(map.height, y);
|
||||
let end_y = cmp::min(map.height, y + h);
|
||||
|
||||
let start_x = cmp::min(display.width, x);
|
||||
let len = cmp::min(display.width, x + w) - start_x;
|
||||
let start_x = cmp::min(map.width, x);
|
||||
let len = cmp::min(map.width, x + w) - start_x;
|
||||
|
||||
let mut offscreen_ptr = display.offscreen as *mut u8 as usize;
|
||||
let mut offscreen_ptr = map.offscreen as *mut u8 as usize;
|
||||
|
||||
let stride = display.width * 4;
|
||||
let stride = map.width * 4;
|
||||
|
||||
let offset = y * stride + start_x * 4;
|
||||
offscreen_ptr += offset;
|
||||
@@ -59,16 +58,16 @@ impl TextScreen {
|
||||
}
|
||||
|
||||
/// Invert a rectangle
|
||||
fn invert(display: &mut Display, x: usize, y: usize, w: usize, h: usize) {
|
||||
let start_y = cmp::min(display.height, y);
|
||||
let end_y = cmp::min(display.height, y + h);
|
||||
fn invert(map: &mut DisplayMap, x: usize, y: usize, w: usize, h: usize) {
|
||||
let start_y = cmp::min(map.height, y);
|
||||
let end_y = cmp::min(map.height, y + h);
|
||||
|
||||
let start_x = cmp::min(display.width, x);
|
||||
let len = cmp::min(display.width, x + w) - start_x;
|
||||
let start_x = cmp::min(map.width, x);
|
||||
let len = cmp::min(map.width, x + w) - start_x;
|
||||
|
||||
let mut offscreen_ptr = display.offscreen as *mut u8 as usize;
|
||||
let mut offscreen_ptr = map.offscreen as *mut u8 as usize;
|
||||
|
||||
let stride = display.width * 4;
|
||||
let stride = map.width * 4;
|
||||
|
||||
let offset = y * stride + start_x * 4;
|
||||
offscreen_ptr += offset;
|
||||
@@ -92,7 +91,7 @@ impl TextScreen {
|
||||
|
||||
/// Draw a character
|
||||
fn char(
|
||||
display: &mut Display,
|
||||
map: &mut DisplayMap,
|
||||
x: usize,
|
||||
y: usize,
|
||||
character: char,
|
||||
@@ -100,8 +99,8 @@ impl TextScreen {
|
||||
_bold: bool,
|
||||
_italic: bool,
|
||||
) {
|
||||
if x + 8 <= display.width && y + 16 <= display.height {
|
||||
let mut dst = display.offscreen as *mut u8 as usize + (y * display.width + x) * 4;
|
||||
if x + 8 <= map.width && y + 16 <= map.height {
|
||||
let mut dst = map.offscreen as *mut u8 as usize + (y * map.width + x) * 4;
|
||||
|
||||
let font_i = 16 * (character as usize);
|
||||
if font_i + 16 <= FONT.len() {
|
||||
@@ -114,7 +113,7 @@ impl TextScreen {
|
||||
}
|
||||
}
|
||||
}
|
||||
dst += display.width * 4;
|
||||
dst += map.width * 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -223,9 +222,11 @@ impl TextScreen {
|
||||
}
|
||||
|
||||
pub fn write(&mut self, buf: &[u8]) -> Result<usize> {
|
||||
self.console.state.w = self.display.width / 8;
|
||||
self.console.state.h = self.display.height / 16;
|
||||
self.console.state.bottom_margin = (self.display.height / 16).saturating_sub(1);
|
||||
let mut map = self.display.map.lock().unwrap();
|
||||
|
||||
self.console.state.w = map.width / 8;
|
||||
self.console.state.h = map.height / 16;
|
||||
self.console.state.bottom_margin = (map.height / 16).saturating_sub(1);
|
||||
|
||||
if self.console.state.cursor
|
||||
&& self.console.state.x < self.console.state.w
|
||||
@@ -233,12 +234,11 @@ impl TextScreen {
|
||||
{
|
||||
let x = self.console.state.x;
|
||||
let y = self.console.state.y;
|
||||
Self::invert(&mut self.display, x * 8, y * 16, 8, 16);
|
||||
Self::invert(&mut map, x * 8, y * 16, 8, 16);
|
||||
self.changed.insert(y);
|
||||
}
|
||||
|
||||
{
|
||||
let display = &mut self.display;
|
||||
let changed = &mut self.changed;
|
||||
let input = &mut self.input;
|
||||
self.console.write(buf, |event| match event {
|
||||
@@ -250,14 +250,14 @@ impl TextScreen {
|
||||
bold,
|
||||
..
|
||||
} => {
|
||||
Self::char(display, x * 8, y * 16, c, color.as_rgb(), bold, false);
|
||||
Self::char(&mut map, x * 8, y * 16, c, color.as_rgb(), bold, false);
|
||||
changed.insert(y);
|
||||
}
|
||||
ransid::Event::Input { data } => {
|
||||
input.extend(data);
|
||||
}
|
||||
ransid::Event::Rect { x, y, w, h, color } => {
|
||||
Self::rect(display, x * 8, y * 16, w * 8, h * 16, color.as_rgb());
|
||||
Self::rect(&mut map, x * 8, y * 16, w * 8, h * 16, color.as_rgb());
|
||||
for y2 in y..y + h {
|
||||
changed.insert(y2);
|
||||
}
|
||||
@@ -271,8 +271,8 @@ impl TextScreen {
|
||||
w,
|
||||
h,
|
||||
} => {
|
||||
let width = display.width;
|
||||
let pixels = unsafe { &mut *display.offscreen };
|
||||
let width = map.width;
|
||||
let pixels = unsafe { &mut *map.offscreen };
|
||||
|
||||
for raw_y in 0..h {
|
||||
let y = if from_y > to_y { raw_y } else { h - raw_y - 1 };
|
||||
@@ -310,21 +310,24 @@ impl TextScreen {
|
||||
{
|
||||
let x = self.console.state.x;
|
||||
let y = self.console.state.y;
|
||||
Self::invert(&mut self.display, x * 8, y * 16, 8, 16);
|
||||
Self::invert(&mut map, x * 8, y * 16, 8, 16);
|
||||
self.changed.insert(y);
|
||||
}
|
||||
|
||||
let width = self.display.width.try_into().unwrap();
|
||||
for &change in self.changed.iter() {
|
||||
self.display.sync_rect(Damage {
|
||||
x: 0,
|
||||
y: i32::try_from(change).unwrap() * 16,
|
||||
width,
|
||||
height: 16,
|
||||
})?;
|
||||
}
|
||||
let width = map.width.try_into().unwrap();
|
||||
drop(map);
|
||||
self.display.sync_rects(
|
||||
self.changed
|
||||
.iter()
|
||||
.map(|&change| Damage {
|
||||
x: 0,
|
||||
y: i32::try_from(change).unwrap() * 16,
|
||||
width,
|
||||
height: 16,
|
||||
})
|
||||
.collect(),
|
||||
);
|
||||
self.changed.clear();
|
||||
libredox::call::fsync(self.display.display_file.as_raw_fd().as_raw_fd() as usize)?;
|
||||
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user