use std::ffi::CString; use std::fmt::Debug; #[derive(Clone, Debug)] pub struct TaskConfig { exe: String, } #[derive(Clone, Debug)] pub struct TaskInfo { config: TaskConfig, pid: libc::pid_t, } #[derive(Clone, Debug)] pub struct TaskResult { info: TaskInfo, status: i32, } impl TaskConfig { pub fn new>(exe: Exe) -> Self { Self { exe: exe.into() } } } impl TaskInfo { pub fn new(config: TaskConfig, pid: libc::pid_t) -> Self { Self { config, pid } } } impl TaskResult { pub fn new(info: TaskInfo, status: i32) -> Self { Self { info, status } } pub fn status(&self) -> i32 { self.status } } pub trait Task: Debug + Sized { fn new(info: TaskInfo) -> Self; fn info(&self) -> &TaskInfo; fn start(config: TaskConfig) -> Result { unsafe { let pid = libc::fork(); if pid == -1 { return Err("fork".into()); } if pid == 0 { let arg0 = CString::new(config.exe.as_bytes()).unwrap(); let args = vec![arg0.as_ptr(), std::ptr::null()]; libc::execvp(arg0.as_ptr(), args.as_ptr()); libc::exit(libc::EXIT_FAILURE); } Ok(Self::new(TaskInfo::new(config, pid))) } } fn wait(self) -> TaskResult { unsafe { let status: i32 = 0; libc::waitpid(self.info().pid, status as *mut i32, 0); let status = libc::WEXITSTATUS(status); TaskResult::new(self.info().clone(), status) } } fn terminate(self) -> TaskResult { unsafe { libc::kill(self.info().pid, libc::SIGKILL); let status: i32 = 0; libc::waitpid(self.info().pid, status as *mut i32, 0); let status = libc::WEXITSTATUS(status); TaskResult::new(self.info().clone(), status) } } }