1
Fork 0

Rollup merge of #139711 - thaliaarchi:hermit-args, r=jhpratt

Hermit: Unify `std::env::args` with Unix

The only differences between these implementations of `std::env::args` are that Unix uses relaxed ordering, but Hermit uses acquire/release, and Unix truncates `argv` at the first null pointer, but Hermit doesn't. Since Hermit aims for Unix compatibility, unify it with Unix.

The atomic orderings were established in https://github.com/rust-lang/rust/pull/74006 (cc `@euclio)` for Unix and https://github.com/rust-lang/rust/pull/100579 (cc `@joboet)` for Hermit and, before those, they used mutexes and non-atomic statics. I think the difference in orderings is simply from them being changed at different times. The commented explanation for using acquire/release for Hermit is “to broadcast writes by the OS”. I'm not experienced enough with atomics to accurately judge, but I think acquire/release is stronger than needed. Either way, they should match.

Truncating at the first null pointer seems desirable, though I don't know whether it is necessary in practice on Hermit.

cc `@mkroening` `@stlankes` for Hermit
This commit is contained in:
Chris Denton 2025-04-21 18:53:16 +00:00 committed by GitHub
commit 5779843eda
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 9 additions and 40 deletions

View file

@ -1,35 +0,0 @@
use crate::ffi::{CStr, OsString, c_char};
use crate::os::hermit::ffi::OsStringExt;
use crate::ptr;
use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release};
use crate::sync::atomic::{AtomicIsize, AtomicPtr};
#[path = "common.rs"]
mod common;
pub use common::Args;
static ARGC: AtomicIsize = AtomicIsize::new(0);
static ARGV: AtomicPtr<*const u8> = AtomicPtr::new(ptr::null_mut());
/// One-time global initialization.
pub unsafe fn init(argc: isize, argv: *const *const u8) {
ARGC.store(argc, Relaxed);
// Use release ordering here to broadcast writes by the OS.
ARGV.store(argv as *mut *const u8, Release);
}
/// Returns the command line arguments
pub fn args() -> Args {
// Synchronize with the store above.
let argv = ARGV.load(Acquire);
// If argv has not been initialized yet, do not return any arguments.
let argc = if argv.is_null() { 0 } else { ARGC.load(Relaxed) };
let args: Vec<OsString> = (0..argc)
.map(|i| unsafe {
let cstr = CStr::from_ptr(*argv.offset(i) as *const c_char);
OsStringExt::from_vec(cstr.to_bytes().to_vec())
})
.collect();
Args::new(args)
}

View file

@ -3,15 +3,15 @@
#![forbid(unsafe_op_in_unsafe_fn)] #![forbid(unsafe_op_in_unsafe_fn)]
cfg_if::cfg_if! { cfg_if::cfg_if! {
if #[cfg(all(target_family = "unix", not(any(target_os = "espidf", target_os = "vita"))))] { if #[cfg(any(
all(target_family = "unix", not(any(target_os = "espidf", target_os = "vita"))),
target_os = "hermit",
))] {
mod unix; mod unix;
pub use unix::*; pub use unix::*;
} else if #[cfg(target_family = "windows")] { } else if #[cfg(target_family = "windows")] {
mod windows; mod windows;
pub use windows::*; pub use windows::*;
} else if #[cfg(target_os = "hermit")] {
mod hermit;
pub use hermit::*;
} else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] { } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
mod sgx; mod sgx;
pub use sgx::*; pub use sgx::*;

View file

@ -6,6 +6,9 @@
#![allow(dead_code)] // runtime init functions not used during testing #![allow(dead_code)] // runtime init functions not used during testing
use crate::ffi::CStr; use crate::ffi::CStr;
#[cfg(target_os = "hermit")]
use crate::os::hermit::ffi::OsStringExt;
#[cfg(not(target_os = "hermit"))]
use crate::os::unix::ffi::OsStringExt; use crate::os::unix::ffi::OsStringExt;
#[path = "common.rs"] #[path = "common.rs"]
@ -73,6 +76,7 @@ pub fn args() -> Args {
target_os = "illumos", target_os = "illumos",
target_os = "emscripten", target_os = "emscripten",
target_os = "haiku", target_os = "haiku",
target_os = "hermit",
target_os = "l4re", target_os = "l4re",
target_os = "fuchsia", target_os = "fuchsia",
target_os = "redox", target_os = "redox",
@ -100,7 +104,7 @@ mod imp {
unsafe fn really_init(argc: isize, argv: *const *const u8) { unsafe fn really_init(argc: isize, argv: *const *const u8) {
// These don't need to be ordered with each other or other stores, // These don't need to be ordered with each other or other stores,
// because they only hold the unmodified system-provide argv/argc. // because they only hold the unmodified system-provided argv/argc.
ARGC.store(argc, Ordering::Relaxed); ARGC.store(argc, Ordering::Relaxed);
ARGV.store(argv as *mut _, Ordering::Relaxed); ARGV.store(argv as *mut _, Ordering::Relaxed);
} }