use core::sync::atomic::{AtomicU64, Ordering};
#[doc(hidden)]
#[repr(transparent)]
pub struct __Rc(AtomicU64);
impl __Rc {
#[allow(clippy::new_without_default)]
#[inline]
pub const fn new() -> Self {
Self(AtomicU64::new(0))
}
#[inline]
pub(crate) fn inc(&self) {
let _old_rc = self.0.fetch_add(1, Ordering::Relaxed);
#[cfg(any(debug_assertions, miri))]
if _old_rc > u64::MAX / 2 {
panic!("lien: refcount overflow");
}
}
#[inline]
pub(crate) unsafe fn dec(this: *const Self) {
let old = unsafe { (*this).0.fetch_sub(1, Ordering::Release) };
imp::wake(this as *const u64, old);
}
#[inline]
pub(crate) fn wait(&self) {
imp::wait(&self.0);
}
}
#[allow(dead_code)]
#[inline]
fn words(p: *const u64) -> [*const u32; 2] {
[(p as *const u32), (p as *const u32).wrapping_add(1)]
}
crate::cfg_select! {
target_endian = "little" => {
#[allow(dead_code)]
#[inline]
fn hi_ptr(p: *const u64) -> *const u32 { words(p)[1] }
#[allow(dead_code)]
#[inline]
fn lo_ptr(p: *const u64) -> *const u32 { words(p)[0] }
}
target_endian = "big" => {
#[allow(dead_code)]
#[inline]
fn hi_ptr(p: *const u64) -> *const u32 { words(p)[0] }
#[allow(dead_code)]
#[inline]
fn lo_ptr(p: *const u64) -> *const u32 { words(p)[1] }
}
}
#[allow(dead_code)]
#[inline]
pub(super) fn wait_hi_lo(atom: &AtomicU64, wait32: impl Fn(*const u32, u32)) {
let p = atom as *const AtomicU64 as *const u64;
loop {
let v = atom.load(Ordering::Acquire);
match ((v >> 32) as u32, v as u32) {
(0, 0) => break,
(hi, 0) => wait32(hi_ptr(p), hi),
(_, lo) => wait32(lo_ptr(p), lo),
}
}
}
#[allow(dead_code)]
#[inline]
pub(super) fn wake_hi_lo(ptr: *const u64, old: u64, wake32: impl Fn(*const u32)) {
match old {
0x0000_0001_0000_0000 => wake32(hi_ptr(ptr)), 0x0000_0000_0000_0001 => wake32(lo_ptr(ptr)), _ => {}
}
}
crate::cfg_select! {
miri => {
#[path = "refcount/miri.rs"]
mod imp;
}
any(target_os = "linux", target_os = "android") => {
#[path = "refcount/linux.rs"]
mod imp;
}
target_family = "wasm" => {
#[path = "refcount/wasm.rs"]
mod imp;
}
target_os = "dragonfly" => {
#[path = "refcount/dragonfly.rs"]
mod imp;
}
target_os = "freebsd" => {
#[path = "refcount/freebsd.rs"]
mod imp;
}
target_os = "fuchsia" => {
#[path = "refcount/fuchsia.rs"]
mod imp;
}
target_os = "netbsd" => {
#[path = "refcount/netbsd.rs"]
mod imp;
}
target_os = "openbsd" => {
#[path = "refcount/openbsd.rs"]
mod imp;
}
target_os = "redox" => {
#[path = "refcount/redox.rs"]
mod imp;
}
target_vendor = "apple" => {
#[path = "refcount/macos.rs"]
mod imp;
}
target_family = "windows" => {
#[path = "refcount/windows.rs"]
mod imp;
}
feature = "spin" => {
#[path = "refcount/spin.rs"]
mod imp;
}
_ => {
compile_error!(
"lien: no futex implementation for this platform; \
enable the `spin` feature for a (costly) fallback"
);
}
}