Merge branch 'inputd_pull_vt_events' into 'master'

inputd: Major refactorings to the inputd interface

See merge request redox-os/drivers!210
This commit is contained in:
Jeremy Soller
2024-12-22 16:56:49 +00:00
9 changed files with 521 additions and 526 deletions
Generated
+1
View File
@@ -1681,6 +1681,7 @@ dependencies = [
"ransid",
"redox-daemon",
"redox-scheme",
"redox_event",
"redox_syscall",
]
+3 -1
View File
@@ -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();
-4
View File
@@ -36,13 +36,10 @@ pub struct FbconScheme {
pub vts: BTreeMap<VtIndex, TextScreen>,
next_id: usize,
pub handles: BTreeMap<usize, Handle>,
pub inputd_handle: inputd::Handle,
}
impl FbconScheme {
pub fn new(vt_ids: &[usize], event_queue: &mut EventQueue<VtIndex>) -> 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,
}
}
+2 -1
View File
@@ -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" }
+121 -63
View File
@@ -2,15 +2,15 @@
extern crate orbclient;
extern crate syscall;
use redox_scheme::{RequestKind, SignalBehavior, Socket, V2};
use event::{user_data, EventQueue};
use libredox::errno::{EAGAIN, EINTR};
use redox_scheme::{RequestKind, Response, SignalBehavior, Socket, V2};
use std::env;
use std::fs::File;
use std::os::fd::AsRawFd;
use syscall::EVENT_READ;
use crate::{
framebuffer::FrameBuffer,
scheme::{DisplayScheme, HandleKind},
};
use crate::{framebuffer::FrameBuffer, scheme::DisplayScheme};
mod display;
mod framebuffer;
@@ -80,80 +80,138 @@ fn main() {
}
fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec<FrameBuffer>, spec: &[()]) -> ! {
let socket: Socket<V2> =
Socket::create("display.vesa").expect("vesad: failed to create display scheme");
Socket::nonblock("display.vesa").expect("vesad: failed to create display scheme");
let mut scheme = DisplayScheme::new(framebuffers, &spec);
let mut inputd_control_handle = inputd::ControlHandle::new().unwrap();
user_data! {
enum Source {
Input,
Scheme,
}
}
let event_queue: EventQueue<Source> =
EventQueue::new().expect("vesad: failed to create event queue");
event_queue
.subscribe(
scheme.inputd_handle.inner().as_raw_fd() as usize,
Source::Input,
event::EventFlags::READ,
)
.unwrap();
event_queue
.subscribe(
socket.inner().raw(),
Source::Scheme,
event::EventFlags::READ,
)
.unwrap();
let _ = File::open("/scheme/debug/disable-graphical-debug");
libredox::call::setrens(0, 0).expect("vesad: failed to enter null namespace");
daemon.ready().expect("failed to notify parent");
scheme.inputd_handle.activate(1).unwrap();
inputd_control_handle.activate_vt(1).unwrap();
let mut blocked = Vec::new();
loop {
let Some(request) = socket
.next_request(SignalBehavior::Restart)
.expect("vesad: failed to read display scheme")
else {
// Scheme likely got unmounted
std::process::exit(0);
};
match request.kind() {
RequestKind::Call(call_request) => {
if let Some(resp) = call_request.handle_scheme_block_mut(&mut scheme) {
socket
.write_response(resp, SignalBehavior::Restart)
.expect("vesad: failed to write display scheme");
} else {
blocked.push(call_request);
let all = [Source::Input, Source::Scheme];
for event in all
.into_iter()
.chain(event_queue.map(|e| e.expect("vesad: failed to get next event").user_data))
{
match event {
Source::Input => {
while let Some(vt_event) = scheme
.inputd_handle
.read_vt_event()
.expect("vesad: failed to read display handle")
{
scheme.handle_vt_event(vt_event);
}
}
RequestKind::Cancellation(_cancellation_request) => {}
RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => unreachable!(),
}
Source::Scheme => {
loop {
let request = match socket.next_request(SignalBehavior::Restart) {
Ok(Some(request)) => request,
Ok(None) => {
// Scheme likely got unmounted
std::process::exit(0);
}
Err(err) if err.errno == EAGAIN => break,
Err(err) => panic!("vesad: failed to read display scheme: {err}"),
};
// If there are blocked readers, try to handle them.
{
let mut i = 0;
while i < blocked.len() {
if let Some(resp) = blocked[i].handle_scheme_block_mut(&mut scheme) {
socket
.write_response(resp, SignalBehavior::Restart)
.expect("vesad: failed to write display scheme");
blocked.remove(i);
} else {
i += 1;
match request.kind() {
RequestKind::Call(call_request) => {
if let Some(resp) = call_request.handle_scheme_block_mut(&mut scheme) {
socket
.write_response(resp, SignalBehavior::Restart)
.expect("vesad: failed to write display scheme");
} else {
blocked.push(call_request);
}
}
RequestKind::Cancellation(cancellation_request) => {
if let Some(i) = blocked.iter().position(|req| {
req.request().request_id() == cancellation_request.id
}) {
let blocked_req = blocked.remove(i);
let resp =
Response::new(&blocked_req, Err(syscall::Error::new(EINTR)));
socket
.write_response(resp, SignalBehavior::Restart)
.expect("vesad: failed to write display scheme");
}
}
RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => {
unreachable!()
}
}
// If there are blocked readers, try to handle them.
{
let mut i = 0;
while i < blocked.len() {
if let Some(resp) = blocked[i].handle_scheme_block_mut(&mut scheme) {
socket
.write_response(resp, SignalBehavior::Restart)
.expect("vesad: failed to write display scheme");
blocked.remove(i);
} else {
i += 1;
}
}
}
for (handle_id, handle) in scheme.handles.iter_mut() {
if handle.notified_read || !handle.events.contains(EVENT_READ) {
continue;
}
let can_read = scheme
.vts
.get(&handle.vt)
.and_then(|screens| screens.get(&handle.screen))
.map_or(false, |screen| screen.can_read());
if can_read {
handle.notified_read = true;
socket
.post_fevent(*handle_id, EVENT_READ.bits())
.expect("vesad: failed to write display event");
} else {
handle.notified_read = false;
}
}
}
}
}
for (handle_id, handle) in scheme.handles.iter_mut() {
if handle.notified_read || !handle.events.contains(EVENT_READ) {
continue;
}
let can_read = if let HandleKind::Screen(vt_i, screen_i) = handle.kind {
scheme
.vts
.get(&vt_i)
.and_then(|screens| screens.get(&screen_i))
.map_or(false, |screen| screen.can_read())
} else {
false
};
if can_read {
handle.notified_read = true;
socket
.post_fevent(*handle_id, EVENT_READ.bits())
.expect("vesad: failed to write display event");
} else {
handle.notified_read = false;
}
}
}
panic!();
}
+77 -125
View File
@@ -1,6 +1,7 @@
use std::collections::BTreeMap;
use std::str;
use inputd::{VtEvent, VtEventKind};
use redox_scheme::SchemeBlockMut;
use syscall::{Error, EventFlags, MapFlags, Result, EBADF, EINVAL, ENOENT, O_NONBLOCK};
@@ -12,15 +13,11 @@ pub struct VtIndex(usize);
#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd, Debug)]
pub struct ScreenIndex(usize);
#[derive(Clone)]
pub enum HandleKind {
Input,
Screen(VtIndex, ScreenIndex),
}
#[derive(Clone)]
pub struct Handle {
pub kind: HandleKind,
pub vt: VtIndex,
pub screen: ScreenIndex,
pub flags: usize,
pub events: EventFlags,
pub notified_read: bool,
@@ -32,12 +29,12 @@ pub struct DisplayScheme {
pub vts: BTreeMap<VtIndex, BTreeMap<ScreenIndex, GraphicScreen>>,
next_id: usize,
pub handles: BTreeMap<usize, Handle>,
pub inputd_handle: inputd::Handle,
pub inputd_handle: inputd::DisplayHandle,
}
impl DisplayScheme {
pub fn new(framebuffers: Vec<FrameBuffer>, spec: &[()]) -> DisplayScheme {
let mut inputd_handle = inputd::Handle::new("vesa").unwrap();
let mut inputd_handle = inputd::DisplayHandle::new("vesa").unwrap();
let mut vts = BTreeMap::<VtIndex, BTreeMap<ScreenIndex, GraphicScreen>>::new();
@@ -47,7 +44,7 @@ impl DisplayScheme {
let fb = &framebuffers[fb_i];
screens.insert(ScreenIndex(fb_i), GraphicScreen::new(fb.width, fb.height));
}
vts.insert(VtIndex(inputd_handle.register().unwrap()), screens);
vts.insert(VtIndex(inputd_handle.register_vt().unwrap()), screens);
}
DisplayScheme {
@@ -84,6 +81,32 @@ impl DisplayScheme {
}
}
}
pub fn handle_vt_event(&mut self, vt_event: VtEvent) {
match vt_event.kind {
VtEventKind::Activate => {
let vt_i = VtIndex(vt_event.vt);
if let Some(screens) = self.vts.get_mut(&vt_i) {
for (screen_i, screen) in screens.iter_mut() {
screen.redraw(&mut self.framebuffers[screen_i.0]);
}
}
self.active = vt_i;
}
VtEventKind::Deactivate => {
// Nothing to do for deactivate :)
}
VtEventKind::Resize => {
self.resize(
vt_event.width as usize,
vt_event.height as usize,
vt_event.stride as usize,
);
}
}
}
}
impl SchemeBlockMut for DisplayScheme {
@@ -94,21 +117,6 @@ impl SchemeBlockMut for DisplayScheme {
_uid: u32,
_gid: u32,
) -> Result<Option<usize>> {
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::<usize>().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<Option<usize>> {
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<Option<usize>> {
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<Option<usize>> {
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<Option<usize>> {
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<Option<usize>> {
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));
}
}
}
+74 -103
View File
@@ -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<Display<'a>>,
vt: usize,
},
Input,
struct Handle<'a> {
display: Arc<Display<'a>>,
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<usize> {
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<usize> {
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<usize> {
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<usize> {
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::<Damage>(),
)
};
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::<Damage>(),
)
};
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<usize> {
@@ -484,12 +459,8 @@ impl<'a> SchemeMut for Scheme<'a> {
flags: MapFlags,
) -> syscall::Result<usize> {
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)
}
}
+53 -113
View File
@@ -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<T: Sized>(p: &T) -> &[u8] {
::core::slice::from_raw_parts((p as *const T) as *const u8, ::core::mem::size_of::<T>())
std::slice::from_raw_parts((p as *const T) as *const u8, size_of::<T>())
}
unsafe fn any_as_u8_slice_mut<T: Sized>(p: &mut T) -> &mut [u8] {
std::slice::from_raw_parts_mut((p as *mut T) as *mut u8, size_of::<T>())
}
#[derive(Debug, Clone)]
@@ -13,9 +19,9 @@ pub struct VtActivate {
pub vt: usize,
}
pub struct Handle(File);
pub struct DisplayHandle(File);
impl Handle {
impl DisplayHandle {
pub fn new<S: Into<String>>(device_name: S) -> Result<Self, Error> {
let path = format!("/scheme/input/handle/display/{}", device_name.into());
Ok(Self(File::open(path)?))
@@ -23,131 +29,65 @@ impl Handle {
// The return value is the display identifier. It will be used to uniquely
// identify the display on activation events.
pub fn register(&mut self) -> Result<usize, Error> {
pub fn register_vt(&mut self) -> Result<usize, Error> {
self.0.read(&mut [])
}
pub fn activate(&mut self, vt: usize) -> Result<usize, Error> {
pub fn read_vt_event(&mut self) -> Result<Option<VtEvent>, 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::<VtEvent>());
Ok(Some(event))
}
}
pub fn inner(&self) -> BorrowedFd<'_> {
self.0.as_fd()
}
}
pub struct ControlHandle(File);
impl ControlHandle {
pub fn new() -> Result<Self, Error> {
let path = format!("/scheme/input/control");
Ok(Self(File::open(path)?))
}
pub fn activate_vt(&mut self, vt: usize) -> Result<usize, Error> {
let cmd = VtActivate { vt };
self.0.write(unsafe { any_as_u8_slice(&cmd) })
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
#[repr(u8)]
enum CmdTy {
Unknown = 0,
#[derive(Debug)]
#[repr(usize)]
pub enum VtEventKind {
Activate,
Deactivate,
Resize,
}
impl From<u8> 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<Cmd> {
const U32_SIZE: usize = core::mem::size_of::<u32>();
const USIZE_SIZE: usize = core::mem::size_of::<usize>();
let mut parser = buffer.iter().cloned();
let command = CmdTy::from(parser.next()?);
let vt = usize::from_le_bytes(parser.next_chunk::<USIZE_SIZE>().ok()?);
match command {
CmdTy::Activate => {
let cmd = unsafe { &*buffer.as_ptr().offset(1).cast::<VtActivate>() };
Some(Cmd::Activate { vt: cmd.vt })
}
CmdTy::Deactivate => Some(Cmd::Deactivate(vt)),
CmdTy::Resize => {
let width = parser.next_chunk::<U32_SIZE>().ok()?;
let height = parser.next_chunk::<U32_SIZE>().ok()?;
let stride = parser.next_chunk::<U32_SIZE>().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)]
+190 -116
View File
@@ -11,12 +11,12 @@
//! Read events from `input:consumer`. Optionally, set the `EVENT_READ` flag to be notified when
//! events are available.
use core::mem::size_of;
use std::collections::BTreeMap;
use std::fs::File;
use std::os::fd::AsRawFd;
use std::mem::transmute;
use std::sync::atomic::{AtomicUsize, Ordering};
use inputd::{Cmd, VtActivate};
use inputd::{VtActivate, VtEvent, VtEventKind};
use redox_scheme::{RequestKind, SchemeMut, SignalBehavior, Socket, V2};
@@ -31,9 +31,13 @@ enum Handle {
notified: bool,
vt: usize,
},
Device {
Display {
events: EventFlags,
pending: Vec<VtEvent>,
notified: bool,
device: String,
},
Control,
}
impl Handle {
@@ -44,28 +48,14 @@ impl Handle {
struct Vt {
display: String,
index: usize,
/// This is *required* to be lazily initialized since opening the handle to the display
/// requires the system call to return first. Otherwise, it will block indefinitely.
handle_file: Option<File>,
}
impl Vt {
fn new(display: impl Into<String>, index: usize) -> Self {
fn new(display: impl Into<String>) -> 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<usize>,
pending_activate: Option<VtActivate>,
has_new_events: bool,
}
@@ -93,10 +82,67 @@ impl InputScheme {
super_key: false,
active_vt: None,
pending_activate: None,
has_new_events: false,
}
}
fn switch_vt(&mut self, new_active: usize) -> syscall::Result<()> {
if let Some(active_vt) = self.active_vt {
if new_active == active_vt {
return Ok(());
}
}
if !self.vts.contains_key(&new_active) {
log::warn!("inputd: switch to non-existent VT #{new_active} was requested");
return Ok(());
}
log::info!(
"inputd: switching from VT #{} to VT #{new_active}",
self.active_vt.unwrap_or(0)
);
for handle in self.handles.values_mut() {
match handle {
Handle::Display {
pending,
notified,
device,
..
} => {
if let Some(active_vt) = self.active_vt {
if &self.vts[&active_vt].display == &*device {
pending.push(VtEvent {
kind: VtEventKind::Deactivate,
vt: self.active_vt.unwrap(),
width: 0,
height: 0,
stride: 0,
});
*notified = false;
}
}
if &self.vts[&new_active].display == &*device {
pending.push(VtEvent {
kind: VtEventKind::Activate,
vt: new_active,
width: 0,
height: 0,
stride: 0,
});
*notified = false;
}
}
_ => continue,
}
}
self.active_vt = Some(new_active);
Ok(())
}
}
impl SchemeMut for InputScheme {
@@ -123,8 +169,14 @@ impl SchemeMut for InputScheme {
}
"handle" => {
let display = path_parts.collect::<Vec<_>>().join(".");
Handle::Device { device: display }
Handle::Display {
events: EventFlags::empty(),
pending: Vec::new(),
notified: false,
device: display,
}
}
"control" => Handle::Control,
_ => {
log::error!("inputd: invalid path {path}");
@@ -174,18 +226,42 @@ impl SchemeMut for InputScheme {
Ok(copy)
}
Handle::Device { device } => {
assert!(buf.is_empty());
Handle::Display {
pending, device, ..
} => {
// FIXME Create new VT through a write instead and return a NewVt event on read
// This allows also returning events for VT (de)activation from the display handle
// rather than pushing them to the graphics driver.
if buf.is_empty() {
// Trying to do an empty read creates a new VT.
let vt = self.next_vt_id.fetch_add(1, Ordering::SeqCst);
log::info!("inputd: created VT #{vt} for {device}");
self.vts.insert(vt, Vt::new(device.clone()));
Ok(vt)
} else if buf.len() % size_of::<VtEvent>() == 0 {
let copy = core::cmp::min(pending.len(), buf.len() / size_of::<VtEvent>());
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::<VtEvent>()..(i + 1) * size_of::<VtEvent>()]
.copy_from_slice(&unsafe {
transmute::<VtEvent, [u8; size_of::<VtEvent>()]>(event)
});
}
Ok(copy * size_of::<VtEvent>())
} else {
log::error!("inputd: display tried to read incorrectly sized event");
return Err(SysError::new(EINVAL));
}
}
Handle::Producer => {
log::error!("inputd: producer tried to read");
return Err(SysError::new(EINVAL));
}
Handle::Control => {
log::error!("inputd: control tried to read");
return Err(SysError::new(EINVAL));
}
}
}
@@ -201,17 +277,16 @@ impl SchemeMut for InputScheme {
let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?;
match handle {
Handle::Device { device } => {
if buf.len() != core::mem::size_of::<VtActivate>() {
log::error!("inputd: device tried to write incorrectly sized command");
Handle::Control => {
if buf.len() != size_of::<VtActivate>() {
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::<VtActivate>() };
self.vts.insert(cmd.vt, Vt::new(device.clone(), cmd.vt));
self.pending_activate = Some(cmd.clone());
self.switch_vt(cmd.vt)?;
return Ok(buf.len());
}
@@ -220,6 +295,10 @@ impl SchemeMut for InputScheme {
log::error!("inputd: consumer tried to write");
return Err(SysError::new(EINVAL));
}
Handle::Display { .. } => {
log::error!("inputd: display tried to write");
return Err(SysError::new(EINVAL));
}
Handle::Producer => {}
}
@@ -230,11 +309,11 @@ impl SchemeMut for InputScheme {
let events = unsafe {
core::slice::from_raw_parts(
buf.as_ptr() as *const Event,
buf.len() / core::mem::size_of::<Event>(),
buf.len() / size_of::<Event>(),
)
};
'out: for event in events.iter() {
for event in events.iter() {
let mut new_active_opt = None;
match event.to_option() {
EventOption::Key(key_event) => match key_event.scancode {
@@ -262,42 +341,41 @@ impl SchemeMut for InputScheme {
},
EventOption::Resize(resize_event) => {
let active_vt = self.vts.get_mut(&self.active_vt.unwrap()).unwrap();
active_vt.send_command(Cmd::Resize {
vt: active_vt.index,
width: resize_event.width,
height: resize_event.height,
for handle in self.handles.values_mut() {
match handle {
Handle::Display {
pending,
notified,
device,
..
} => {
if &self.vts[&self.active_vt.unwrap()].display == &*device {
pending.push(VtEvent {
kind: VtEventKind::Resize,
vt: self.active_vt.unwrap(),
width: resize_event.width,
height: resize_event.height,
// TODO(andypython): Figure out how to get the stride.
stride: resize_event.width,
})?;
// TODO(andypython): Figure out how to get the stride.
stride: resize_event.width,
});
*notified = false;
}
}
_ => continue,
}
}
}
_ => continue,
}
if let Some(new_active) = new_active_opt {
if new_active == self.vts[&self.active_vt.unwrap()].index {
continue 'out;
}
if self.vts.contains_key(&new_active) {
let active_vt = self.vts.get_mut(&self.active_vt.unwrap()).unwrap();
active_vt.send_command(Cmd::Deactivate(active_vt.index))?;
}
if let Some(new_active) = self.vts.get_mut(&new_active) {
new_active.send_command(Cmd::Activate {
vt: new_active.index,
})?;
self.active_vt = Some(new_active.index);
} else {
log::warn!("inputd: switch to non-existent VT #{new_active} was requested");
}
self.switch_vt(new_active)?;
}
}
let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?;
assert!(handle.is_producer());
let active_vt = self.active_vt.unwrap();
@@ -340,8 +418,17 @@ impl SchemeMut for InputScheme {
*notified = false;
Ok(EventFlags::empty())
}
Handle::Producer | Handle::Device { .. } => {
log::error!("inputd: producer or device tried to use an event queue");
Handle::Display {
ref mut events,
ref mut notified,
..
} => {
*events = flags;
*notified = false;
Ok(EventFlags::empty())
}
Handle::Producer | Handle::Control => {
log::error!("inputd: producer or control tried to use an event queue");
Err(SysError::new(EINVAL))
}
}
@@ -377,44 +464,51 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> {
RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => unreachable!(),
}
if let Some(cmd) = scheme.pending_activate.take() {
let vt = scheme.vts.get_mut(&cmd.vt).unwrap();
// Failing to activate a VT is not a fatal error.
if let Err(err) = vt.send_command(Cmd::Activate { vt: vt.index }) {
log::error!("inputd: failed to activate VT #{}: {err}", vt.index)
}
scheme.active_vt = Some(vt.index);
}
if !scheme.has_new_events {
continue;
}
for (id, handle) in scheme.handles.iter_mut() {
if let Handle::Consumer {
events,
pending,
ref mut notified,
vt,
} = handle
{
if pending.is_empty() || *notified || !events.contains(EventFlags::EVENT_READ) {
continue;
match handle {
Handle::Consumer {
events,
pending,
ref mut notified,
vt,
} => {
if pending.is_empty() || *notified || !events.contains(EventFlags::EVENT_READ) {
continue;
}
let active_vt = scheme.active_vt.unwrap();
// The activate VT is not the same as the VT that the consumer is listening to
// for events.
if active_vt != *vt {
continue;
}
// Notify the consumer that we have some events to read. Yum yum.
socket_file.post_fevent(*id, EventFlags::EVENT_READ.bits())?;
*notified = true;
}
Handle::Display {
events,
pending,
ref mut notified,
..
} => {
if pending.is_empty() || *notified || !events.contains(EventFlags::EVENT_READ) {
continue;
}
let active_vt = scheme.active_vt.unwrap();
// Notify the consumer that we have some events to read. Yum yum.
socket_file.post_fevent(*id, EventFlags::EVENT_READ.bits())?;
// The activate VT is not the same as the VT that the consumer is listening to
// for events.
if active_vt != *vt {
continue;
*notified = true;
}
// Notify the consumer that we have some events to read. Yum yum.
socket_file.post_fevent(*id, EventFlags::EVENT_READ.bits())?;
*notified = true;
_ => {}
}
}
}
@@ -442,31 +536,11 @@ fn main() {
"-A" => {
let vt = args.next().unwrap().parse::<usize>().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),