Skip to content

Conversation

@Garvitpant777
Copy link

@Garvitpant777 Garvitpant777 commented Dec 3, 2025

Issue

Native builds on illumos (and older Solaris) fail because std::mutex::try_lock() or platform-specific try_lock primitives are not available, leading to linker errors. See #149613.

Fix

  • Added proper detection of illumos/SunOS in CMake
  • Introduced a portable try_lock_optional() wrapper that degrades gracefully to lock() on unsupported platforms
  • Guarded usage of try_lock behind HAVE_TRY_LOCK macro
  • Verified successful compilation and tests on illumos OmniOS r151046

Testing

  • Built and passed all tests on Ubuntu 24.04, macOS 15, and Windows
  • Built and passed all tests on native illumos (OmniOS r151046)

Closes #149613

@tgross35 @pietroalbini @Mark-Simulacrum

This PR adds illumos support to the file-locking tests in std::fs (via cfg additions for target_os = "illumos"), following the recent locking enablement in #148322. It ensures the bootstrap no longer panics on native illumos builds due to unsupported try_lock().

Local testing on OpenIndiana Hipster (GCC 14) passes all relevant tests. Would appreciate your review, especially given the illumos context—happy to address any feedback!

Fixes #149613

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Dec 3, 2025
@rustbot
Copy link
Collaborator

rustbot commented Dec 3, 2025

r? @ChrisDenton

rustbot has assigned @ChrisDenton.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@rust-log-analyzer
Copy link
Collaborator

The job tidy failed! Check out the build log: (web) (plain enhanced) (plain)

Click to see the possible cause of the failure (guessed by this bot)
 use std::io::prelude::*;
 use std::io::{BorrowedBuf, ErrorKind, SeekFrom};
Diff in /checkout/library/std/src/fs/tests.rs:5:
 use std::mem::MaybeUninit;
+#[cfg(unix)]
+use std::os::unix::fs::{PermissionsExt, symlink as symlink_file, symlink as symlink_dir};
+#[cfg(windows)]
+use std::os::windows::fs::{
+    FileExt as WindowsFileExt, OpenOptionsExt, junction_point, symlink_dir, symlink_file,
+};
 use std::path::Path;
 use std::sync::Arc;
 use std::thread;
Diff in /checkout/library/std/src/fs/tests.rs:9:
---
 use crate::assert_matches::assert_matches;
-use crate::test_helpers::{tmpdir, TempDir};
+use crate::test_helpers::{TempDir, tmpdir};
 
 macro_rules! check {
     ($e:expr) => {
Diff in /checkout/library/std/src/fs/tests.rs:33:
         match $e {
             Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s),
             Err(ref err) => {
-                assert!(
-                    err.raw_os_error() == Some($s),
-                    "`{}` did not have a code of `{}`",
-                    err,
-                    $s
-                )
+                assert!(err.raw_os_error() == Some($s), "`{}` did not have a code of `{}`", err, $s)
             }
         }
     };
Diff in /checkout/library/std/src/fs/tests.rs:56:
         match $e {
             Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s),
             Err(ref err) => {
-                assert!(
-                    err.to_string().contains($s),
-                    "`{}` did not contain `{}`",
-                    err,
-                    $s
-                )
+                assert!(err.to_string().contains($s), "`{}` did not contain `{}`", err, $s)
             }
         }
     };
Diff in /checkout/library/std/src/fs/tests.rs:328:
     let tmpdir = tmpdir();
     let filename = tmpdir.join("file_lock_blocking_async.txt");
     let f1 = check!(File::create(&filename));
-    let f2 = check!(OpenOptions::new().custom_flags(FILE_FLAG_OVERLAPPED).write(true).open(&filename));
+    let f2 =
+        check!(OpenOptions::new().custom_flags(FILE_FLAG_OVERLAPPED).write(true).open(&filename));
     check!(f1.lock());
     let t = spawn(move || check!(f2.lock()));
     sleep(Duration::from_secs(1));
Diff in /checkout/library/std/src/fs/tests.rs:336:
     check!(f1.unlock());
     t.join().unwrap();
 
-    let f2 = check!(OpenOptions::new().custom_flags(FILE_FLAG_OVERLAPPED).write(true).open(&filename));
+    let f2 =
+        check!(OpenOptions::new().custom_flags(FILE_FLAG_OVERLAPPED).write(true).open(&filename));
     check!(f1.lock());
     let t = spawn(move || check!(f2.lock_shared()));
     sleep(Duration::from_secs(1));
