dope-core 0.15.0

The manifold runtime
Documentation
use std::{cell, marker, mem};

use o3::collections;

use crate::driver::{route::kind, schedule::ready};

const NONE: u32 = u32::MAX;

struct Link {
    previous: cell::Cell<u32>,
    next: cell::Cell<u32>,
    epoch: cell::Cell<u32>,
}

const _: () = assert!(mem::size_of::<Link>() == 3 * mem::size_of::<u32>());

pub(super) struct Waiters {
    links: Box<[Link]>,
    head: cell::Cell<u32>,
    tail: cell::Cell<u32>,
    _thread: o3::ThreadBound,
}

impl Waiters {
    pub(super) fn try_with_capacity(capacity: usize) -> Result<Self, collections::AllocationError> {
        use o3::collections::BoxSliceExt;

        Ok(Self {
            links: BoxSliceExt::try_box_with(capacity, |_| Link {
                previous: cell::Cell::new(NONE),
                next: cell::Cell::new(NONE),
                epoch: cell::Cell::new(0),
            })?,
            head: cell::Cell::new(NONE),
            tail: cell::Cell::new(NONE),
            _thread: o3::ThreadBound::NEW,
        })
    }

    pub(super) fn retire(&self, arena: &ready::Arena, key: ready::FixedKey<'_>) -> bool {
        let Some(resolved) = arena.entries.slots.resolve(key.key()) else {
            return false;
        };
        let Some(dispatch) = resolved.dispatch() else {
            return false;
        };
        match dispatch.get().kind() {
            kind::RECV_BUFFER_WAITING => {
                self.unlink(key);
                false
            }
            kind::RECV_BUFFER_GRANTED => true,
            _ => false,
        }
    }

    pub(super) fn wake(&self, arena: &ready::Arena) -> bool {
        while let Some((index, epoch)) = self.pop_front() {
            let key = ready::Key {
                index: index as u32,
                epoch,
                _arena: marker::PhantomData,
                _thread: o3::ThreadBound::NEW,
            };
            let Some(dispatch) = arena
                .entries
                .slots
                .resolve(key)
                .and_then(|entry| entry.dispatch())
            else {
                continue;
            };
            let target = dispatch.get();
            if target.kind() != kind::RECV_BUFFER_WAITING {
                continue;
            }
            dispatch.set(target.with_kind(kind::RECV_BUFFER_GRANTED));
            arena.ready.insert(index);
            return true;
        }
        false
    }

    pub(super) fn link(&self, key: ready::FixedKey<'_>) -> bool {
        let index = key.index() as usize;
        let Some(link) = self.links.get(index) else {
            return false;
        };
        if link.previous.get() != NONE {
            return false;
        }

        let index = index as u32;
        let tail = self.tail.get();
        link.previous.set(if tail == NONE { index } else { tail });
        link.next.set(NONE);
        link.epoch.set(key.epoch());
        if tail == NONE {
            self.head.set(index);
        } else {
            self.links[tail as usize].next.set(index);
        }
        self.tail.set(index);
        true
    }

    pub(super) fn unlink(&self, key: ready::FixedKey<'_>) -> bool {
        self.unlink_index(key.index() as usize)
    }

    pub(super) fn unlink_index(&self, index: usize) -> bool {
        let Some(link) = self.links.get(index) else {
            return false;
        };
        let previous = link.previous.replace(NONE);
        if previous == NONE {
            return false;
        }

        let next = link.next.replace(NONE);
        let index = index as u32;
        if previous == index {
            self.head.set(next);
        } else {
            self.links[previous as usize].next.set(next);
        }
        if next == NONE {
            self.tail
                .set(if previous == index { NONE } else { previous });
        } else if previous == index {
            self.links[next as usize].previous.set(next);
        } else {
            self.links[next as usize].previous.set(previous);
        }
        true
    }

    fn pop_front(&self) -> Option<(usize, u32)> {
        let index = self.head.get();
        if index == NONE {
            return None;
        }
        let epoch = self.links[index as usize].epoch.get();
        self.unlink_index(index as usize);
        Some((index as usize, epoch))
    }
}