LocalManager

Struct LocalManager 

Source
pub struct LocalManager { /* private fields */ }
Expand description

A local manager of objects that need to be deallocated or dropped when it is safe.

It should be created by some runtime with SharedManager::register_new_executor, and only the runtime can call LocalManager::deregister and LocalManager::maybe_pass_epoch. The runtime should call LocalManager::deregister when it is stopped and should call LocalManager::maybe_pass_epoch periodically (it uses cached time to prevent unnecessary attempts to pass the epoch).

After the registration, the LocalManager is stored in thread-local storage and can be accessed with local_manager.

It allows scheduling objects to be deallocated or dropped when it is safe.

Use LocalManager::schedule_deallocate and LocalManager::schedule_deallocate_slice to schedule deallocation of objects, and LocalManager::schedule_drop to schedule dropping of objects.

§Example

use std::cell::Cell;
use light_qsbr::{local_manager, SharedManager, orengine_utils::OrengineInstant, LocalManager};

fn start_runtime() {
    let mut runtime = Runtime { tasks: Vec::new(), is_stopped: Cell::new(false) };
    let shared_manager = SharedManager::new();

    shared_manager.register_new_executor();

    'runtime: loop {
        for _ in 0..61 {
            if let Some(task) = runtime.tasks.pop() {
                task();
            } else {
                break 'runtime;
            }
        }

        if runtime.is_stopped.get() {
            break;
        }

        local_manager().maybe_pass_epoch(OrengineInstant::now()); // Free some memory if it is safe
    }

    unsafe { LocalManager::deregister() };
}

fn one_of_tasks(lock_free_stack: LockFreeStack<usize>) {
    let node = lock_free_stack.pop();
    let ptr_to_deallocate: *mut LockFreeStackNode<usize> = node.get_node_ptr();
    // It's not safe to release the node right now because other threads can load it but still not read it.
    unsafe {
        local_manager() // Get the thread-local LocalManager
            .schedule_deallocate(ptr_to_deallocate);
    }
    // The node will be deallocated when it is safe.
}

Implementations§

Source§

impl LocalManager

Source

pub fn current_epoch(&self) -> usize

Returns the current epoch.

Source

pub fn shared_manager(&self) -> &SharedManager

Returns a reference to the associated SharedManager.

Source

pub unsafe fn schedule_deallocate<T>(&mut self, ptr: *const T)

Schedules deallocation of an object. It will be deallocated when it is safe.

§Safety

It requires the same safety conditions as dealloc.

Source

pub unsafe fn schedule_deallocate_slice<T>(&mut self, ptr: *const T, len: usize)

Schedules deallocation of the provided slice. They will be deallocated when it is safe.

§Safety

It requires the same safety conditions as dealloc.

§Panics
Source

pub unsafe fn schedule_drop<F: FnOnce()>(&mut self, func: F)

Schedules dropping of the provided function. It will be dropped when it is safe.

The function can be a closure; therefore, it can be used to drop any object.

§Safety

It requires the same safety conditions as mem::ManuallyDrop::drop.

Source

pub fn maybe_pass_epoch(&mut self, now: impl Into<OrengineInstant>)

Maybe passes the epoch and frees some memory if it is safe.

This function accepts the current time as a parameter to avoid very often epoch passing.

While at least one thread doesn’t pass the epoch, all other threads can’t free memory.

Source

pub unsafe fn deregister()

Deregisters the thread-local LocalManager. After that the calling local_manager can cause undefined behavior before the next registration.

§Safety
§Panics

It the thread is not registered.

Source

pub unsafe fn temporary_deregister(&mut self)

Deregisters the thread-local LocalManager without reclaiming memory.

It is the unsafest function in the library. It is expected to be called only before the thread is stopped and to be resumed by calling LocalManager::resume_after_temporary_deregister after the thread is resumed.

After this function is called and before calling LocalManager::resume_after_temporary_deregister, the thread-local LocalManager is invalid.

You should completely deregister the thread-local LocalManager by calling LocalManager::deregister before the thread is terminated.

§Safety
§Example
use light_qsbr::{local_manager, LocalManager, SharedManager};

let shared_manager = SharedManager::new();

shared_manager.register_new_executor();

// Do some work

// While thread is stopped it can't call `local_manager.maybe_pass_epoch`.
// But completely deregister is excessive.
// While `local_manager().temporary_deregister()` is inexpensive
// and allows other threads to pass epochs.

unsafe { local_manager().temporary_deregister(); }

std::thread::sleep(std::time::Duration::from_secs(1));

unsafe { local_manager().resume_after_temporary_deregister(); }

// Do some work

 unsafe { LocalManager::deregister(); }
Source

pub unsafe fn resume_after_temporary_deregister(&mut self)

Resumes the thread-local LocalManager after calling LocalManager::temporary_deregister.

§Safety
§Example

You can find an example in LocalManager::temporary_deregister.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

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

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.