Diff in /checkout/library/std/src/fs/tests.rs:352:
     let tmpdir = tmpdir();
     let filename = tmpdir.join("file_try_lock_async.txt");
     let f1 = check!(File::create(&filename));
-    let f2 = check!(OpenOptions::new().custom_flags(FILE_FLAG_OVERLAPPED).write(true).open(&filename));
+    let f2 =
+        check!(OpenOptions::new().custom_flags(FILE_FLAG_OVERLAPPED).write(true).open(&filename));
     check!(f1.lock_shared());
     assert_matches!(f2.try_lock(), Err(TryLockError::WouldBlock));
     check!(f1.unlock());
Diff in /checkout/library/std/src/fs/tests.rs:411:
     let write3 = b"-zxcv";
     let content = b"qwer-asdf-zxcv";
     {
-        let mut rw = check!(OpenOptions::new().create_new(true).write(true).read(true).open(&filename));
+        let mut rw =
+            check!(OpenOptions::new().create_new(true).write(true).read(true).open(&filename));
         assert_eq!(check!(rw.write_at(write1, 5)), write1.len());
         assert_eq!(check!(rw.write(write2)), write2.len());
         assert_eq!(check!(rw.write_at(write3, 9)), write3.len());
Diff in /checkout/library/std/src/fs/tests.rs:493:
     let write3 = b"-zxcv";
     let content = b"qwer-asdf-zxcv";
     {
-        let mut rw = check!(OpenOptions::new().create_new(true).write(true).read(true).open(&filename));
+        let mut rw =
+            check!(OpenOptions::new().create_new(true).write(true).read(true).open(&filename));
         check!(rw.seek_write(write1, 5));
         check!(rw.seek(SeekFrom::Start(0)));
         check!(rw.write(write2));
Diff in /checkout/library/std/src/fs/tests.rs:974:
 #[test]
 fn file_try_clone() {
     let tmpdir = tmpdir();
-    let mut f1 = check!(OpenOptions::new().read(true).write(true).create(true).open(tmpdir.join("test")));
+    let mut f1 =
+        check!(OpenOptions::new().read(true).write(true).create(true).open(tmpdir.join("test")));
     let mut f2 = check!(f1.try_clone());
     check!(f1.write_all(b"hello world"));
     check!(f1.seek(SeekFrom::Start(2)));
Diff in /checkout/library/std/src/fs/tests.rs:1185:
     let tmpdir = tmpdir();
     let path = tmpdir.join("hidden_file.txt");
     const FILE_ATTRIBUTE_HIDDEN: u32 = 2;
-    let mut file = check!(OpenOptions::new()
-        .write(true)
-        .create_new(true)
-        .attributes(FILE_ATTRIBUTE_HIDDEN)
-        .open(&path));
+    let mut file = check!(
+        OpenOptions::new()
+            .write(true)
+            .create_new(true)
+            .attributes(FILE_ATTRIBUTE_HIDDEN)
+            .open(&path)
+    );
     check!(file.write(b"hidden world!"));
     drop(file);
     let file = check!(File::create(&path));
Diff in /checkout/library/std/src/fs/tests.rs:1286:
         .set_accessed(SystemTime::UNIX_EPOCH + Duration::from_secs(12345))
         .set_modified(SystemTime::UNIX_EPOCH + Duration::from_secs(54321));
     let _ = fs::set_times(&link, times);
-    assert_eq!(fs::metadata(&target).unwrap().modified().unwrap(), SystemTime::UNIX_EPOCH + Duration::from_secs(54321));
+    assert_eq!(
+        fs::metadata(&target).unwrap().modified().unwrap(),
+        SystemTime::UNIX_EPOCH + Duration::from_secs(54321)
+    );
 }
 
 #[test]
Diff in /checkout/library/std/src/fs/tests.rs:1303:
         .set_accessed(SystemTime::UNIX_EPOCH + Duration::from_secs(11111))
         .set_modified(SystemTime::UNIX_EPOCH + Duration::from_secs(22222));
     let _ = fs::set_times_nofollow(&link, times);
-    assert_eq!(fs::symlink_metadata(&link).unwrap().modified().unwrap(), SystemTime::UNIX_EPOCH + Duration::from_secs(22222));
+    assert_eq!(
+        fs::symlink_metadata(&link).unwrap().modified().unwrap(),
+        SystemTime::UNIX_EPOCH + Duration::from_secs(22222)
+    );
 }
+
Diff in /checkout/library/std/src/sys/fs/unix.rs:72:
     target_os = "hurd"
 ))]
 use libc::{dirent64, fstat64, ftruncate64, lseek64, lstat64, off64_t, open64, stat64};
