use vj_abi::Region;
use crate::sched::assert_control::{self, SiteId};
use crate::sched::maturation::{self, ReportKind};
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum ViolationType {
Unique,
Unique0,
Priority,
}
pub const DEFERRED_MODE_OBSERVED: u32 = 0;
pub const DEFERRED_MODE_FINAL: u32 = 1;
pub const DEFERRED_MODE_CANCEL: u32 = 5;
impl ViolationType {
pub const fn assertion_type_bit(self) -> u32 {
match self {
ViolationType::Unique => 32,
ViolationType::Unique0 => 64,
ViolationType::Priority => 128,
}
}
pub const fn deferred_mode(self) -> u32 {
match self {
ViolationType::Unique => 2,
ViolationType::Unique0 => 3,
ViolationType::Priority => 4,
}
}
pub const fn from_deferred_mode(mode: u32) -> Option<ViolationType> {
match mode {
2 => Some(ViolationType::Unique),
3 => Some(ViolationType::Unique0),
4 => Some(ViolationType::Priority),
_ => None,
}
}
}
pub fn set_violation_writer(f: fn(&[u8])) {
maturation::set_writer(ReportKind::Violation, f);
}
pub fn violation_report(ty: ViolationType, text: Vec<u8>) {
violation_report_for(ty, text, None);
}
pub fn violation_report_for(_ty: ViolationType, text: Vec<u8>, control: Option<SiteId>) {
if let Some(id) = control
&& !assert_control::state(id).checking
{
return;
}
maturation::report_independent_for_site(ReportKind::Violation, Region::Observed, text, control);
}
pub(crate) fn flush_violation_reports(proc: crate::sched::ProcessId) {
maturation::flush_violations(proc);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn violation_types_round_trip_through_their_deferred_modes() {
let all = [
(ViolationType::Unique, 32),
(ViolationType::Unique0, 64),
(ViolationType::Priority, 128),
];
for (ty, bit) in all {
assert_eq!(ty.assertion_type_bit(), bit);
assert_eq!(
ViolationType::from_deferred_mode(ty.deferred_mode()),
Some(ty)
);
}
assert_eq!(
ViolationType::from_deferred_mode(DEFERRED_MODE_OBSERVED),
None
);
assert_eq!(ViolationType::from_deferred_mode(DEFERRED_MODE_FINAL), None);
assert_eq!(ViolationType::from_deferred_mode(5), None);
}
#[test]
fn a_report_of_a_site_that_is_off_is_dropped_and_kill_flushes_a_pending_one() {
use crate::sched::assert_control::{self as ac, Control, Op, SiteDesc};
ac::reset();
let id = ac::intern(SiteDesc {
assertion_type: ac::ASSERT_UNIQUE,
directive_type: 0,
scope: "top".into(),
label: String::new(),
});
let op = |control| Op {
control,
assertion_type: ac::ASSERT_ALL,
directive_type: ac::DIR_ALL,
levels: 0,
targets: Vec::new(),
};
let before = maturation::pending_len();
violation_report_for(ViolationType::Unique, b"a\n".to_vec(), Some(id));
assert_eq!(maturation::pending_len(), before + 1, "checking: reported");
for killed in ac::control(op(Control::Kill)) {
assert_eq!(killed, id);
maturation::flush_sites(&[killed]);
}
assert_eq!(maturation::pending_len(), before, "the pending one is gone");
violation_report_for(ViolationType::Unique, b"b\n".to_vec(), Some(id));
assert_eq!(maturation::pending_len(), before, "off: not reported");
ac::control(op(Control::On));
violation_report_for(ViolationType::Unique, b"c\n".to_vec(), Some(id));
assert_eq!(maturation::pending_len(), before + 1, "on again: reported");
violation_report(ViolationType::Unique, b"d\n".to_vec());
assert_eq!(maturation::pending_len(), before + 2);
}
}