Skip to content

Commit 1d69db9

Browse files
VLanvinfacebook-github-bot
authored andcommitted
Mitigate race causing ETXTBSY on eqWAlizer exe
Summary: A race condition can occur between a thread trying to use the eqWAlizer executable, and the main thread creating the executable, leading to a panic with "text file busy". See rust-lang/rust#114554 for more details. This mitigates the issue by attempting to start the eqWAlizer command in a loop, retrying if it fails with ETXTBSY. Reviewed By: robertoaloi, TD5 Differential Revision: D69775408 fbshipit-source-id: 9f08258bdb762edbe9c75ed813b52cbb0fb303df
1 parent 103cc12 commit 1d69db9

File tree

1 file changed

+32
-16
lines changed

1 file changed

+32
-16
lines changed

crates/eqwalizer/src/ipc.rs

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,14 @@ use std::fs;
1111
use std::io::BufRead;
1212
use std::io::BufReader;
1313
use std::io::BufWriter;
14+
use std::io::ErrorKind;
1415
use std::io::Write;
16+
use std::process::Child;
1517
use std::process::ChildStdin;
1618
use std::process::ChildStdout;
1719
use std::process::Command;
1820
use std::process::Stdio;
21+
use std::thread;
1922
use std::time::Duration;
2023

2124
use anyhow::bail;
@@ -83,28 +86,41 @@ const WRITE_TIMEOUT: Duration = Duration::from_secs(240);
8386
const READ_TIMEOUT: Duration = Duration::from_secs(240);
8487

8588
impl IpcHandle {
89+
fn spawn_cmd(cmd: &mut Command) -> Result<Child> {
90+
// Spawn can fail due to a race condition with the creation/closing of the
91+
// eqWAlizer executable, so we retry until the file is properly closed.
92+
// See https://github.com/rust-lang/rust/issues/114554
93+
loop {
94+
match cmd.spawn() {
95+
Ok(c) => return Ok(c),
96+
Err(err) => {
97+
if err.kind() == ErrorKind::ExecutableFileBusy {
98+
thread::sleep(Duration::from_millis(10));
99+
} else {
100+
// Provide extra debugging detail, to track down T198872667
101+
let command_str = cmd.get_program();
102+
let attr = fs::metadata(command_str);
103+
let error_str = format!(
104+
"err: {}, command_str: {:?}, cmd: {:?}, meta_data: {:?}",
105+
err, command_str, cmd, &attr
106+
);
107+
// Show up in error log
108+
log::error!("{}", limit_logged_string(&error_str));
109+
// And show up as an eqwalizer error
110+
bail!(error_str)
111+
}
112+
}
113+
}
114+
}
115+
}
116+
86117
pub fn from_command(cmd: &mut Command) -> Result<Self> {
87118
cmd.stdin(Stdio::piped())
88119
.stdout(Stdio::piped())
89120
// for debugging purposes
90121
.stderr(Stdio::inherit());
91122

92-
let mut child = match cmd.spawn() {
93-
Ok(c) => c,
94-
Err(err) => {
95-
// Provide extra debugging detail, to track down T198872667
96-
let command_str = cmd.get_program();
97-
let attr = fs::metadata(command_str);
98-
let error_str = format!(
99-
"err: {}, command_str: {:?}, cmd: {:?}, meta_data: {:?}",
100-
err, command_str, cmd, &attr
101-
);
102-
// Show up in error log
103-
log::error!("{}", limit_logged_string(&error_str));
104-
// And show up as an eqwalizer error
105-
bail!(error_str);
106-
}
107-
};
123+
let mut child = Self::spawn_cmd(cmd)?;
108124
let stdin = child
109125
.stdin
110126
.take()

0 commit comments

Comments
 (0)