Skip to main content

dope_core/driver/schedule/
sequence.rs

1use std::{cell, mem, num};
2
3use o3::base::marker::ThreadBound;
4
5use crate::driver;
6
7const LOCAL: u64 = u32::MAX as u64;
8const BLOCK: u64 = 1_u64 << u32::BITS;
9
10pub(in crate::driver) struct Owner(cell::Cell<Option<num::NonZero<u64>>>);
11
12impl Owner {
13    pub(in crate::driver) const fn new() -> Self {
14        Self(cell::Cell::new(Some(num::NonZero::<u64>::MIN)))
15    }
16
17    fn claim(&self) -> Option<num::NonZero<u64>> {
18        let first = self.0.get()?;
19        let skip = 1_u32.wrapping_sub(first.get() as u32);
20        let first = first.checked_add(u64::from(skip))?;
21        self.0.set(first.checked_add(BLOCK));
22        Some(first)
23    }
24
25    pub(in crate::driver) fn next(&self) -> Option<num::NonZero<u64>> {
26        let next = self.0.get()?;
27        self.0.set(next.checked_add(1));
28        Some(next)
29    }
30}
31
32#[derive(Clone, Copy, Debug, Eq, PartialEq)]
33pub struct Exhausted;
34
35/// A sequence identity issued by one live driver.
36///
37/// The invariant lifetime brand prevents identities from independent driver
38/// instances from being retained or compared after their issuing driver ends.
39#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
40#[repr(transparent)]
41pub struct Id<'d> {
42    raw: num::NonZero<u64>,
43    driver: driver::Invariant<'d>,
44    thread: ThreadBound,
45}
46
47impl<'d> Id<'d> {
48    pub(in crate::driver) fn new(driver: driver::Reference<'d>, raw: num::NonZero<u64>) -> Self {
49        Self {
50            raw,
51            driver: driver.brand,
52            thread: ThreadBound::NEW,
53        }
54    }
55}
56
57pub struct Block<'d> {
58    driver: driver::Reference<'d>,
59    next: cell::Cell<Option<num::NonZero<u64>>>,
60}
61
62impl<'d> Block<'d> {
63    pub(in crate::driver) fn new(driver: driver::Reference<'d>) -> Self {
64        let next = driver.shared.context().sequence.claim();
65        Self {
66            driver,
67            next: cell::Cell::new(next),
68        }
69    }
70
71    pub fn try_next(&self) -> Result<Id<'d>, Exhausted> {
72        let raw = match self.next.get() {
73            Some(raw) => raw,
74            None => self
75                .driver
76                .shared
77                .context()
78                .sequence
79                .claim()
80                .ok_or(Exhausted)?,
81        };
82        let next = raw.checked_add(1).filter(|next| next.get() & LOCAL != 0);
83        self.next.set(next);
84        Ok(Id::new(self.driver, raw))
85    }
86}
87
88const _: () = {
89    assert!(mem::size_of::<Block<'static>>() == 2 * mem::size_of::<usize>());
90    assert!(mem::size_of::<Id<'static>>() == mem::size_of::<num::NonZero<u64>>());
91    assert!(mem::size_of::<Result<Id<'static>, Exhausted>>() == mem::size_of::<usize>());
92};