#[cfg(windows)]
use kernel32;
#[cfg(unix)]
use libc;
#[cfg(not(any(windows, unix)))]
use std::thread;
#[cfg(not(feature = "nightly"))]
use std::sync::atomic::{Ordering, fence};
#[cfg(windows)]
#[inline]
fn thread_yield() {
unsafe {
kernel32::Sleep(0);
}
}
#[cfg(unix)]
#[inline]
fn thread_yield() {
unsafe {
libc::sched_yield();
}
}
#[cfg(not(any(windows, unix)))]
#[inline]
fn thread_yield() {
thread::yield_now();
}
#[cfg(all(feature = "nightly", any(target_arch = "x86", target_arch = "x86_64")))]
#[inline]
fn cpu_relax(iterations: u32) {
for _ in 0..iterations {
unsafe {
asm!("pause" ::: "memory" : "volatile");
}
}
}
#[cfg(all(feature = "nightly", target_arch = "aarch64"))]
#[inline]
fn cpu_relax(iterations: u32) {
for _ in 0..iterations {
unsafe {
asm!("yield" ::: "memory" : "volatile");
}
}
}
#[cfg(all(feature = "nightly", not(any(target_arch = "x86",
target_arch = "x86_64",
target_arch = "aarch64"))))]
#[inline]
fn cpu_relax(iterations: u32) {
for _ in 0..iterations {
unsafe {
asm!("" ::: "memory" : "volatile");
}
}
}
#[cfg(not(feature = "nightly"))]
#[inline]
fn cpu_relax(iterations: u32) {
for _ in 0..iterations {
fence(Ordering::SeqCst);
}
}
pub struct SpinWait {
counter: u32,
}
impl SpinWait {
#[cfg(feature = "nightly")]
#[inline]
pub const fn new() -> SpinWait {
SpinWait { counter: 0 }
}
#[cfg(not(feature = "nightly"))]
#[inline]
pub fn new() -> SpinWait {
SpinWait { counter: 0 }
}
#[inline]
pub fn reset(&mut self) {
self.counter = 0;
}
#[inline]
pub fn spin(&mut self) -> bool {
if self.counter >= 20 {
return false;
}
self.counter += 1;
if self.counter <= 10 {
cpu_relax(4 << self.counter);
} else {
thread_yield();
}
true
}
#[inline]
pub fn spin_no_yield(&mut self) {
self.counter += 1;
if self.counter > 10 {
self.counter = 10;
}
cpu_relax(4 << self.counter);
}
}
impl Default for SpinWait {
#[inline]
fn default() -> SpinWait {
SpinWait::new()
}
}