libFenrir/src/inner/mod.rs
Luca Fulchir d8a27bf969
Stream ROB: Reconstruct data TCP-like
this was more convoluted than I thought.
maybe someone will simplify this.

Signed-off-by: Luca Fulchir <luca.fulchir@runesauth.com>
2023-06-25 19:22:40 +02:00

125 lines
3.9 KiB
Rust

//! Inner Fenrir tracking
//! This is meant to be **async-free** so that others might use it
//! without the tokio runtime
pub(crate) mod worker;
use crate::inner::worker::Work;
use ::std::{collections::BTreeMap, vec::Vec};
use ::tokio::time::Instant;
/// Track the total number of threads and our index
/// 65K cpus should be enough for anybody
#[derive(Debug, Clone, Copy)]
pub(crate) struct ThreadTracker {
pub total: u16,
/// Note: starts from 1
pub id: u16,
}
pub(crate) static mut SLEEP_RESOLUTION: ::std::time::Duration =
if cfg!(linux) || cfg!(macos) {
::std::time::Duration::from_millis(1)
} else {
// windows
::std::time::Duration::from_millis(16)
};
pub(crate) async fn set_minimum_sleep_resolution() {
let nanosleep = ::std::time::Duration::from_nanos(1);
let mut tests: usize = 3;
while tests > 0 {
let pre_sleep = ::std::time::Instant::now();
::tokio::time::sleep(nanosleep).await;
let post_sleep = ::std::time::Instant::now();
let slept_for = post_sleep - pre_sleep;
#[allow(unsafe_code)]
unsafe {
if slept_for < SLEEP_RESOLUTION {
SLEEP_RESOLUTION = slept_for;
}
}
tests = tests - 1;
}
}
/// Sleeping has a higher resolution that we would like for packet pacing.
/// So we sleep for however log we need, then chunk up all the work here
/// we will end up chunking the work in SLEEP_RESOLUTION, then we will busy wait
/// for more precise timing
pub(crate) struct Timers {
times: BTreeMap<Instant, Work>,
}
impl Timers {
pub(crate) fn new() -> Self {
Self {
times: BTreeMap::new(),
}
}
pub(crate) fn get_next(&self) -> ::tokio::time::Sleep {
match self.times.keys().next() {
Some(entry) => ::tokio::time::sleep_until((*entry).into()),
None => {
::tokio::time::sleep(::std::time::Duration::from_secs(3600))
}
}
}
pub(crate) fn add(
&mut self,
duration: ::tokio::time::Duration,
work: Work,
) -> ::tokio::time::Instant {
// the returned time is the key in the map.
// Make sure it is unique.
//
// We can be pretty sure we won't do a lot of stuff
// in a single nanosecond, so if we hit a time that is already present
// just add a nanosecond and retry
let mut time = ::tokio::time::Instant::now() + duration;
let mut work = work;
loop {
if let Some(old_val) = self.times.insert(time, work) {
work = self.times.insert(time, old_val).unwrap();
time = time + ::std::time::Duration::from_nanos(1);
} else {
break;
}
}
time
}
pub(crate) fn remove(&mut self, time: ::tokio::time::Instant) {
let _ = self.times.remove(&time);
}
/// Get all the work from now up until now + SLEEP_RESOLUTION
pub(crate) fn get_work(&mut self) -> Vec<Work> {
let now: ::tokio::time::Instant = ::std::time::Instant::now().into();
let mut ret = Vec::with_capacity(4);
let mut count_rm = 0;
#[allow(unsafe_code)]
let next_instant = unsafe { now + SLEEP_RESOLUTION };
let mut iter = self.times.iter_mut().peekable();
loop {
match iter.peek() {
None => break,
Some(next) => {
if *next.0 > next_instant {
break;
}
}
}
let mut work = Work::DropHandshake(crate::enc::asym::KeyID(0));
let mut entry = iter.next().unwrap();
::core::mem::swap(&mut work, &mut entry.1);
ret.push(work);
count_rm = count_rm + 1;
}
while count_rm > 0 {
self.times.pop_first();
count_rm = count_rm - 1;
}
ret
}
}