use crate::Client;
use std::sync::atomic::Ordering;
#[cfg(feature = "enable")]
#[cfg(not(loom))]
static CLIENT_STATE: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);
#[cfg(loom)]
loom::lazy_static! {
static ref CLIENT_STATE: loom::sync::atomic::AtomicUsize =
loom::sync::atomic::AtomicUsize::new(0);
}
#[cfg(feature = "enable")]
const STATE_STEP: usize = 1; #[cfg(feature = "enable")]
const STATE_DISABLED: usize = 0;
#[cfg(feature = "enable")]
const STATE_ENABLING: usize = STATE_DISABLED + STATE_STEP;
#[cfg(feature = "enable")]
const STATE_ENABLED: usize = STATE_ENABLING + STATE_STEP;
#[cfg(feature = "enable")]
#[inline(always)]
fn spin_loop() {
#[cfg(loom)]
loom::thread::yield_now();
#[cfg(not(loom))]
std::hint::spin_loop();
}
impl Client {
pub fn start() -> Self {
#[cfg(feature = "enable")]
{
let mut old_state = CLIENT_STATE.load(Ordering::Relaxed);
loop {
match old_state {
STATE_ENABLED => return Client(()),
STATE_ENABLING => {
while !Self::is_running() {
spin_loop();
}
return Client(());
}
STATE_DISABLED => {
let result = CLIENT_STATE.compare_exchange_weak(
old_state,
STATE_ENABLING,
Ordering::Relaxed,
Ordering::Relaxed,
);
if let Err(next_old_state) = result {
old_state = next_old_state;
continue;
} else {
unsafe {
sys::___tracy_startup_profiler();
CLIENT_STATE.store(STATE_ENABLED, Ordering::Release);
return Client(());
}
}
}
_ => unreachable!(),
}
}
}
#[cfg(not(feature = "enable"))]
Client(())
}
#[inline(always)]
pub fn running() -> Option<Self> {
if Self::is_running() {
Some(Client(()))
} else {
None
}
}
#[inline(always)]
pub fn is_running() -> bool {
#[cfg(feature = "enable")]
return CLIENT_STATE.load(Ordering::Relaxed) == STATE_ENABLED;
#[cfg(not(feature = "enable"))]
return true;
}
}
impl Clone for Client {
#[inline(always)]
fn clone(&self) -> Self {
Client(())
}
}
#[cfg(all(test, feature = "enable"))]
mod test {
use super::*;
#[test]
fn state_transitions() {
assert_eq!(0, STATE_DISABLED);
assert_eq!(STATE_DISABLED.wrapping_add(STATE_STEP), STATE_ENABLING);
assert_eq!(STATE_ENABLING.wrapping_add(STATE_STEP), STATE_ENABLED);
}
}