use crate::{TelemetryError, TelemetryResult};
use core::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
pub type MemoryAdmissionProbe = extern "C" fn(usize, usize) -> bool;
pub type MemoryAdmissionProbeV2 = extern "C" fn(usize, usize, u32) -> bool;
pub const WORK_GENERAL: u32 = 0;
pub const WORK_CACHED_TRANSIT: u32 = 1;
pub const WORK_SMALL_PROTECTED: u32 = 2;
static PROBE_V2: AtomicPtr<()> = AtomicPtr::new(core::ptr::null_mut());
static PROBE: AtomicPtr<()> = AtomicPtr::new(core::ptr::null_mut());
static REJECTED: AtomicUsize = AtomicUsize::new(0);
pub fn set_probe(probe: Option<MemoryAdmissionProbe>) {
PROBE_V2.store(core::ptr::null_mut(), Ordering::Release);
PROBE.store(
probe.map_or(core::ptr::null_mut(), |f| f as *mut ()),
Ordering::Release,
);
}
pub fn set_probe_v2(probe: Option<MemoryAdmissionProbeV2>) {
PROBE.store(core::ptr::null_mut(), Ordering::Release);
PROBE_V2.store(
probe.map_or(core::ptr::null_mut(), |f| f as *mut ()),
Ordering::Release,
);
}
pub(crate) fn supports_work_kinds() -> bool {
!PROBE_V2.load(Ordering::Relaxed).is_null()
}
fn has_probe() -> bool {
supports_work_kinds() || !PROBE.load(Ordering::Relaxed).is_null()
}
pub fn rejected_operations() -> usize {
REJECTED.load(Ordering::Relaxed)
}
pub(crate) fn check(additional_bytes: usize, largest_allocation: usize) -> TelemetryResult<()> {
check_work(additional_bytes, largest_allocation, WORK_GENERAL)
}
fn check_work(
additional_bytes: usize,
largest_allocation: usize,
work: u32,
) -> TelemetryResult<()> {
let extended = PROBE_V2.load(Ordering::Acquire);
let allowed = if !extended.is_null() {
let probe: MemoryAdmissionProbeV2 = unsafe { core::mem::transmute(extended) };
probe(additional_bytes, largest_allocation, work)
} else {
let ptr = PROBE.load(Ordering::Acquire);
if ptr.is_null() {
return Ok(());
}
let probe: MemoryAdmissionProbe = unsafe { core::mem::transmute(ptr) };
probe(additional_bytes, largest_allocation)
};
if allowed {
return Ok(());
}
REJECTED.fetch_add(1, Ordering::Relaxed);
Err(TelemetryError::Io("memory pressure"))
}
pub(crate) fn check_cached_transit(len: usize) -> TelemetryResult<()> {
let ptr = PROBE_V2.load(Ordering::Acquire);
if ptr.is_null() {
return check_frame(len, false);
}
let probe: MemoryAdmissionProbeV2 = unsafe { core::mem::transmute(ptr) };
if probe(
1024usize.saturating_add(len.saturating_mul(2)),
256,
WORK_CACHED_TRANSIT,
) {
return Ok(());
}
REJECTED.fetch_add(1, Ordering::Relaxed);
Err(TelemetryError::Io("memory pressure"))
}
pub(crate) fn check_receive(bytes: &[u8]) -> TelemetryResult<()> {
if !has_probe() {
return Ok(());
}
let frame = crate::wire_format::peek_routing_frame_info(bytes).ok();
let ack = frame.as_ref().is_some_and(|frame| {
frame.ack_only()
|| matches!(
frame.envelope.ty,
crate::DataType::ReliableAck
| crate::DataType::ReliablePartialAck
| crate::DataType::DiscoveryAnnounce
)
});
if !ack
&& supports_work_kinds()
&& bytes.len() <= 128
&& bytes.first().is_some_and(|flags| flags & 0x11 == 0)
&& frame.as_ref().is_some_and(|frame| {
let Some(meta) = crate::config::try_get_message_meta(frame.envelope.ty) else {
return false;
};
let crate::MessageElement::Static(count, crate::MessageDataType::UInt8, _) =
meta.element
else {
return false;
};
meta.priority >= 200
&& frame.reliable.is_some()
&& count <= 16
&& matches!(
frame.envelope.wire_shape,
None | Some(crate::MessageElement::Static(
0..=16,
crate::MessageDataType::UInt8,
_
))
)
&& bytes.get(1).is_some_and(|count| *count <= 3)
&& frame.envelope.target_senders().len() <= 3
})
{
return check_frame_kind(bytes.len(), false, WORK_SMALL_PROTECTED);
}
check_frame(bytes.len(), ack)
}
pub(crate) fn check_frame(len: usize, ack: bool) -> TelemetryResult<()> {
check_frame_kind(len, ack, WORK_GENERAL)
}
#[inline(never)]
fn check_frame_kind(len: usize, ack: bool, work: u32) -> TelemetryResult<()> {
if ack && len <= 128 {
check(512, len.saturating_add(32))
} else {
check_work(
len.saturating_mul(3).saturating_add(2048),
len.saturating_add(32),
work,
)
}
}
#[unsafe(no_mangle)]
pub extern "C" fn seds_set_memory_admission_probe(probe: Option<MemoryAdmissionProbe>) {
set_probe(probe);
}
#[unsafe(no_mangle)]
pub extern "C" fn seds_set_memory_admission_probe_v2(probe: Option<MemoryAdmissionProbeV2>) {
set_probe_v2(probe);
}
#[unsafe(no_mangle)]
pub extern "C" fn seds_memory_admission_rejected() -> usize {
rejected_operations()
}
pub(crate) fn allow_drain<T: Default>(result: TelemetryResult<T>) -> TelemetryResult<T> {
match result {
Err(TelemetryError::Io("memory pressure")) => Ok(T::default()),
other => other,
}
}