mirror of
https://github.com/joleuger/vuinputd.git
synced 2026-07-17 16:36:03 +00:00
Some name refactorings
This commit is contained in:
parent
2c3531152b
commit
ee38a7147c
16 changed files with 85 additions and 66 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -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();
|
||||
|
||||
38
vuinputd/src/job_engine/mod.rs
Normal file
38
vuinputd/src/job_engine/mod.rs
Normal 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;
|
||||
|
|
@ -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);
|
||||
|
|
@ -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 {
|
||||
|
|
@ -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;
|
||||
|
|
@ -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 ===
|
||||
|
||||
|
|
@ -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)]
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue