use std::cell::Cell;
use std::marker::PhantomData;
use crate::rcu::callback::{RcuCall, RcuDefer};
use crate::rcu::flavor::RcuFlavor;
use crate::rcu::guard::RcuGuard;
use crate::rcu::poller::RcuPoller;
use crate::utility::{PhantomUnsend, PhantomUnsync};
pub unsafe trait RcuContext {
type Flavor: RcuFlavor;
type Poller<'a>: RcuPoller + 'a
where
Self: 'a;
fn rcu_synchronize(&mut self);
fn rcu_synchronize_poller(&self) -> Self::Poller<'_>;
}
pub unsafe trait RcuReadContext: RcuContext {
type Guard<'a>: RcuGuard<Flavor = Self::Flavor> + 'a
where
Self: 'a;
fn rcu_read_lock(&self) -> Self::Guard<'_>;
fn rcu_call<F>(&self, callback: Box<F>)
where
F: RcuCall + Send + 'static;
}
pub unsafe trait RcuDeferContext: RcuContext {
fn rcu_defer<F>(&mut self, callback: Box<F>)
where
F: RcuDefer;
}
macro_rules! define_rcu_context {
($kind:ident, $context:ident, $flavor:ident, $guard:ident, $poller:ident) => {
#[doc = concat!("Defines a RCU context for the current thread (`liburcu-", stringify!($kind), "`).")]
pub struct $context<const READ: bool = false, const DEFER: bool = false>(
PhantomUnsend,
PhantomUnsync,
);
impl<const READ: bool, const DEFER: bool> $context<READ, DEFER> {
pub(crate) fn new() -> Option<Self> {
thread_local! {static RCU_CONTEXT: Cell<bool> = Cell::new(false)};
RCU_CONTEXT.with(|initialized| {
if initialized.replace(true) {
return None;
}
log::info!(
"registering thread '{}' ({}) with RCU (liburcu-{})",
std::thread::current().name().unwrap_or("<unnamed>"),
unsafe { libc::gettid() },
stringify!($kind),
);
unsafe { $flavor::unchecked_rcu_init() };
if READ {
unsafe { $flavor::unchecked_rcu_read_register_thread() };
}
if DEFER {
unsafe { $flavor::unchecked_rcu_defer_register_thread() };
}
Some(Self(PhantomData, PhantomData))
})
}
}
impl<const READ: bool, const DEFER: bool> Drop for $context<READ, DEFER> {
fn drop(&mut self) {
log::info!(
"unregistering thread '{}' ({}) with RCU (liburcu-{})",
std::thread::current().name().unwrap_or("<unnamed>"),
unsafe { libc::gettid() },
stringify!($kind),
);
if DEFER {
unsafe { $flavor::unchecked_rcu_defer_barrier() };
unsafe { $flavor::unchecked_rcu_defer_unregister_thread() };
}
if READ {
unsafe { $flavor::unchecked_rcu_call_barrier() };
unsafe { $flavor::unchecked_rcu_read_unregister_thread() };
}
}
}
unsafe impl<const READ: bool, const DEFER: bool> RcuContext for $context<READ, DEFER> {
type Flavor = $flavor;
type Poller<'a> = $poller<'a>;
fn rcu_synchronize(&mut self) {
unsafe { $flavor::unchecked_rcu_synchronize() };
}
fn rcu_synchronize_poller(&self) -> Self::Poller<'_> {
$poller::new(self)
}
}
unsafe impl<const DEFER: bool> RcuReadContext for $context<true, DEFER> {
type Guard<'a> = $guard<'a>;
fn rcu_read_lock(&self) -> Self::Guard<'_> {
$guard::<'_>::new(self)
}
fn rcu_call<F>(&self, callback: Box<F>)
where
F: RcuCall + Send + 'static,
{
callback.configure(|mut head, func| {
unsafe { $flavor::unchecked_rcu_call(Some(func), head.as_mut()) };
});
}
}
unsafe impl<const READ: bool> RcuDeferContext for $context<READ, true> {
fn rcu_defer<F>(&mut self, callback: Box<F>)
where
F: RcuDefer,
{
callback.configure(|mut ptr, func| {
unsafe { $flavor::unchecked_rcu_defer_call(Some(func), ptr.as_mut()) };
});
}
}
};
}
#[cfg(feature = "flavor-bp")]
mod bp {
use super::*;
use crate::rcu::flavor::RcuFlavorBp;
use crate::rcu::guard::RcuGuardBp;
use crate::rcu::poller::RcuPollerBp;
define_rcu_context!(bp, RcuContextBp, RcuFlavorBp, RcuGuardBp, RcuPollerBp);
}
#[cfg(feature = "flavor-mb")]
mod mb {
use super::*;
use crate::rcu::flavor::RcuFlavorMb;
use crate::rcu::guard::RcuGuardMb;
use crate::rcu::poller::RcuPollerMb;
define_rcu_context!(mb, RcuContextMb, RcuFlavorMb, RcuGuardMb, RcuPollerMb);
}
#[cfg(feature = "flavor-memb")]
mod memb {
use super::*;
use crate::rcu::flavor::RcuFlavorMemb;
use crate::rcu::guard::RcuGuardMemb;
use crate::rcu::poller::RcuPollerMemb;
define_rcu_context!(
memb,
RcuContextMemb,
RcuFlavorMemb,
RcuGuardMemb,
RcuPollerMemb
);
}
#[cfg(feature = "flavor-qsbr")]
mod qsbr {
use super::*;
use crate::rcu::flavor::RcuFlavorQsbr;
use crate::rcu::guard::RcuGuardQsbr;
use crate::rcu::poller::RcuPollerQsbr;
define_rcu_context!(
qsbr,
RcuContextQsbr,
RcuFlavorQsbr,
RcuGuardQsbr,
RcuPollerQsbr
);
}
#[cfg(feature = "flavor-bp")]
pub use bp::*;
#[cfg(feature = "flavor-mb")]
pub use mb::*;
#[cfg(feature = "flavor-memb")]
pub use memb::*;
#[cfg(feature = "flavor-qsbr")]
pub use qsbr::*;
mod asserts {
use static_assertions::assert_not_impl_all;
#[cfg(feature = "flavor-bp")]
mod bp {
use super::*;
use crate::rcu::context::bp::RcuContextBp;
assert_not_impl_all!(RcuContextBp: Send);
assert_not_impl_all!(RcuContextBp: Sync);
}
#[cfg(feature = "flavor-mb")]
mod mb {
use super::*;
use crate::rcu::context::mb::RcuContextMb;
assert_not_impl_all!(RcuContextMb: Send);
assert_not_impl_all!(RcuContextMb: Sync);
}
#[cfg(feature = "flavor-memb")]
mod memb {
use super::*;
use crate::rcu::context::memb::RcuContextMemb;
assert_not_impl_all!(RcuContextMemb: Send);
assert_not_impl_all!(RcuContextMemb: Sync);
}
#[cfg(feature = "flavor-qsbr")]
mod qsbr {
use super::*;
use crate::rcu::context::qsbr::RcuContextQsbr;
assert_not_impl_all!(RcuContextQsbr: Send);
assert_not_impl_all!(RcuContextQsbr: Sync);
}
}