From 3b1c742e23648260e60f87d67aa47e1f43d0cc0d Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Sat, 23 Nov 2019 17:07:31 +0100 Subject: [PATCH 1/4] Add as_mut_ptr method to atomic types. --- src/libcore/sync/atomic.rs | 62 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index d311cb16b64d3..5d6972bf75c79 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -802,6 +802,37 @@ impl AtomicBool { pub fn fetch_xor(&self, val: bool, order: Ordering) -> bool { unsafe { atomic_xor(self.v.get(), val as u8, order) != 0 } } + + /// Returns a mutable pointer to the underlying [`bool`]. + /// + /// Doing non-atomic reads and writes on the resulting integer can be a data race. + /// This method is mostly useful for FFI, where the function signature may use + /// `*mut bool` instead of `&AtomicBool`. + /// + /// [`bool`]: ../../../std/primitive.bool.html + /// + /// # Examples + /// + /// ```ignore (extern-declaration) + /// # fn main() { + /// use std::sync::atomic::AtomicBool; + /// extern { + /// fn my_atomic_op(arg: *mut bool); + /// } + /// + /// let mut atomic = AtomicBool::new(true); + /// unsafe { + /// my_atomic_op(atomic.as_mut_ptr()); + /// } + /// # } + /// ``` + #[inline] + #[unstable(feature = "atomic_mut_ptr", + reason = "recently added", + issue = "0")] + pub fn as_mut_ptr(&self) -> *mut bool { + self.v.get() as *mut bool + } } #[cfg(any(bootstrap, target_has_atomic_load_store = "ptr"))] @@ -1891,6 +1922,37 @@ assert_eq!(min_foo, 12); } } + doc_comment! { + concat!("Returns a mutable pointer to the underlying integer. + +Doing non-atomic reads and writes on the resulting integer can be a data race. +This method is mostly useful for FFI, where the function signature may use +`*mut ", stringify!($int_type), "` instead of `&", stringify!($atomic_type), "`. + +# Examples + +```ignore (extern-declaration) +# fn main() { +", $extra_feature, "use std::sync::atomic::", stringify!($atomic_type), "; + +extern { + fn my_atomic_op(arg: *mut ", stringify!($int_type), "); +} + +let mut atomic = ", stringify!($atomic_type), "::new(1); +unsafe { + my_atomic_op(atomic.as_mut_ptr()); +} +# } +```"), + #[inline] + #[unstable(feature = "atomic_mut_ptr", + reason = "recently added", + issue = "0")] + pub fn as_mut_ptr(&self) -> *mut $int_type { + self.v.get() + } + } } } } From 23c5e584e0ea40a6f630be0d4c5151b67ba96dd1 Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Sun, 24 Nov 2019 16:28:01 +0100 Subject: [PATCH 2/4] Use as_mut_ptr instead of casts --- src/libstd/lib.rs | 1 + src/libstd/sys/wasm/alloc.rs | 4 ++-- src/libstd/sys/wasm/condvar_atomics.rs | 2 +- src/libstd/sys/wasm/mutex_atomics.rs | 4 ++-- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 927fd2a6b0bc6..9846476388229 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -234,6 +234,7 @@ #![feature(allocator_internals)] #![feature(allow_internal_unsafe)] #![feature(allow_internal_unstable)] +#![feature(atomic_mut_ptr)] #![feature(arbitrary_self_types)] #![feature(array_error_internals)] #![feature(asm)] diff --git a/src/libstd/sys/wasm/alloc.rs b/src/libstd/sys/wasm/alloc.rs index c1af6ec12623c..05e55334ac008 100644 --- a/src/libstd/sys/wasm/alloc.rs +++ b/src/libstd/sys/wasm/alloc.rs @@ -67,7 +67,7 @@ mod lock { // // unsafe { // let r = core::arch::wasm32::i32_atomic_wait( - // &LOCKED as *const AtomicI32 as *mut i32, + // LOCKED.as_mut_ptr(), // 1, // expected value // -1, // timeout // ); @@ -143,7 +143,7 @@ mod lock { // // unsafe { // core::arch::wasm32::atomic_notify( - // &LOCKED as *const AtomicI32 as *mut i32, + // LOCKED.as_mut_ptr(), // 1, // only one thread // ); // } diff --git a/src/libstd/sys/wasm/condvar_atomics.rs b/src/libstd/sys/wasm/condvar_atomics.rs index 580d21218445f..f452bbd348787 100644 --- a/src/libstd/sys/wasm/condvar_atomics.rs +++ b/src/libstd/sys/wasm/condvar_atomics.rs @@ -89,6 +89,6 @@ impl Condvar { #[inline] fn ptr(&self) -> *mut i32 { assert_eq!(mem::size_of::(), mem::size_of::()); - &self.cnt as *const AtomicUsize as *mut i32 + self.cnt.as_mut_ptr() as *mut i32 } } diff --git a/src/libstd/sys/wasm/mutex_atomics.rs b/src/libstd/sys/wasm/mutex_atomics.rs index 0e4f3d80aa938..cddd584dd2207 100644 --- a/src/libstd/sys/wasm/mutex_atomics.rs +++ b/src/libstd/sys/wasm/mutex_atomics.rs @@ -56,7 +56,7 @@ impl Mutex { #[inline] fn ptr(&self) -> *mut i32 { assert_eq!(mem::size_of::(), mem::size_of::()); - &self.locked as *const AtomicUsize as *mut isize as *mut i32 + self.locked.as_mut_ptr() as *mut i32 } } @@ -145,6 +145,6 @@ impl ReentrantMutex { #[inline] fn ptr(&self) -> *mut i32 { - &self.owner as *const AtomicU32 as *mut i32 + self.owner.as_mut_ptr() as *mut i32 } } From 4843173a0015df5139866bffc3957c7782d8ccfe Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Sat, 30 Nov 2019 12:57:50 +0100 Subject: [PATCH 3/4] Document why as_mut_ptr is safe --- src/libcore/sync/atomic.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 5d6972bf75c79..3a5b4135a917c 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -809,6 +809,12 @@ impl AtomicBool { /// This method is mostly useful for FFI, where the function signature may use /// `*mut bool` instead of `&AtomicBool`. /// + /// Returning an `*mut` pointer from a shared reference to this atomic is safe because the + /// atomic types work with interior mutability. All modifications of an atomic change the value + /// through a shared reference, and can do so safely as long as they use atomic operations. Any + /// use of the returned raw pointer requires an `unsafe` block and still has to uphold the same + /// restriction: operations on it must be atomic. + /// /// [`bool`]: ../../../std/primitive.bool.html /// /// # Examples @@ -1929,6 +1935,12 @@ Doing non-atomic reads and writes on the resulting integer can be a data race. This method is mostly useful for FFI, where the function signature may use `*mut ", stringify!($int_type), "` instead of `&", stringify!($atomic_type), "`. +Returning an `*mut` pointer from a shared reference to this atomic is safe because the +atomic types work with interior mutability. All modifications of an atomic change the value +through a shared reference, and can do so safely as long as they use atomic operations. Any +use of the returned raw pointer requires an `unsafe` block and still has to uphold the same +restriction: operations on it must be atomic. + # Examples ```ignore (extern-declaration) From d34090a10a6517f3e3ea8528936175953ce8bc3d Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Sat, 30 Nov 2019 12:58:15 +0100 Subject: [PATCH 4/4] Fill tracking issue --- src/libcore/sync/atomic.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 3a5b4135a917c..9a910f3548577 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -835,7 +835,7 @@ impl AtomicBool { #[inline] #[unstable(feature = "atomic_mut_ptr", reason = "recently added", - issue = "0")] + issue = "66893")] pub fn as_mut_ptr(&self) -> *mut bool { self.v.get() as *mut bool } @@ -1960,7 +1960,7 @@ unsafe { #[inline] #[unstable(feature = "atomic_mut_ptr", reason = "recently added", - issue = "0")] + issue = "66893")] pub fn as_mut_ptr(&self) -> *mut $int_type { self.v.get() }