Some name refactorings

This commit is contained in:
Johannes Leupolz 2025-12-08 22:48:22 +00:00
parent 2c3531152b
commit ee38a7147c
16 changed files with 85 additions and 66 deletions

View file

@ -570,6 +570,11 @@ https://gitlab.steamos.cloud/steamrt/steam-runtime-tools/-/blob/main/docs/ld-lib
https://github.com/ValveSoftware/steam-for-linux/issues/10175
https://github.com/ValveSoftware/steam-for-linux/issues/8042
#### 5.3.3 Selkies Project
Absolutely untested.
https://github.com/selkies-project/selkies/pull/173
### 5.4 Applications that use the created devices
#### 5.4.1 SDL
@ -598,6 +603,10 @@ https://gitlab.freedesktop.org/libevdev/libevdev/-/blob/master/libevdev/libevdev
https://github.com/GloriousEggroll/proton-ge-custom/blob/master/docs/CONTROLLERS.md
wine control
https://github.com/flatpak/xdg-desktop-portal/issues/536
## 6. HIDAPI
https://github.com/libusb/hidapi

View file

@ -1,6 +1,6 @@
[package]
name = "vuinputd"
version = "0.2.0"
version = "0.2.1"
edition = "2021"
authors = ["Johannes Leupolz <dev@leupolz.eu>"]
license = "MIT"

View file

@ -1,9 +0,0 @@
// SPDX-License-Identifier: MIT
//
// Author: Johannes Leupolz <dev@leupolz.eu>
pub mod inject_in_container_job;
pub mod remove_from_container_job;
pub mod mknod_input_device;
pub mod runtime_data;
pub mod netlink_message;

View file

@ -5,7 +5,8 @@
use std::future::Future;
use std::pin::Pin;
use crate::jobs::job::{Dispatcher, Job, JobTarget};
use crate::job_engine::job::{Dispatcher, Job, JobTarget};
pub struct ClosureJob {
desc: String,
@ -56,7 +57,7 @@ impl Job for ClosureJob {
}
/// Example usage
#[allow(dead_code)]
#[test]
pub fn example() {
let mut dispatcher = Dispatcher::new();

View file

@ -0,0 +1,38 @@
// SPDX-License-Identifier: MIT
//
// Author: Johannes Leupolz <dev@leupolz.eu>
//! # Design: Async Per-Container Job Executor (Tokio)
//!
//! ## Overview
//! A scalable, structured design for running async jobs per container.
//!
//! - Global dispatcher routes jobs to per-container async loops or to global queue.
//! - Each container has its own unbounded job queue (no backpressure).
//! - Loops are spawned lazily on first job and exit when their sender drops.
//! - Graceful shutdown happens automatically (channel close → loop exit).
//! - Periodic cleanup removes idle container queues.
//!
//! ## Async Jobs
//! - Each `Job` contains an async closure `task: Box<dyn FnOnce(JobTarget) -> Pin<Box<dyn Future<Output = ()>>> + Send>`
//! - This allows full async/await usage inside the job body.
//!
//!
//! +--------------------------------------+
//! | Global dispatcher |
//! +----------+---------------------------+
//! | |
//! v v
//! +----------+-----------+ +------------+
//! | Per-container queues | | Host queue |
//! +----+------+----+-----+ +------------+
//! | | |
//! +----v----+ +---v----+ +---v----+
//! | Cont A | | Cont B | | Cont C |
//! | loop() | | loop() | | loop() |
//! +---------+ +--------+ +--------+
pub mod closure_job;
pub mod job;
#[cfg(test)]
mod tests;

View file

@ -1,5 +1,7 @@
use crate::jobs::closure_job::ClosureJob;
use crate::jobs::job::{Dispatcher, Job, JobTarget};
use crate::job_engine::closure_job::ClosureJob;
use crate::job_engine::job::{Dispatcher, JobTarget};
use super::*;
use futures::executor::LocalPool;
@ -49,6 +51,7 @@ fn test_job_ordering() {
}),
)));
dispatcher.close();
dispatcher.wait_until_finished();
assert_eq!(*c.lock().unwrap(), 6);

