pub static FAULT_INJECT_COUNTER: core::sync::atomic::AtomicU64 =
core::sync::atomic::AtomicU64::new(u64::MAX);
pub static SLEEPINESS: core::sync::atomic::AtomicU32 = core::sync::atomic::AtomicU32::new(0);
#[doc(hidden)]
pub type Trigger = fn(crate_name: &'static str, file_name: &'static str, line_number: u32);
pub fn set_trigger_function(f: Trigger) {
TRIGGER_FN.store(
f as usize as *mut Trigger,
core::sync::atomic::Ordering::Release,
);
}
#[doc(hidden)]
pub static TRIGGER_FN: core::sync::atomic::AtomicPtr<Trigger> =
core::sync::atomic::AtomicPtr::new(0 as _);
#[macro_export]
macro_rules! fallible {
($e:expr) => {{
fault_injection::maybe!($e)?
}};
}
#[macro_export]
macro_rules! maybe {
($e:expr) => {{
let sleepiness = fault_injection::SLEEPINESS.load(core::sync::atomic::Ordering::Acquire);
if sleepiness > 0 {
#[cfg(target_arch = "x86")]
let rdtsc = unsafe { core::arch::x86::_rdtsc() as u16 };
#[cfg(target_arch = "x86_64")]
let rdtsc = unsafe { core::arch::x86_64::_rdtsc() as u16 };
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
let rdtsc = 0b10_u16;
let random_sleeps = rdtsc.trailing_zeros() as u32 * sleepiness;
for _ in 0..random_sleeps {
std::thread::yield_now();
}
}
const CRATE_NAME: &str = if let Some(name) = core::option_env!("CARGO_CRATE_NAME") {
name
} else {
""
};
if fault_injection::FAULT_INJECT_COUNTER.fetch_sub(1, core::sync::atomic::Ordering::AcqRel)
== 1
{
let trigger_fn = fault_injection::TRIGGER_FN.load(core::sync::atomic::Ordering::Acquire);
if !trigger_fn.is_null() {
unsafe {
let f: &fault_injection::Trigger = std::mem::transmute(&trigger_fn);
(f)(CRATE_NAME, file!(), line!());
}
}
Err(fault_injection::annotate!(std::io::Error::new(
std::io::ErrorKind::Other,
"injected fault",
)))
} else {
match $e {
Ok(ok) => Ok(ok),
Err(e) => Err(fault_injection::annotate!(e)),
}
}
}};
}
#[macro_export]
macro_rules! annotate {
($e:expr) => {{
const CRATE_NAME: &str = if let Some(name) = core::option_env!("CARGO_CRATE_NAME") {
name
} else {
""
};
std::io::Error::new(
$e.kind(),
format!(
"{}:{}:{} -> {}",
CRATE_NAME,
file!(),
line!(),
$e.to_string()
),
)
}};
}