use crate::rt::{alloc, arc, atomic, condvar, execution, mutex, notify};
use crate::rt::{Access, Execution, VersionVec};
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct Object {
index: usize,
execution_id: execution::Id,
}
#[derive(Debug)]
pub struct Store {
execution_id: execution::Id,
entries: Vec<Entry>,
}
#[derive(Debug)]
enum Entry {
Alloc(alloc::State),
Arc(arc::State),
Atomic(atomic::State),
Mutex(mutex::State),
Condvar(condvar::State),
Notify(notify::State),
}
#[derive(Debug, Copy, Clone)]
pub(super) struct Operation {
obj: Object,
action: Action,
}
#[derive(Debug, Copy, Clone)]
pub(super) enum Action {
Arc(arc::Action),
Atomic(atomic::Action),
Opaque,
}
impl Object {
pub(super) fn alloc(self, store: &mut Store) -> &mut alloc::State {
assert_eq!(self.execution_id, store.execution_id);
match &mut store.entries[self.index] {
Entry::Alloc(v) => v,
_ => panic!(),
}
}
pub(super) fn arc_mut(self, store: &mut Store) -> &mut arc::State {
assert_eq!(self.execution_id, store.execution_id);
match &mut store.entries[self.index] {
Entry::Arc(v) => v,
_ => panic!(),
}
}
pub(super) fn atomic_mut(self, store: &mut Store) -> Option<&mut atomic::State> {
assert_eq!(self.execution_id, store.execution_id);
match &mut store.entries[self.index] {
Entry::Atomic(v) => Some(v),
_ => None,
}
}
pub(super) fn condvar_mut(self, store: &mut Store) -> Option<&mut condvar::State> {
assert_eq!(self.execution_id, store.execution_id);
match &mut store.entries[self.index] {
Entry::Condvar(v) => Some(v),
_ => None,
}
}
pub(super) fn mutex_mut(self, store: &mut Store) -> Option<&mut mutex::State> {
assert_eq!(self.execution_id, store.execution_id);
match &mut store.entries[self.index] {
Entry::Mutex(v) => Some(v),
_ => None,
}
}
pub(super) fn notify_mut(self, store: &mut Store) -> Option<&mut notify::State> {
assert_eq!(self.execution_id, store.execution_id);
match &mut store.entries[self.index] {
Entry::Notify(v) => Some(v),
_ => None,
}
}
}
impl Store {
pub(super) fn new(execution_id: execution::Id) -> Store {
Store {
execution_id,
entries: vec![],
}
}
pub(super) fn insert_alloc(&mut self, state: alloc::State) -> Object {
self.insert(Entry::Alloc(state))
}
pub(super) fn insert_arc(&mut self, state: arc::State) -> Object {
self.insert(Entry::Arc(state))
}
pub(super) fn insert_atomic(&mut self, state: atomic::State) -> Object {
self.insert(Entry::Atomic(state))
}
pub(super) fn atomics_mut(&mut self) -> impl Iterator<Item = &mut atomic::State> {
self.entries.iter_mut().filter_map(|entry| match entry {
Entry::Atomic(entry) => Some(entry),
_ => None,
})
}
pub(super) fn insert_mutex(&mut self, state: mutex::State) -> Object {
self.insert(Entry::Mutex(state))
}
pub(super) fn insert_condvar(&mut self, state: condvar::State) -> Object {
self.insert(Entry::Condvar(state))
}
pub(super) fn insert_notify(&mut self, state: notify::State) -> Object {
self.insert(Entry::Notify(state))
}
fn insert(&mut self, entry: Entry) -> Object {
let index = self.entries.len();
self.entries.push(entry);
Object {
index,
execution_id: self.execution_id,
}
}
pub(super) fn last_dependent_access(&self, operation: Operation) -> Option<&Access> {
match &self.entries[operation.obj.index] {
Entry::Alloc(_) => panic!("allocations are not branchable operations"),
Entry::Arc(entry) => entry.last_dependent_access(operation.action.into()),
Entry::Atomic(entry) => entry.last_dependent_access(),
Entry::Mutex(entry) => entry.last_dependent_access(),
Entry::Condvar(entry) => entry.last_dependent_access(),
Entry::Notify(entry) => entry.last_dependent_access(),
}
}
pub(super) fn set_last_access(
&mut self,
operation: Operation,
path_id: usize,
dpor_vv: &VersionVec,
) {
match &mut self.entries[operation.obj.index] {
Entry::Alloc(_) => panic!("allocations are not branchable operations"),
Entry::Arc(entry) => entry.set_last_access(operation.action.into(), path_id, dpor_vv),
Entry::Atomic(entry) => entry.set_last_access(path_id, dpor_vv),
Entry::Mutex(entry) => entry.set_last_access(path_id, dpor_vv),
Entry::Condvar(entry) => entry.set_last_access(path_id, dpor_vv),
Entry::Notify(entry) => entry.set_last_access(path_id, dpor_vv),
}
}
pub(crate) fn clear(&mut self) {
self.entries.clear();
}
pub(crate) fn check_for_leaks(&self) {
for entry in &self.entries[..] {
match entry {
Entry::Alloc(entry) => entry.check_for_leaks(),
Entry::Arc(entry) => entry.check_for_leaks(),
_ => {}
}
}
}
}
impl Object {
pub(super) fn branch_acquire(self, is_locked: bool) {
super::branch(|execution| {
self.set_action(execution, Action::Opaque);
if is_locked {
execution.threads.active_mut().set_blocked();
}
})
}
pub(super) fn branch<T: Into<Action>>(self, action: T) {
super::branch(|execution| {
self.set_action(execution, action.into());
})
}
pub(super) fn branch_opaque(self) {
self.branch(Action::Opaque)
}
fn set_action(self, execution: &mut Execution, action: Action) {
execution.threads.active_mut().operation = Some(Operation { obj: self, action });
}
}
impl Operation {
pub(super) fn object(&self) -> Object {
self.obj
}
}
impl Into<arc::Action> for Action {
fn into(self) -> arc::Action {
match self {
Action::Arc(action) => action,
_ => unimplemented!(),
}
}
}
impl Into<atomic::Action> for Action {
fn into(self) -> atomic::Action {
match self {
Action::Atomic(action) => action,
_ => unimplemented!(),
}
}
}
impl Into<Action> for arc::Action {
fn into(self) -> Action {
Action::Arc(self)
}
}
impl Into<Action> for atomic::Action {
fn into(self) -> Action {
Action::Atomic(self)
}
}