vuinputd/vuinputd-tests/src/run_vuinputd.rs

83 lines
2.1 KiB
Rust

// SPDX-License-Identifier: MIT
//
// Author: Johannes Leupolz <dev@leupolz.eu>
use std::{
os::unix::process::CommandExt,
process::{Child, Command},
sync::Mutex,
thread,
time::Duration,
};
use nix::sys::signal::{self, Signal};
use nix::unistd::Pid;
/// Global singleton
static VUINPUTD_LOCK: Mutex<()> = Mutex::new(());
pub fn ensure_vuinputd_running(args: &[&str]) -> VuinputdGuard {
VuinputdGuard::start(args)
}
pub struct VuinputdGuard {
child: Child,
}
impl VuinputdGuard {
fn start(args: &[&str]) -> Self {
println!("Acquiring lock to ensure only one vuinputd test instance is running");
let _mutex = VUINPUTD_LOCK.lock().unwrap();
println!("Executing vuinputd located via cargo run");
let mut concat_args = vec![
"run",
"-p",
"vuinputd",
"--",
"--major",
"120",
"--minor",
"414796",
"--devname",
"vuinput-test",
];
concat_args.extend(args);
let child = unsafe {
Command::new("cargo")
.args(concat_args)
.pre_exec(|| {
// Last resort, if the parent just is killed.
libc::prctl(libc::PR_SET_PDEATHSIG, libc::SIGKILL);
Ok(())
})
.spawn()
.expect("failed to start vuinputd")
};
// Optional: give it time to create /dev/vuinput
thread::sleep(Duration::from_millis(1000));
Self { child }
}
}
impl Drop for VuinputdGuard {
fn drop(&mut self) {
let pid = Pid::from_raw(self.child.id() as i32);
// First: SIGTERM
let _ = signal::kill(pid, Signal::SIGTERM);
// Wait a bit
for _ in 0..10 {
if let Ok(Some(_)) = self.child.try_wait() {
return;
}
thread::sleep(Duration::from_millis(100));
}
// Still alive → SIGKILL
let _ = signal::kill(pid, Signal::SIGKILL);
let _ = self.child.wait();
}
}