Rollup merge of #146269 - weihanglo:solaris-flock, r=Mark-Simulacrum

feat(std): emulate flock for solaris via fcntl

Upstream Solaris flock emulation to libstd from cargo.

This is borrowed from
3b379fcc54/src/cargo/util/flock.rs (L502-L536) which was implemented by an Oracle employee.
The code has been in cargo since 2022-12.

Python's `fcntl.flock` emulates like this as well: c919d02ede/Modules/fcntlmodule.c (L337-L400)

We did the same thing in
0d0f4eac8b/compiler/rustc_data_structures/src/flock/unix.rs (L13-L39)

However, should we just always falls back to fcntl for all Unix, instead of "unsupported"?

try-job: `*-solaris`
This commit is contained in:
Matthias Krüger 2025-09-07 20:02:28 +02:00 committed by GitHub
commit e4e4829579
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 70 additions and 0 deletions

View file

@ -226,6 +226,7 @@ fn file_test_io_seek_and_write() {
target_os = "freebsd",
target_os = "linux",
target_os = "netbsd",
target_os = "solaris",
target_vendor = "apple",
))]
fn file_lock_multiple_shared() {
@ -249,6 +250,7 @@ fn file_lock_multiple_shared() {
target_os = "freebsd",
target_os = "linux",
target_os = "netbsd",
target_os = "solaris",
target_vendor = "apple",
))]
fn file_lock_blocking() {
@ -273,6 +275,7 @@ fn file_lock_blocking() {
target_os = "freebsd",
target_os = "linux",
target_os = "netbsd",
target_os = "solaris",
target_vendor = "apple",
))]
fn file_lock_drop() {
@ -294,6 +297,7 @@ fn file_lock_drop() {
target_os = "freebsd",
target_os = "linux",
target_os = "netbsd",
target_os = "solaris",
target_vendor = "apple",
))]
fn file_lock_dup() {

View file

@ -1293,6 +1293,15 @@ impl File {
return Ok(());
}
#[cfg(target_os = "solaris")]
pub fn lock(&self) -> io::Result<()> {
let mut flock: libc::flock = unsafe { mem::zeroed() };
flock.l_type = libc::F_WRLCK as libc::c_short;
flock.l_whence = libc::SEEK_SET as libc::c_short;
cvt(unsafe { libc::fcntl(self.as_raw_fd(), libc::F_SETLKW, &flock) })?;
Ok(())
}
#[cfg(not(any(
target_os = "freebsd",
target_os = "fuchsia",
@ -1300,6 +1309,7 @@ impl File {
target_os = "netbsd",
target_os = "openbsd",
target_os = "cygwin",
target_os = "solaris",
target_vendor = "apple",
)))]
pub fn lock(&self) -> io::Result<()> {
@ -1320,6 +1330,15 @@ impl File {
return Ok(());
}
#[cfg(target_os = "solaris")]
pub fn lock_shared(&self) -> io::Result<()> {
let mut flock: libc::flock = unsafe { mem::zeroed() };
flock.l_type = libc::F_RDLCK as libc::c_short;
flock.l_whence = libc::SEEK_SET as libc::c_short;
cvt(unsafe { libc::fcntl(self.as_raw_fd(), libc::F_SETLKW, &flock) })?;
Ok(())
}
#[cfg(not(any(
target_os = "freebsd",
target_os = "fuchsia",
@ -1327,6 +1346,7 @@ impl File {
target_os = "netbsd",
target_os = "openbsd",
target_os = "cygwin",
target_os = "solaris",
target_vendor = "apple",
)))]
pub fn lock_shared(&self) -> io::Result<()> {
@ -1355,6 +1375,23 @@ impl File {
}
}
#[cfg(target_os = "solaris")]
pub fn try_lock(&self) -> Result<(), TryLockError> {
let mut flock: libc::flock = unsafe { mem::zeroed() };
flock.l_type = libc::F_WRLCK as libc::c_short;
flock.l_whence = libc::SEEK_SET as libc::c_short;
let result = cvt(unsafe { libc::fcntl(self.as_raw_fd(), libc::F_SETLK, &flock) });
if let Err(err) = result {
if err.kind() == io::ErrorKind::WouldBlock {
Err(TryLockError::WouldBlock)
} else {
Err(TryLockError::Error(err))
}
} else {
Ok(())
}
}
#[cfg(not(any(
target_os = "freebsd",
target_os = "fuchsia",
@ -1362,6 +1399,7 @@ impl File {
target_os = "netbsd",
target_os = "openbsd",
target_os = "cygwin",
target_os = "solaris",
target_vendor = "apple",
)))]
pub fn try_lock(&self) -> Result<(), TryLockError> {
@ -1393,6 +1431,23 @@ impl File {
}
}
#[cfg(target_os = "solaris")]
pub fn try_lock_shared(&self) -> Result<(), TryLockError> {
let mut flock: libc::flock = unsafe { mem::zeroed() };
flock.l_type = libc::F_RDLCK as libc::c_short;
flock.l_whence = libc::SEEK_SET as libc::c_short;
let result = cvt(unsafe { libc::fcntl(self.as_raw_fd(), libc::F_SETLK, &flock) });
if let Err(err) = result {
if err.kind() == io::ErrorKind::WouldBlock {
Err(TryLockError::WouldBlock)
} else {
Err(TryLockError::Error(err))
}
} else {
Ok(())
}
}
#[cfg(not(any(
target_os = "freebsd",
target_os = "fuchsia",
@ -1400,6 +1455,7 @@ impl File {
target_os = "netbsd",
target_os = "openbsd",
target_os = "cygwin",
target_os = "solaris",
target_vendor = "apple",
)))]
pub fn try_lock_shared(&self) -> Result<(), TryLockError> {
@ -1423,6 +1479,15 @@ impl File {
return Ok(());
}
#[cfg(target_os = "solaris")]
pub fn unlock(&self) -> io::Result<()> {
let mut flock: libc::flock = unsafe { mem::zeroed() };
flock.l_type = libc::F_UNLCK as libc::c_short;
flock.l_whence = libc::SEEK_SET as libc::c_short;
cvt(unsafe { libc::fcntl(self.as_raw_fd(), libc::F_SETLKW, &flock) })?;
Ok(())
}
#[cfg(not(any(
target_os = "freebsd",
target_os = "fuchsia",
@ -1430,6 +1495,7 @@ impl File {
target_os = "netbsd",
target_os = "openbsd",
target_os = "cygwin",
target_os = "solaris",
target_vendor = "apple",
)))]
pub fn unlock(&self) -> io::Result<()> {