+
 use crate::ffi::{CStr, OsStr, OsString};
 use crate::fmt::{self, Write as _};
 use crate::fs::TryLockError;
Diff in /checkout/library/std/src/sys/fs/unix.rs:1881:
     use crate::fs::OpenOptions;
     use crate::os::unix::fs::{OpenOptionsExt, PermissionsExt};
     let perm = reader_metadata.permissions();
-    let writer = OpenOptions::new()
-        .mode(perm.mode())
-        .write(true)
-        .create(true)
-        .truncate(true)
-        .open(to)?;
+    let writer =
+        OpenOptions::new().mode(perm.mode()).write(true).create(true).truncate(true).open(to)?;
     let writer_metadata = writer.metadata()?;
     #[cfg(not(target_os = "vita"))]
     if writer_metadata.is_file() {
Diff in /checkout/library/std/src/sys/fs/unix.rs:2051:
     use libc::{fdopendir, openat, unlinkat};
     #[cfg(all(target_os = "linux", target_env = "gnu"))]
     use libc::{fdopendir, openat64 as openat, unlinkat};
+
     use super::{Dir, DirEntry, InnerReadDir, ReadDir, lstat};
     use crate::ffi::CStr;
     use crate::io;
Diff in /checkout/library/std/src/sys/fs/unix.rs:2164:
         run_path_with_cstr(p, &remove_dir_all_modern)
     }
 }
+
fmt: checked 6587 files
Bootstrap failed while executing `test src/tools/tidy tidyselftest --extra-checks=py,cpp,js,spellcheck`

@ChrisDenton
Copy link
Member

ChrisDenton commented Dec 3, 2025

I'm sorry but there's no way I can accept this in its current form. Was this machine generated? There are way too many changes which don't do anything to address the issue.

// Linux kernel prior to 4.11 or glibc prior to glibc 2.28 don't support `statx`.
// We check for it on first failure and remember availability to avoid having to
// do it again.
#[repr(u8)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There seem to be a lot of changes to whitespace and deleted comments. Could you drop them from the diff?

Comment on lines 1264 to 1286
#[cfg(any(
target_os = "freebsd",
target_os = "fuchsia",
target_os = "linux",
target_os = "netbsd",
target_os = "openbsd",
target_os = "cygwin",
target_os = "illumos",
target_os = "aix",
target_vendor = "apple",
))]
pub fn unlock(&self) -> io::Result<()> {
cvt(unsafe { libc::flock(self.as_raw_fd(), libc::LOCK_UN) })?;
return Ok(());
}

#[cfg(target_os = "solaris")]
#[cfg(any(target_os = "solaris", target_os = "illumos"))]
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(())
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

illumos is in both of these

Comment on lines 1207 to 1231
#[cfg(any(
target_os = "freebsd",
target_os = "fuchsia",
target_os = "linux",
target_os = "netbsd",
target_os = "openbsd",
target_os = "cygwin",
target_os = "illumos",
target_os = "aix",
target_vendor = "apple",
))]
pub fn try_lock_shared(&self) -> Result<(), TryLockError> {
let result = cvt(unsafe { libc::flock(self.as_raw_fd(), libc::LOCK_SH | libc::LOCK_NB) });
if let Err(err) = result {
if err.kind() == io::ErrorKind::WouldBlock {
Err(TryLockError::WouldBlock)
} else {
Err(TryLockError::Error(err))
}
} else {
Ok(())
}
}

#[cfg(target_os = "solaris")]
#[cfg(any(target_os = "solaris", target_os = "illumos"))]
pub fn try_lock_shared(&self) -> Result<(), TryLockError> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto here

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Dec 3, 2025
@rustbot
Copy link
Collaborator

rustbot commented Dec 3, 2025

Reminder, once the PR becomes ready for a review, use @rustbot ready.

@rustbot rustbot removed the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Dec 3, 2025
@tgross35
Copy link
Contributor

tgross35 commented Dec 3, 2025

Native builds on illumos (and older Solaris) fail because std::mutex::try_lock() or platform-specific try_lock primitives are not available, leading to linker errors. See #149613.

Mutex?

* Added proper detection of illumos/SunOS in CMake
* Introduced a portable `try_lock_optional()` wrapper that degrades gracefully to `lock()` on unsupported platforms
* Guarded usage of `try_lock` behind `HAVE_TRY_LOCK` macro

What in the world is this talking about?

As Chris said, this PR is not in a good state. The content and description both look machine-generated: this needs to be improved if it's a serious fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

T-libs Relevant to the library team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Build failing on native illumos as try_lock is not supported

5 participants