Skip to main content

dope_core/driver/schedule/
sequence.rs

1use std::{cell, hash, 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)]
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
57impl hash::Hash for Id<'_> {
58    fn hash<H: hash::Hasher>(&self, state: &mut H) {
59        self.raw.hash(state);
60    }
61}
62
63pub struct Block<'d> {
64    driver: driver::Reference<'d>,
65    next: cell::Cell<Option<num::NonZero<u64>>>,
66}
67
68impl<'d> Block<'d> {
69    pub(in crate::driver) fn new(driver: driver::Reference<'d>) -> Self {
70        let next = driver.shared.context().sequence.claim();
71        Self {
72            driver,
73            next: cell::Cell::new(next),
74        }
75    }
76
77    pub fn try_next(&self) -> Result<Id<'d>, Exhausted> {
78        let raw = match self.next.get() {
79            Some(raw) => raw,
80            None => self
81                .driver
82                .shared
83                .context()
84                .sequence
85                .claim()
86                .ok_or(Exhausted)?,
87        };
88        let next = raw.checked_add(1).filter(|next| next.get() & LOCAL != 0);
89        self.next.set(next);
90        Ok(Id::new(self.driver, raw))
91    }
92}
93
94const _: () = {
95    assert!(mem::size_of::<Block<'static>>() == 2 * mem::size_of::<usize>());
96    assert!(mem::size_of::<Id<'static>>() == mem::size_of::<num::NonZero<u64>>());
97    assert!(mem::size_of::<Result<Id<'static>, Exhausted>>() == mem::size_of::<usize>());
98};