From da638b3a9f32974c41439be6834670d7a438faa3 Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Tue, 27 Sep 2022 11:50:47 -0700 Subject: [PATCH 1/3] Allow compiling the `wasm32-wasi` std library with atomics The issue #102157 demonstrates how currently the `-Z build-std` option will fail when re-compiling the standard library with `RUSTFLAGS` like `RUSTFLAGS="-C target-feature=+atomics,+bulk-memory -C link-args=--shared-memory"`. This change attempts to resolve those build issues by depending on the the WebAssembly `futex` module and providing an implementation for `env_lock`. Fixes #102157. --- library/std/src/sys/wasi/mod.rs | 3 +++ library/std/src/sys/wasi/os.rs | 11 ++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/library/std/src/sys/wasi/mod.rs b/library/std/src/sys/wasi/mod.rs index 683a07a34dcf9..c8c47763a340b 100644 --- a/library/std/src/sys/wasi/mod.rs +++ b/library/std/src/sys/wasi/mod.rs @@ -25,6 +25,9 @@ pub mod cmath; pub mod env; pub mod fd; pub mod fs; +#[allow(unused)] +#[path = "../wasm/atomics/futex.rs"] +pub mod futex; pub mod io; #[path = "../unsupported/locks/mod.rs"] pub mod locks; diff --git a/library/std/src/sys/wasi/os.rs b/library/std/src/sys/wasi/os.rs index cab2887dfcf14..b340061cb3d10 100644 --- a/library/std/src/sys/wasi/os.rs +++ b/library/std/src/sys/wasi/os.rs @@ -24,10 +24,15 @@ mod libc { } } -#[cfg(not(target_feature = "atomics"))] pub unsafe fn env_lock() -> impl Any { - // No need for a lock if we're single-threaded, but this function will need - // to get implemented for multi-threaded scenarios + cfg_if::cfg_if! { + if #[cfg(target_feature = "atomics")] { + todo!() + } else { + // No need for a lock if we're single-threaded, but this function will need + // to get implemented for multi-threaded scenarios + } + } } pub fn errno() -> i32 { From 9530ba0fe2118d9a60e16861faad29ec5803d3f9 Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Thu, 29 Sep 2022 11:17:15 -0700 Subject: [PATCH 2/3] Implement `env_lock` with `RwLock` Copying the approach of the Unix target, this change uses the standard `RwLock` to protect against concurrent access of libc's environment. This locking is only enabled when WebAssembly's `atomics` feature is also enabled. --- library/std/src/sys/wasi/os.rs | 35 ++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/library/std/src/sys/wasi/os.rs b/library/std/src/sys/wasi/os.rs index b340061cb3d10..cffe1e32308b6 100644 --- a/library/std/src/sys/wasi/os.rs +++ b/library/std/src/sys/wasi/os.rs @@ -1,11 +1,11 @@ #![deny(unsafe_op_in_unsafe_fn)] -use crate::any::Any; use crate::error::Error as StdError; use crate::ffi::{CStr, OsStr, OsString}; use crate::fmt; use crate::io; use crate::marker::PhantomData; +use crate::ops::Drop; use crate::os::wasi::prelude::*; use crate::path::{self, PathBuf}; use crate::str; @@ -24,13 +24,24 @@ mod libc { } } -pub unsafe fn env_lock() -> impl Any { - cfg_if::cfg_if! { - if #[cfg(target_feature = "atomics")] { - todo!() - } else { - // No need for a lock if we're single-threaded, but this function will need - // to get implemented for multi-threaded scenarios +cfg_if::cfg_if! { + if #[cfg(target_feature = "atomics")] { + // Access to the environment must be protected by a lock in multi-threaded scenarios. + use crate::sync::{PoisonError, RwLock}; + static ENV_LOCK: RwLock<()> = RwLock::new(()); + pub fn env_read_lock() -> impl Drop { + ENV_LOCK.read().unwrap_or_else(PoisonError::into_inner) + } + pub fn env_write_lock() -> impl Drop { + ENV_LOCK.write().unwrap_or_else(PoisonError::into_inner) + } + } else { + // No need for a lock if we are single-threaded. + pub fn env_read_lock() -> impl Drop { + () + } + pub fn env_write_lock() -> impl Drop { + () } } } @@ -149,7 +160,7 @@ impl Iterator for Env { pub fn env() -> Env { unsafe { - let _guard = env_lock(); + let _guard = env_read_lock(); let mut environ = libc::environ; let mut result = Vec::new(); if !environ.is_null() { @@ -180,7 +191,7 @@ pub fn env() -> Env { pub fn getenv(k: &OsStr) -> Option { let s = run_with_cstr(k.as_bytes(), |k| unsafe { - let _guard = env_lock(); + let _guard = env_read_lock(); Ok(libc::getenv(k.as_ptr()) as *const libc::c_char) }) .ok()?; @@ -194,7 +205,7 @@ pub fn getenv(k: &OsStr) -> Option { pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { run_with_cstr(k.as_bytes(), |k| { run_with_cstr(v.as_bytes(), |v| unsafe { - let _guard = env_lock(); + let _guard = env_write_lock(); cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(drop) }) }) @@ -202,7 +213,7 @@ pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { pub fn unsetenv(n: &OsStr) -> io::Result<()> { run_with_cstr(n.as_bytes(), |nbuf| unsafe { - let _guard = env_lock(); + let _guard = env_write_lock(); cvt(libc::unsetenv(nbuf.as_ptr())).map(drop) }) } From 95b0b2d34956c232ace714c1f5971b20e2767c6c Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Tue, 11 Oct 2022 11:42:44 -0700 Subject: [PATCH 3/3] fix: return type of single-threaded dummy lock must be droppable --- library/std/src/sys/wasi/os.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/wasi/os.rs b/library/std/src/sys/wasi/os.rs index cffe1e32308b6..f5513e9996d40 100644 --- a/library/std/src/sys/wasi/os.rs +++ b/library/std/src/sys/wasi/os.rs @@ -38,10 +38,10 @@ cfg_if::cfg_if! { } else { // No need for a lock if we are single-threaded. pub fn env_read_lock() -> impl Drop { - () + Box::new(()) } pub fn env_write_lock() -> impl Drop { - () + Box::new(()) } } }