Skip to content

Commit a8018e2

Browse files
authored
Rollup merge of #72161 - nbdd0121:master, r=cuviper
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
2 parents 2059112 + a05acbf commit a8018e2

File tree

1 file changed

+57
-24
lines changed

1 file changed

+57
-24
lines changed

src/librustc_data_structures/flock.rs

+57-24
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,22 @@
77
#![allow(non_camel_case_types)]
88
#![allow(nonstandard_style)]
99

10+
use std::fs::{File, OpenOptions};
1011
use std::io;
1112
use std::path::Path;
1213

1314
cfg_if! {
14-
if #[cfg(unix)] {
15-
use std::ffi::{CString, OsStr};
16-
use std::mem;
15+
// We use `flock` rather than `fcntl` on Linux, because WSL1 does not support
16+
// `fcntl`-style advisory locks properly (rust-lang/rust#72157).
17+
//
18+
// For other Unix targets we still use `fcntl` because it's more portable than
19+
// `flock`.
20+
if #[cfg(target_os = "linux")] {
1721
use std::os::unix::prelude::*;
1822

1923
#[derive(Debug)]
2024
pub struct Lock {
21-
fd: libc::c_int,
25+
_file: File,
2226
}
2327

2428
impl Lock {
@@ -27,22 +31,55 @@ cfg_if! {
2731
create: bool,
2832
exclusive: bool)
2933
-> 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
34+
let file = OpenOptions::new()
35+
.read(true)
36+
.write(true)
37+
.create(create)
38+
.mode(libc::S_IRWXU as u32)
39+
.open(p)?;
40+
41+
let mut operation = if exclusive {
42+
libc::LOCK_EX
3443
} 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)
44+
libc::LOCK_SH
4145
};
46+
if !wait {
47+
operation |= libc::LOCK_NB
48+
}
4249

43-
if fd < 0 {
44-
return Err(io::Error::last_os_error());
50+
let ret = unsafe { libc::flock(file.as_raw_fd(), operation) };
51+
if ret == -1 {
52+
Err(io::Error::last_os_error())
53+
} else {
54+
Ok(Lock { _file: file })
4555
}
56+
}
57+
}
58+
59+
// Note that we don't need a Drop impl to execute `flock(fd, LOCK_UN)`. Lock acquired by
60+
// `flock` is associated with the file descriptor and closing the file release it
61+
// automatically.
62+
} else if #[cfg(unix)] {
63+
use std::mem;
64+
use std::os::unix::prelude::*;
65+
66+
#[derive(Debug)]
67+
pub struct Lock {
68+
file: File,
69+
}
70+
71+
impl Lock {
72+
pub fn new(p: &Path,
73+
wait: bool,
74+
create: bool,
75+
exclusive: bool)
76+
-> io::Result<Lock> {
77+
let file = OpenOptions::new()
78+
.read(true)
79+
.write(true)
80+
.create(create)
81+
.mode(libc::S_IRWXU as u32)
82+
.open(p)?;
4683

4784
let lock_type = if exclusive {
4885
libc::F_WRLCK
@@ -58,14 +95,12 @@ cfg_if! {
5895

5996
let cmd = if wait { libc::F_SETLKW } else { libc::F_SETLK };
6097
let ret = unsafe {
61-
libc::fcntl(fd, cmd, &flock)
98+
libc::fcntl(file.as_raw_fd(), cmd, &flock)
6299
};
63100
if ret == -1 {
64-
let err = io::Error::last_os_error();
65-
unsafe { libc::close(fd); }
66-
Err(err)
101+
Err(io::Error::last_os_error())
67102
} else {
68-
Ok(Lock { fd })
103+
Ok(Lock { file })
69104
}
70105
}
71106
}
@@ -79,15 +114,13 @@ cfg_if! {
79114
flock.l_len = 0;
80115

81116
unsafe {
82-
libc::fcntl(self.fd, libc::F_SETLK, &flock);
83-
libc::close(self.fd);
117+
libc::fcntl(self.file.as_raw_fd(), libc::F_SETLK, &flock);
84118
}
85119
}
86120
}
87121
} else if #[cfg(windows)] {
88122
use std::mem;
89123
use std::os::windows::prelude::*;
90-
use std::fs::{File, OpenOptions};
91124

92125
use winapi::um::minwinbase::{OVERLAPPED, LOCKFILE_FAIL_IMMEDIATELY, LOCKFILE_EXCLUSIVE_LOCK};
93126
use winapi::um::fileapi::LockFileEx;

0 commit comments

Comments
 (0)