use std::cell::RefCell;
use super::LiveImageId;
struct Entry {
id: LiveImageId,
deferred_releases: Vec<u64>,
}
#[cfg(not(teksilo_loom))]
std::thread_local! {
static HELD: RefCell<Vec<Entry>> = const { RefCell::new(Vec::new()) };
}
#[cfg(teksilo_loom)]
crate::sync::thread_local! {
static HELD: RefCell<Vec<Entry>> = RefCell::new(Vec::new());
}
pub(super) fn holds(id: LiveImageId) -> bool {
HELD.with(|held| held.borrow().iter().any(|e| e.id == id))
}
pub(super) fn enter(id: LiveImageId) {
HELD.with(|held| {
held.borrow_mut().push(Entry {
id,
deferred_releases: Vec::new(),
});
});
}
pub(super) fn leave(id: LiveImageId) -> Vec<u64> {
HELD.with(|held| {
let mut held = held.borrow_mut();
match held.iter().position(|e| e.id == id) {
Some(at) => held.swap_remove(at).deferred_releases,
None => Vec::new(),
}
})
}
pub(super) fn defer_release(id: LiveImageId, session: u64) -> bool {
HELD.with(|held| {
let mut held = held.borrow_mut();
match held.iter_mut().find(|e| e.id == id) {
Some(entry) => {
entry.deferred_releases.push(session);
true
}
None => false,
}
})
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub(super) enum Rank {
State = 0,
List = 1,
Waker = 2,
}
#[cfg(all(debug_assertions, not(teksilo_loom)))]
mod order {
use std::cell::Cell;
use super::Rank;
std::thread_local! {
static HELD: Cell<[u8; 3]> = const { Cell::new([0; 3]) };
}
pub(in super::super) fn acquire(rank: Rank) {
HELD.with(|held| {
let mut counts = held.get();
if let Some(later) = counts[rank as usize + 1..].iter().position(|&n| n > 0) {
panic!(
"live image lock order: the {} lock taken while the {} lock is held \
(the order is: state, consumer list, waker)",
name(rank as usize),
name(rank as usize + 1 + later),
);
}
counts[rank as usize] += 1;
held.set(counts);
});
}
pub(in super::super) fn release(rank: Rank) {
HELD.with(|held| {
let mut counts = held.get();
counts[rank as usize] = counts[rank as usize].saturating_sub(1);
held.set(counts);
});
}
fn name(rank: usize) -> &'static str {
["state", "consumer list", "waker"][rank]
}
}
#[cfg(not(all(debug_assertions, not(teksilo_loom))))]
mod order {
use super::Rank;
pub(in super::super) fn acquire(_rank: Rank) {}
pub(in super::super) fn release(_rank: Rank) {}
}
pub(super) struct Ranked(Rank);
impl Ranked {
pub(super) fn acquire(rank: Rank) -> Self {
order::acquire(rank);
Self(rank)
}
}
impl Drop for Ranked {
fn drop(&mut self) {
order::release(self.0);
}
}