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
impl LocalManager
Sourcepub fn current_epoch(&self) -> usize
pub fn current_epoch(&self) -> usize
Returns the current epoch.
Returns a reference to the associated SharedManager.
Sourcepub unsafe fn schedule_deallocate<T>(&mut self, ptr: *const T)
pub unsafe fn schedule_deallocate<T>(&mut self, ptr: *const T)
Sourcepub unsafe fn schedule_deallocate_slice<T>(&mut self, ptr: *const T, len: usize)
pub unsafe fn schedule_deallocate_slice<T>(&mut self, ptr: *const T, len: usize)
Sourcepub unsafe fn schedule_drop<F: FnOnce()>(&mut self, func: F)
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.
Sourcepub fn maybe_pass_epoch(&mut self, now: impl Into<OrengineInstant>)
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.
Sourcepub unsafe fn deregister()
pub unsafe fn deregister()
Deregisters the thread-local LocalManager.
After that the calling local_manager can cause undefined behavior before the next
registration.
§Safety
- The thread must be registered in the
SharedManager. - It is called only once for one
registration. - After calling this function, the caller doesn’t call
local_managerbefore the nextregistration.
§Panics
It the thread is not registered.
Sourcepub unsafe fn temporary_deregister(&mut self)
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
- The thread must be registered in the
SharedManager. - After calling this function, the
LocalManageris not used before callingLocalManager::resume_after_temporary_deregister. LocalManager::deregistermust be called before the thread is terminated.
§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(); }Sourcepub unsafe fn resume_after_temporary_deregister(&mut self)
pub unsafe fn resume_after_temporary_deregister(&mut self)
Resumes the thread-local LocalManager after calling LocalManager::temporary_deregister.
§Safety
- The thread must be registered (before calling
LocalManager::temporary_deregister) in theSharedManager. LocalManager::temporary_deregistermust be called before calling this function.
§Example
You can find an example in LocalManager::temporary_deregister.