I'm working on a function that is supposed to execute a shell command in a child process and capture its output. The catch: I want to be able to send it a signal through a mpsc channel to "reload"/"rerun" the command midway through execution. Therefore, I spawn the command and am waiting on two things: 1. for the command to complete, and 2. to receive something via the reload channel. Here is my current implementation:
pub fn capture_output(&self, reload_rx: &Receiver<()>) -> Result<Vec<String>> {
loop {
let mut child = self.shell_cmd(None).stdout(Stdio::piped()).spawn()?;
// TODO: remove busy waiting by creating two threads that send the same event and handle that
// busy wait for reload signal or child process finishing
loop {
if reload_rx.try_recv().is_ok() {
child.kill().ok();
break;
}
if let Ok(Some(_)) = child.try_wait() {
let output = child.wait_with_output()?;
check_stderr(&output)?;
let lines = String::from_utf8(output.stdout)?
.lines()
.map(str::to_string)
.collect();
return Ok(lines);
}
thread::sleep(Duration::from_millis(50));
}
}
}
I am not happy with this implementation, because I have to create a tick rate (of 50 ms) where I go to sleep and then check both conditions again. I want to improve this somehow, and am asking for some suggestions. I have zero experience with async + e.g. tokio, is that something worth looking into? My first thought was to create two threads, and in each wait blockingly on the events and then send an event to the "main" thread, which then just handles the first one it receives. However, it's impossible to transfer the reload_rx receiver into a thread (according to rust), as I need it elsewhere as well.
Any ideas on how to improve my code by removing the tick rate and somehow blockingly waiting on two (seperate) events at the same time? Thanks everyone!