Skip to content

Commit 22f9a1d

Browse files
Rollup merge of rust-lang#157046 - RalfJung:file_lock_double_unlock, r=Mark-Simulacrum
file locking: clarify that double-locking is underspecified The 2nd commit fixes rust-lang#157045 by making the docs more clear.
2 parents b5e038d + 2c1d605 commit 22f9a1d

2 files changed

Lines changed: 39 additions & 16 deletions

File tree

library/std/src/fs.rs

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -815,18 +815,17 @@ impl File {
815815

816816
/// Acquire an exclusive lock on the file. Blocks until the lock can be acquired.
817817
///
818-
/// This acquires an exclusive lock; no other file handle to this file, in this or any other
818+
/// This acquires an exclusive lock. No *other* file handle to this file, in this or any other
819819
/// process, may acquire another lock.
820+
/// If this file handle/descriptor, or a clone of it, already holds a lock, the exact behavior
821+
/// is unspecified and platform dependent, including the possibility that it will deadlock.
822+
/// However, if this method returns, then an exclusive lock is held.
820823
///
821824
/// This lock may be advisory or mandatory. This lock is meant to interact with [`lock`],
822825
/// [`try_lock`], [`lock_shared`], [`try_lock_shared`], and [`unlock`]. Its interactions with
823826
/// other methods, such as [`read`] and [`write`] are platform specific, and it may or may not
824827
/// cause non-lockholders to block.
825828
///
826-
/// If this file handle/descriptor, or a clone of it, already holds a lock the exact behavior
827-
/// is unspecified and platform dependent, including the possibility that it will deadlock.
828-
/// However, if this method returns, then an exclusive lock is held.
829-
///
830829
/// If the file is not open for writing, it is unspecified whether this function returns an error.
831830
///
832831
/// The lock will be released when this file (along with any other file descriptors/handles
@@ -869,18 +868,18 @@ impl File {
869868

870869
/// Acquire a shared (non-exclusive) lock on the file. Blocks until the lock can be acquired.
871870
///
872-
/// This acquires a shared lock; more than one file handle, in this or any other process, may
873-
/// hold a shared lock, but none may hold an exclusive lock at the same time.
871+
/// This acquires a shared lock. More than one file handle to this file, in this or any other
872+
/// process, may hold a shared lock, but no *other* file handle may hold an exclusive lock at
873+
/// the same time.
874+
/// If this file handle/descriptor, or a clone of it, already holds a lock, the exact
875+
/// behavior is unspecified and platform dependent, including the possibility that it will
876+
/// deadlock. However, if this method returns, then a shared lock is held.
874877
///
875878
/// This lock may be advisory or mandatory. This lock is meant to interact with [`lock`],
876879
/// [`try_lock`], [`lock_shared`], [`try_lock_shared`], and [`unlock`]. Its interactions with
877880
/// other methods, such as [`read`] and [`write`] are platform specific, and it may or may not
878881
/// cause non-lockholders to block.
879882
///
880-
/// If this file handle/descriptor, or a clone of it, already holds a lock, the exact behavior
881-
/// is unspecified and platform dependent, including the possibility that it will deadlock.
882-
/// However, if this method returns, then a shared lock is held.
883-
///
884883
/// The lock will be released when this file (along with any other file descriptors/handles
885884
/// duplicated or inherited from it) is closed, or if the [`unlock`] method is called.
886885
///

library/std/src/fs/tests.rs

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -305,18 +305,42 @@ fn file_lock_dup() {
305305
}
306306

307307
#[test]
308-
#[cfg(windows)]
309-
fn file_lock_double_unlock() {
308+
#[cfg_attr(
309+
not(any(
310+
windows,
311+
target_os = "aix",
312+
target_os = "cygwin",
313+
target_os = "freebsd",
314+
target_os = "fuchsia",
315+
target_os = "hurd",
316+
target_os = "illumos",
317+
target_os = "linux",
318+
target_os = "netbsd",
319+
target_os = "openbsd",
320+
target_os = "solaris",
321+
target_vendor = "apple",
322+
)),
323+
should_panic
324+
)]
325+
fn file_lock_double() {
310326
let tmpdir = tmpdir();
311-
let filename = &tmpdir.join("file_lock_double_unlock_test.txt");
327+
let filename = &tmpdir.join("file_lock_double_test.txt");
312328
let f1 = check!(File::create(filename));
313329
let f2 = check!(OpenOptions::new().write(true).open(filename));
314330

315-
// On Windows a file handle may acquire both a shared and exclusive lock.
316-
// Check that both are released by unlock()
331+
// A file handle may acquire both a shared and exclusive lock.
317332
check!(f1.lock());
318333
check!(f1.lock_shared());
334+
// The behavior here differs between Windows and Unix: on Windows, f1 holds both locks;
335+
// on Unix, the lock got downgraded so f1 only holds the shared lock.
319336
assert_matches!(f2.try_lock(), Err(TryLockError::WouldBlock));
337+
if cfg!(windows) {
338+
assert_matches!(f2.try_lock_shared(), Err(TryLockError::WouldBlock));
339+
} else {
340+
check!(f2.try_lock_shared());
341+
check!(f2.unlock());
342+
}
343+
// Check that both are released by unlock().
320344
check!(f1.unlock());
321345
check!(f2.try_lock());
322346
}

0 commit comments

Comments
 (0)