Is there a way to await for tokio's child process to finish in spawned task but still be able to use it after this task was spawned?
use std::{io, sync::Arc};
use tokio::{process::Command, sync::Mutex, task};
#[tokio::main]
async fn main() -> io::Result<()> {
let process = Arc::new(Mutex::new(Command::new("ls").spawn()?));
task::spawn({
let process = process.clone();
async move {
let mut process = process.lock().await;
process.wait_with_output().await;
}
});
// use process here
Ok(())
}
The current error is:
error[E0507]: cannot move out of dereference of `tokio::sync::MutexGuard<'_, tokio::process::Child>`
--> src/main.rs:14:13
|
14 | process.wait_with_output().await;
| ^^^^^^^ move occurs because value has type `tokio::process::Child`, which does not implement the `Copy` trait
Anyway, I posted a dummy reduced example for readability but it doesn't really illustrates "why"s. Here's the full code that I'm trying to make work to clarify what exactly I'm trying to do:
pub(crate) async fn wait(self, stdio: Stdio) -> Result {
let process = self.0;
let exit_reason = {
let process = process.clone();
tokio::select! {
result = {
let mut process = process.lock().await;
process.wait_with_output()
} => ExitReason::ProcessFinished(result),
_ = signal::ctrl_c() => ExitReason::CtrlC,
}
};
match exit_reason {
ExitReason::ProcessFinished(result) => {
let output = result?;
if output.status.success() {
match stdio {
Stdio::Inherit | Stdio::Ignore => Ok(Done::Bye),
Stdio::Collect => Ok(Done::Output(output.into())),
}
} else {
Err(output.into())
}
}
ExitReason::CtrlC => {
let res = {
let process = process.clone();
tokio::select! {
_ = {
let mut process = process.lock().await;
process.wait()
} => CtrlCResult::ProcessExited,
_ = time::sleep(Duration::from_secs(TIMEOUT)) => CtrlCResult::Timeout,
}
};
match res {
CtrlCResult::ProcessExited => Ok(Done::Bye),
CtrlCResult::Timeout => {
let mut process = process.lock().await;
process.kill().await?;
Ok(Done::Bye)
}
}
}
}
}
then it can be checked in the main task later on: if it wasn't flipped after timeout, it means process is still running -> killing it using libc::kill(pid, libc::SIGKILL).