Skip to content

Commit a23dd0d

Browse files
committed
Replace fcntl-based file lock with flock
WSL1 does not support `fcntl`-based lock and will always report success, therefore creating a race condition when multiple rustc processes are modifying shared data such as `search-index.js`. WSL1 does however support `flock`. `flock` is supported by all unix-like platforms. The only caveat is that Linux 2.6.11 or earlier does not support `flock` on NFS mounts, but as the minimum supported Linux version is 2.6.18, it is not an issue. Fixes #72157
1 parent 769d12e commit a23dd0d

File tree

1 file changed

+19
-48
lines changed

1 file changed

+19
-48
lines changed

src/librustc_data_structures/flock.rs

+19-48
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,12 @@ use std::path::Path;
1212

1313
cfg_if! {
1414
if #[cfg(unix)] {
15-
use std::ffi::{CString, OsStr};
16-
use std::mem;
1715
use std::os::unix::prelude::*;
16+
use std::fs::{File, OpenOptions};
1817

1918
#[derive(Debug)]
2019
pub struct Lock {
21-
fd: libc::c_int,
20+
_file: File,
2221
}
2322

2423
impl Lock {
@@ -27,63 +26,35 @@ cfg_if! {
2726
create: bool,
2827
exclusive: bool)
2928
-> io::Result<Lock> {
30-
let os: &OsStr = p.as_ref();
31-
let buf = CString::new(os.as_bytes()).unwrap();
32-
let open_flags = if create {
33-
libc::O_RDWR | libc::O_CREAT
29+
let file = OpenOptions::new()
30+
.read(true)
31+
.write(true)
32+
.create(create)
33+
.mode(libc::S_IRWXU as u32)
34+
.open(p)?;
35+
36+
let mut operation = if exclusive {
37+
libc::LOCK_EX
3438
} else {
35-
libc::O_RDWR
36-
};
37-
38-
let fd = unsafe {
39-
libc::open(buf.as_ptr(), open_flags,
40-
libc::S_IRWXU as libc::c_int)
39+
libc::LOCK_SH
4140
};
42-
43-
if fd < 0 {
44-
return Err(io::Error::last_os_error());
41+
if !wait {
42+
operation |= libc::LOCK_NB
4543
}
4644

47-
let lock_type = if exclusive {
48-
libc::F_WRLCK
49-
} else {
50-
libc::F_RDLCK
51-
};
52-
53-
let mut flock: libc::flock = unsafe { mem::zeroed() };
54-
flock.l_type = lock_type as libc::c_short;
55-
flock.l_whence = libc::SEEK_SET as libc::c_short;
56-
flock.l_start = 0;
57-
flock.l_len = 0;
58-
59-
let cmd = if wait { libc::F_SETLKW } else { libc::F_SETLK };
60-
let ret = unsafe {
61-
libc::fcntl(fd, cmd, &flock)
62-
};
45+
let ret = unsafe { libc::flock(file.as_raw_fd(), operation) };
6346
if ret == -1 {
6447
let err = io::Error::last_os_error();
65-
unsafe { libc::close(fd); }
6648
Err(err)
6749
} else {
68-
Ok(Lock { fd })
50+
Ok(Lock { _file: file })
6951
}
7052
}
7153
}
7254

73-
impl Drop for Lock {
74-
fn drop(&mut self) {
75-
let mut flock: libc::flock = unsafe { mem::zeroed() };
76-
flock.l_type = libc::F_UNLCK as libc::c_short;
77-
flock.l_whence = libc::SEEK_SET as libc::c_short;
78-
flock.l_start = 0;
79-
flock.l_len = 0;
80-
81-
unsafe {
82-
libc::fcntl(self.fd, libc::F_SETLK, &flock);
83-
libc::close(self.fd);
84-
}
85-
}
86-
}
55+
// Note that we don't need a Drop impl to execute `flock(fd, LOCK_UN)`. Lock acquired by
56+
// `flock` is associated with the file descriptor and closing the file release it
57+
// automatically.
8758
} else if #[cfg(windows)] {
8859
use std::mem;
8960
use std::os::windows::prelude::*;

0 commit comments

Comments
 (0)