View file

@ -7,9 +7,8 @@ use std::{collections::HashMap, future::Future, pin::Pin, sync::{Arc, Condvar, M
use async_io::Timer;
use log::debug;
use crate::{
container::{mknod_input_device::ensure_input_device, netlink_message::send_udev_monitor_message_with_properties, runtime_data::{self, ensure_udev_structure, read_udev_data, write_udev_data}}, jobs::job::{Job, JobTarget}, monitor_udev::EVENT_STORE, requesting_process::{Pid, RequestingProcess, await_process, run_in_net_and_mnt_namespace}
};
use crate::{job_engine::job::{Job, JobTarget}, jobs::{mknod_input_device::ensure_input_device, monitor_udev_job::EVENT_STORE, netlink_message::send_udev_monitor_message_with_properties, runtime_data::{ensure_udev_structure, read_udev_data, write_udev_data}}, requesting_process::{Pid, RequestingProcess, await_process, run_in_net_and_mnt_namespace}};
#[derive(Clone,Debug,Copy,PartialOrd,PartialEq)]
pub enum State {

View file

@ -1,38 +1,10 @@
// SPDX-License-Identifier: MIT
//
// Author: Johannes Leupolz <dev@leupolz.eu>
//! # Design: Async Per-Container Job Executor (Tokio)
//!
//! ## Overview
//! A scalable, structured design for running async jobs per container.
//!
//! - Global dispatcher routes jobs to per-container async loops or to global queue.
//! - Each container has its own unbounded job queue (no backpressure).
//! - Loops are spawned lazily on first job and exit when their sender drops.
//! - Graceful shutdown happens automatically (channel close → loop exit).
//! - Periodic cleanup removes idle container queues.
//!
//! ## Async Jobs
//! - Each `Job` contains an async closure `task: Box<dyn FnOnce(JobTarget) -> Pin<Box<dyn Future<Output = ()>>> + Send>`
//! - This allows full async/await usage inside the job body.
//!
//!
//! +--------------------------------------+
//! | Global dispatcher |
//! +----------+---------------------------+
//! | |
//! v v
//! +----------+-----------+ +------------+
//! | Per-container queues | | Host queue |
//! +----+------+----+-----+ +------------+
//! | | |
//! +----v----+ +---v----+ +---v----+
//! | Cont A | | Cont B | | Cont C |
//! | loop() | | loop() | | loop() |
//! +---------+ +--------+ +--------+
pub mod closure_job;
pub mod job;
#[cfg(test)]
mod tests;
pub mod inject_in_container_job;
pub mod remove_from_container_job;
pub mod monitor_udev_job;
pub mod mknod_input_device;
pub mod runtime_data;
pub mod netlink_message;

View file

@ -19,7 +19,7 @@ use libudev::Monitor;
use log::debug;
use regex::Regex;
use crate::jobs::job::{Job, JobTarget};
use crate::job_engine::job::{Job, JobTarget};
// === Basic types ===

View file

@ -7,9 +7,8 @@ use std::{collections::HashMap, future::Future, pin::Pin, sync::{Arc, Condvar, M
use async_io::Timer;
use log::debug;
use crate::{
container::{mknod_input_device::{ensure_input_device, remove_input_device}, netlink_message::send_udev_monitor_message_with_properties, runtime_data::{self, delete_udev_data, ensure_udev_structure, read_udev_data, write_udev_data}}, jobs::job::{Job, JobTarget}, monitor_udev::EVENT_STORE, requesting_process::{Pid, RequestingProcess, await_process, run_in_net_and_mnt_namespace}
};
use crate::{job_engine::job::{Job, JobTarget}, jobs::{mknod_input_device::remove_input_device, monitor_udev_job::EVENT_STORE, netlink_message::send_udev_monitor_message_with_properties, runtime_data::{delete_udev_data, ensure_udev_structure, read_udev_data, write_udev_data}}, requesting_process::{Pid, RequestingProcess, await_process, run_in_net_and_mnt_namespace}};
#[derive(Clone,Debug,Copy,PartialOrd,PartialEq)]

View file

@ -38,18 +38,17 @@ use std::sync::{Arc, Mutex, OnceLock, RwLock};
use uinput_ioctls::*;
pub mod requesting_process;
pub mod monitor_udev;
pub mod compat;
use crate::compat::input_event_compat;
use crate::container::inject_in_container_job::InjectInContainerJob;
use crate::container::remove_from_container_job::RemoveFromContainerJob;
use crate::monitor_udev::MonitorBackgroundLoop;
use crate::jobs::inject_in_container_job::InjectInContainerJob;
use crate::jobs::monitor_udev_job::MonitorBackgroundLoop;
use crate::jobs::remove_from_container_job::RemoveFromContainerJob;
use crate::requesting_process::*;
pub mod jobs;
use crate::jobs::job::*;
pub mod job_engine;
use crate::job_engine::job::*;
pub mod container;
pub mod jobs;
#[derive(Debug)]
@ -351,7 +350,7 @@ unsafe extern "C" fn vuinput_release(
let remove_job=RemoveFromContainerJob::new(vuinput_state.requesting_process.clone(),input_device.devnode.clone(),input_device.syspath.clone(),input_device.major,input_device.minor);
let awaiter = remove_job.get_awaiter_for_state();
JOB_DISPATCHER.get().unwrap().lock().unwrap().dispatch(Box::new(remove_job));
awaiter(&container::remove_from_container_job::State::Finished);
awaiter(&jobs::remove_from_container_job::State::Finished);
}
drop(vuinput_state);
@ -364,7 +363,15 @@ unsafe extern "C" fn vuinput_release(
drop(vuinput_state_mutex); // this also closes the file when no other references are open
// TODO: maybe also ensure that nothing is left in the containers
// This _must_ be fuse_reply_err. fuse_reply_none would lead to a deadlock of the uinput user.
// Note: For CUSE, the kernel always issues RELEASE via fuse_sync_release(),
// which forces a *synchronous* request (fuse_simple_request()).
//
// That means the kernel thread blocks until userspace sends a reply header.
// Calling fuse_reply_none() would send no header at all, causing the kernel
// to wait forever and the caller to deadlock.
//
// Therefore we must always send a real reply for RELEASE.
// `fuse_reply_err(req, 0)` is enough to wake the kernel and is safe here.
fuse_lowlevel::fuse_reply_err(_req, 0);
}
@ -522,7 +529,7 @@ unsafe extern "C" fn vuinput_ioctl(
let inject_job=InjectInContainerJob::new(vuinput_state.requesting_process.clone(),devnode.clone(),sysname.clone(),major,minor);
let awaiter = inject_job.get_awaiter_for_state();
JOB_DISPATCHER.get().unwrap().lock().unwrap().dispatch(Box::new(inject_job));
awaiter(&container::inject_in_container_job::State::Finished);
awaiter(&jobs::inject_in_container_job::State::Finished);
debug!("fh {}: injecting dev-nodes in container has been finished ", fh);
}
@ -542,7 +549,7 @@ unsafe extern "C" fn vuinput_ioctl(
let remove_job=RemoveFromContainerJob::new(vuinput_state.requesting_process.clone(),input_device.devnode.clone(),input_device.syspath.clone(),input_device.major,input_device.minor);
let awaiter = remove_job.get_awaiter_for_state();
JOB_DISPATCHER.get().unwrap().lock().unwrap().dispatch(Box::new(remove_job));
awaiter(&container::remove_from_container_job::State::Finished);
awaiter(&jobs::remove_from_container_job::State::Finished);
debug!("fh {}: removing dev-nodes from container has been finished ", fh);
}