use super::{Arc, Weak};
use crate::sync::OnceCell;
use crate::sync::event::Event;
use crate::sync::internal::{Ordering, fence};
fn next_id() -> u64 {
use std::sync::atomic::{AtomicU64, Ordering};
static NEXT: AtomicU64 = AtomicU64::new(0);
NEXT.fetch_add(1, Ordering::Relaxed)
}
pub(super) struct Children {
#[cfg(not(all(loom, test)))]
map: kovan_map::HashMap<u64, Weak<Node>>,
#[cfg(all(loom, test))]
map: loom::sync::Mutex<std::collections::BTreeMap<u64, Weak<Node>>>,
}
impl Children {
fn new() -> Self {
#[cfg(not(all(loom, test)))]
{
Self {
map: kovan_map::HashMap::with_capacity(64),
}
}
#[cfg(all(loom, test))]
{
Self {
map: loom::sync::Mutex::new(std::collections::BTreeMap::new()),
}
}
}
fn insert(&self, id: u64, child: Weak<Node>) {
#[cfg(not(all(loom, test)))]
{
self.map.insert(id, child);
}
#[cfg(all(loom, test))]
{
let mut map = self.map.lock().unwrap_or_else(|e| e.into_inner());
map.insert(id, child);
}
}
fn remove(&self, id: u64) {
#[cfg(not(all(loom, test)))]
{
self.map.remove(&id);
}
#[cfg(all(loom, test))]
{
let mut map = self.map.lock().unwrap_or_else(|e| e.into_inner());
map.remove(&id);
}
}
fn collect(&self, out: &mut Vec<Arc<Node>>) {
#[cfg(not(all(loom, test)))]
{
out.extend(self.map.iter().filter_map(|(_, child)| child.upgrade()));
}
#[cfg(all(loom, test))]
{
let weak: Vec<Weak<Node>> = {
let map = self.map.lock().unwrap_or_else(|e| e.into_inner());
map.values().cloned().collect()
};
out.extend(weak.iter().filter_map(Weak::upgrade));
}
}
#[cfg(all(test, not(loom)))]
pub(super) fn len(&self) -> usize {
self.map.len()
}
}
pub(super) struct Node {
pub(super) cancelled: Event,
parent: Option<Arc<Node>>,
id: u64,
pub(super) children: OnceCell<Children>,
}
impl Node {
pub(super) fn new(parent: Option<Arc<Node>>) -> Arc<Node> {
Arc::new(Node {
cancelled: Event::new(),
parent,
id: next_id(),
children: OnceCell::new(),
})
}
pub(super) fn child(parent: &Arc<Node>) -> Arc<Node> {
let child = Node::new(Some(Arc::clone(parent)));
parent
.children
.get_or_init_racy(Children::new)
.insert(child.id, Arc::downgrade(&child));
fence(Ordering::SeqCst);
if parent.cancelled.is_set() {
Node::cancel(&child);
}
child
}
pub(super) fn cancel(this: &Arc<Node>) {
if !this.cancelled.is_set() {
this.cancelled.set();
}
let mut stack = Vec::new();
let mut found = Vec::new();
this.mark_children(&mut stack, &mut found);
while let Some(node) = stack.pop() {
node.mark_children(&mut stack, &mut found);
}
}
fn mark_children(&self, stack: &mut Vec<Arc<Node>>, found: &mut Vec<Arc<Node>>) {
fence(Ordering::SeqCst);
let Some(children) = self.children.get() else {
return;
};
children.collect(found);
for child in found.drain(..) {
if !child.cancelled.is_set() {
child.cancelled.set();
}
stack.push(child);
}
}
fn detach(&mut self) -> Option<Arc<Node>> {
let parent = self.parent.take()?;
if let Some(children) = parent.children.get() {
children.remove(self.id);
}
Some(parent)
}
}
impl Drop for Node {
fn drop(&mut self) {
let mut parent = self.detach();
while let Some(handle) = parent {
parent = match Arc::into_inner(handle) {
Some(mut node) => node.detach(),
None => None,
};
}
}
}