Struct lockfree::incin::Incinerator

source ·
pub struct Incinerator<T> { /* private fields */ }
Expand description

The incinerator. It is an API used to solve the infamous ABA problem. It basically consists of a counter and a list of garbage. Before a thread begins a suffering-from-ABA operation, it should start a new pause, and keep the incinerator paused while it is performing the operation.

When a thread wants to drop an allocation that might affect other threads with ABA problem or uses-after-free, it should add it to the incinerator’s garbage list. The incinerator will only execute the drop of its type T when the pause counter is zero.

When the incinerator is dropped, all the garbage is automatically dropped too.

C11 Implementation: https://gitlab.com/bzim/c11-incinerator/

Example

extern crate lockfree;

use lockfree::incin::Incinerator;
use std::{
    ptr::{null_mut, NonNull},
    sync::{
        atomic::{AtomicPtr, Ordering::*},
        Arc,
    },
    thread,
};

let incin = Arc::new(Incinerator::<Box<u128>>::new());
let ptr = Box::into_raw(Box::new(55u128));
let dummy_state = Arc::new(AtomicPtr::new(ptr));

let mut threads = Vec::with_capacity(16);

for i in 0 .. 16 {
    let state = dummy_state.clone();
    let incin = incin.clone();
    threads.push(thread::spawn(move || {
        let ptr = incin.pause_with(|_| {
            let loaded = state.load(SeqCst);
            let new = unsafe { *loaded + i };
            state.swap(Box::into_raw(Box::new(new)), SeqCst)
        });

        // dropping
        incin.add(unsafe { Box::from_raw(ptr) })
    }));
}

for thread in threads {
    thread.join().unwrap();
}

let boxed = unsafe { Box::from_raw(dummy_state.load(SeqCst)) };
assert!(*boxed <= 15 * 15);

Implementations

Creates a new incinerator, with no pauses and empty garbage list.

Increments the pause counter and creates a pause associated with this incinerator. Only after creating the pause you should perform atomic operations such as load and any other operation affected by ABA problem. This operation performs AcqRel on the pause counter.

Creates a pause before executing the given closure and resumes the incinerator only after executing the closure. You should execute the whole ABA-problem-suffering cycle of load and compare_and_swap inside the closure. See documentation for Incinerator::pause and Pause::resume for more details.

Adds the given value to the garbage list. The value is only dropped when the counter is zero. If the counter is zero when the method is called, the value is immediately dropped and the garbage list is cleared. You must remove the resource from shared context before calling this method. This operation performs Acquire on the pause counter.

Tries to delete the garbage list associated with this thread. The garbage list is only cleared if the counter is zero. In case of success, true is returned. This operation performs Acquire on the pause counter.

Clears everything that is in the inicinerator regardless of pauses. Exclusive reference is required.

Trait Implementations

Formats the value using the given formatter. Read more
Returns the “default value” for a type. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.