//! 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, } 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 { 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 } }