blob: 047c37e56b8f37d4fc377be74ed976e4e9f6ddae [file] [log] [blame] [edit]
use std::rc::Rc;
use super::{data_race, weak_memory};
use crate::concurrency::GenmcCtx;
use crate::{VisitProvenance, VisitWith};
pub enum GlobalDataRaceHandler {
/// No data race detection will be done.
None,
/// State required to run in GenMC mode.
/// In this mode, the program will be executed repeatedly to explore different concurrent executions.
/// The `GenmcCtx` must persist across multiple executions, so it is behind an `Rc`.
///
/// The `GenmcCtx` has several methods with which to inform it about events like atomic memory accesses.
/// In GenMC mode, some functionality is taken over by GenMC:
/// - Memory Allocation: Allocated addresses need to be consistent across executions, which Miri's allocator doesn't guarantee
/// - Scheduling: To influence which concurrent execution we will explore next, GenMC takes over scheduling
/// - Atomic operations: GenMC will ensure that we explore all possible values that the memory model allows
/// an atomic operation to see at any specific point of the program.
Genmc(Rc<GenmcCtx>),
/// The default data race detector for Miri using vector clocks.
Vclocks(Box<data_race::GlobalState>),
}
#[derive(Debug)]
pub enum AllocDataRaceHandler {
None,
Genmc,
/// Data race detection via the use of vector clocks.
/// Weak memory emulation via the use of store buffers (if enabled).
Vclocks(data_race::AllocState, Option<weak_memory::AllocState>),
}
impl GlobalDataRaceHandler {
pub fn is_none(&self) -> bool {
matches!(self, GlobalDataRaceHandler::None)
}
pub fn as_vclocks_ref(&self) -> Option<&data_race::GlobalState> {
if let Self::Vclocks(data_race) = self { Some(data_race) } else { None }
}
pub fn as_vclocks_mut(&mut self) -> Option<&mut data_race::GlobalState> {
if let Self::Vclocks(data_race) = self { Some(data_race) } else { None }
}
pub fn as_genmc_ref(&self) -> Option<&GenmcCtx> {
if let Self::Genmc(genmc_ctx) = self { Some(genmc_ctx) } else { None }
}
}
impl AllocDataRaceHandler {
pub fn as_vclocks_ref(&self) -> Option<&data_race::AllocState> {
if let Self::Vclocks(data_race, _weak_memory) = self { Some(data_race) } else { None }
}
pub fn as_vclocks_mut(&mut self) -> Option<&mut data_race::AllocState> {
if let Self::Vclocks(data_race, _weak_memory) = self { Some(data_race) } else { None }
}
pub fn as_weak_memory_ref(&self) -> Option<&weak_memory::AllocState> {
if let Self::Vclocks(_data_race, weak_memory) = self { weak_memory.as_ref() } else { None }
}
pub fn as_weak_memory_mut(&mut self) -> Option<&mut weak_memory::AllocState> {
if let Self::Vclocks(_data_race, weak_memory) = self { weak_memory.as_mut() } else { None }
}
}
impl VisitProvenance for GlobalDataRaceHandler {
fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
match self {
GlobalDataRaceHandler::None => {}
GlobalDataRaceHandler::Vclocks(data_race) => data_race.visit_provenance(visit),
GlobalDataRaceHandler::Genmc(genmc_ctx) => genmc_ctx.visit_provenance(visit),
}
}
}
impl VisitProvenance for AllocDataRaceHandler {
fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
match self {
AllocDataRaceHandler::None => {}
AllocDataRaceHandler::Genmc => {}
AllocDataRaceHandler::Vclocks(data_race, weak_memory) => {
data_race.visit_provenance(visit);
weak_memory.visit_provenance(visit);
}
}
}
}