pub struct Domain<F> { /* private fields */ }
Expand description
Synchronization point between hazard pointers and the writers they guard against.
Every hazard pointer is associated with a domain, and can only guard
against reclamation of objects that are retired through that same domain. In other words, you
should always ensure that your code uses the same domain to retire objects as it uses to make
hazard pointers to read those objects. If it does not, the hazard pointers will provide no
meaningful protection. This connection is part of the safety contract for
HazardPointer::load
.
Domain families
To help aid in determining that the same domain is used for loads and stores, every domain has
an associated domain family (F
). The family serves no purpose beyond adding a statically
checked guide so that obviously-incompatible domains aren’t used. To take advantage of it, your
code should define a new zero-sized type that you use every F
appears, like so:
#[non_exhaustive]
struct Family;
type Domain = haphazard::Domain<Family>;
type HazardPointer<'domain> = haphazard::HazardPointer<'domain, Family>;
type AtomicPtr<T> = haphazard::AtomicPtr<T, Family>;
This ensures at compile-time that you don’t, for example, use a
HazardPointer
from the global domain to guard loads from an
AtomicPtr
that is tied to a custom domain.
This isn’t bullet-proof though! Nothing prevents you from using hazard pointers allocated from
one instance of Domain<Family>
with an atomic pointer whose writers use a different
instance of Domin<Family>
. So be careful!
The unique_domain
macro provides a mechanism for constructing a domain with a unique
domain family that cannot be confused with any other. If you can use it, you should do so, as
it gives stronger static guarantees. However, it has the downside that you cannot name the
return type (at least without impl Trait in type
aliases), which makes it difficult to store in
other types.
Reclamation
Domains are the coordination mechanism used for reclamation. When an object is retired into a
domain, the retiring thread will (sometimes) scan the domain for objects that are now safe to
reclaim (i.e., drop). Objects that cannot yet be reclaimed because there are active readers are
left in the domain for a later retire to check again. This means that there is generally a
delay between when an object is retired (i.e., marked as deleted) and when it is actually
reclaimed (i.e., drop
is called). And if there are no more retires, the
objects may not be reclaimed until the owning domain is itself dropped.
When using the global domain to guard data access in your data structure, keep in
mind that there is no guarantee that retired objects will be cleaned up by the time your data
structure is dropped. As a result, you may need to require that the data you store in said data
structure be 'static
. If you wish to avoid that bound, you’ll need to construct your own
Domain
for each instance of your data structure so that all the guarded data is reclaimed
when your data structure is dropped.
Implementations
sourceimpl Domain<Global>
impl Domain<Global>
sourcepub fn global() -> &'static Self
pub fn global() -> &'static Self
Get a handle to the singleton global domain.
sourceimpl<F> Domain<F>
impl<F> Domain<F>
sourcepub const fn new(_: &F) -> Self
pub const fn new(_: &F) -> Self
Construct a new domain with the given family type.
The type checker protects you from accidentally using a HazardPointer
from one domain
family (the type F
) with an object protected by a domain in a different family.
However, it does not protect you from mixing up domains with the same family type.
Therefore, prefer creating domains with unique_domain
where possible, since it
guarantees a unique F
for every domain.
See the Domain
documentation for more details.
sourcepub unsafe fn retire_ptr<T, P>(&self, ptr: *mut T) -> usize where
T: Send,
P: Pointer<T>,
pub unsafe fn retire_ptr<T, P>(&self, ptr: *mut T) -> usize where
T: Send,
P: Pointer<T>,
Retire ptr
, and reclaim it once it is safe to do so.
T
must be Send
since it may be reclaimed by a different thread.
Safety
- no [
HazardPointer
] will guardptr
from this point forward. ptr
has not already been retired unless it has been reclaimed since then.ptr
is valid as&T
untilself
is dropped.
sourcepub fn eager_reclaim(&self) -> usize
pub fn eager_reclaim(&self) -> usize
Reclaim as many retired objects as possible.
Returns the number of retired objects that were reclaimed.
Trait Implementations
Auto Trait Implementations
impl<F> RefUnwindSafe for Domain<F> where
F: RefUnwindSafe,
impl<F> Send for Domain<F> where
F: Send,
impl<F> Sync for Domain<F> where
F: Sync,
impl<F> Unpin for Domain<F> where
F: Unpin,
impl<F> !UnwindSafe for Domain<F>
Blanket Implementations
sourceimpl<T> BorrowMut<T> for T where
T: ?Sized,
impl<T> BorrowMut<T> for T where
T: ?Sized,
const: unstable · sourcefn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more