From ff5f0e7c32bcf1322bef45e0ed216d63fc0c58a8 Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Sat, 13 Jul 2024 22:30:25 -0700 Subject: [PATCH] `struct DisjointMut`: `unsafe impl Send + Sync`. --- src/disjoint_mut.rs | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/disjoint_mut.rs b/src/disjoint_mut.rs index 0a82b9201..3ecc8c437 100644 --- a/src/disjoint_mut.rs +++ b/src/disjoint_mut.rs @@ -48,6 +48,40 @@ pub struct DisjointMut { inner: UnsafeCell, } +/// SAFETY: If `T: `[`Send`], then sending [`DisjointMut`]`` across threads is safe. +/// There is no non-[`Sync`] state that is left on another thread +/// when [`DisjointMut`] gets sent to another thread. +/// When `&`[`DisjointMut`] gets sent to another thread, +/// that's a different story and justified below for the `unsafe impl Sync`. +unsafe impl Send for DisjointMut {} + +/// SAFETY: [`DisjointMut`] only provides disjoint mutable access +/// to `T`'s elements through a shared `&`[`DisjointMut`]`` reference. +/// Thus, sharing/[`Send`]ing a `&`[`DisjointMut`]`` across threads is safe. +/// +/// More precisely, `&`[`Self`] has the two core methods of +/// [`Self::index`] and [`Self::index_mut`] +/// that provide disjoint immutable and mutable access to `T`'s elements. +/// This disjointness guarantees that we do not create overlapping `&`s and `&mut`s, +/// which would be unsound and otherwise possible from multiple threads. +/// Furthermore, the safety guarantees of [`AsMutPtr::as_mut_ptr`] +/// ensure that no intermediary `&` or `&mut` references to `T`'s elements are created. +/// +/// The disjointness guarantee is checked at runtime in debug mode +/// (i.e. [`#[cfg(debug_assertions)]`]), while in release mode, +/// disjointness must be manually guaranteed. +/// This is less than ideal, but crucial for performance. +/// Since [`DisjointMut`] and [`disjoint_mut`](module@self) are only `pub(crate)`, +/// we can ensure all uses are disjoint and thus sound. +/// +/// Furthermore, all `T`s used have [`AsMutPtr::Target`]s +/// that are provenanceless, i.e. they have no internal references or pointers +/// or integers that hold pointer provenance. +/// Thus, a data race due the lack of runtime disjointness checking in release mode +/// would only result in wrong results, and cannot result in memory safety. +/// This is checked manually for now. +unsafe impl Sync for DisjointMut {} + impl DisjointMut { pub const fn new(value: T) -> Self { Self {