use std::sync::atomic::Ordering::{AcqRel, Relaxed};
use orengine_utils::cache_padded::CachePaddedAtomicUsize;
use orengine_utils::hints::unlikely;
use orengine_utils::light_arc::LightArc;
use crate::local_manager::{LocalManager, LOCAL_MANAGER};
use crate::number_of_executors::NumberOfExecutorsInEpoch;
struct Inner {
current_epoch: CachePaddedAtomicUsize,
number_of_executors_in_epoch: NumberOfExecutorsInEpoch,
#[cfg(test)]
bytes_deallocated: CachePaddedAtomicUsize,
}
#[derive(Clone)]
pub struct SharedManager {
inner: LightArc<Inner>,
}
impl SharedManager {
pub fn new() -> Self {
Self {
inner: LightArc::new(Inner {
current_epoch: CachePaddedAtomicUsize::new(0),
number_of_executors_in_epoch: NumberOfExecutorsInEpoch::new(),
#[cfg(test)]
bytes_deallocated: CachePaddedAtomicUsize::new(0),
})
}
}
#[cfg(test)]
pub(crate) fn increment_bytes_deallocated(&self, bytes: usize) {
self.inner.bytes_deallocated.fetch_add(bytes, std::sync::atomic::Ordering::SeqCst);
}
#[cfg(test)]
pub(crate) fn bytes_deallocated(&self) -> usize {
self.inner.bytes_deallocated.load(std::sync::atomic::Ordering::SeqCst)
}
pub fn register_new_executor(&self) {
self.inner.number_of_executors_in_epoch.register_new_executor();
LOCAL_MANAGER.with(|local_manager_| {
let local_manager = unsafe { &mut *local_manager_.get() };
assert!(
local_manager
.replace(LocalManager::new(self))
.is_none(),
"Attempt to register local manager in a thread that already has a local manager. \
Each thread can be registered only once"
);
});
}
pub(crate) fn register_executor_again(&self) {
self.inner.number_of_executors_in_epoch.register_new_executor();
LOCAL_MANAGER.with(|local_manager_| {
let local_manager = unsafe { &mut *local_manager_.get() };
assert!(
local_manager.is_some(),
"Detected misusage of `LocalManager::temporary_deregister`, \
the thread-local `LocalManager` was completely deregistered after calling it \
and before calling `LocalManager::resume_after_temporary_deregister`."
);
});
}
pub(crate) fn deregister_executor(&self) -> bool {
if unlikely(
self
.inner
.number_of_executors_in_epoch
.deregister_executor_and_decrement_counter(),
) {
self.inner.current_epoch.fetch_add(1, AcqRel);
return true;
}
false
}
pub(crate) fn executor_passed_epoch(&self) -> bool {
if unlikely(self.inner.number_of_executors_in_epoch.executor_passed_epoch()) {
self.inner.current_epoch.fetch_add(1, AcqRel);
return true;
}
false
}
pub(crate) fn current_epoch(&self) -> usize {
self.inner.current_epoch.load(Relaxed)
}
}
impl Default for SharedManager {
fn default() -> Self {
Self::new()
}
}
impl Drop for Inner {
fn drop(&mut self) {
let data = self
.number_of_executors_in_epoch
.parsed_data_for_drop();
assert!(
data.in_current_epoch == 0 && data.all == 0,
"Some executors are still registered when the shared manager is dropped. \
Make sure to call `deregister_executor` for all registered executors \
(use {code}.",
code = "unsafe { LocalManager::deregister() }"
);
}
}