Skip to content

Commit 00f1175

Browse files
refactor: avoid direct libc calls to get Duration from Instant
1 parent 942af00 commit 00f1175

File tree

5 files changed

+92
-62
lines changed

5 files changed

+92
-62
lines changed

Cargo.lock

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,6 @@ socket2 = { version = "0.5.1", features = ["all"] }
2121
getrandom = "0.3.1"
2222
tokio = { version = "1.25", features = ["net", "sync", "rt"] }
2323

24-
# weak
25-
libc = "0.2"
26-
2724
# stream
2825
futures-core = { version = "0.3", optional = true }
2926

src/instant.rs

Lines changed: 73 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,82 +1,114 @@
1-
use std::{mem, ops::Sub, time::Duration};
1+
use std::{
2+
ops::Sub,
3+
time::{Duration, Instant},
4+
};
5+
6+
#[derive(Debug, Clone)]
7+
pub struct ReferenceInstant {
8+
#[cfg(not(feature = "strong"))]
9+
instant: Instant,
10+
}
211

3-
#[derive(Copy, Clone)]
4-
pub struct Instant {
5-
spec: libc::timespec,
12+
#[derive(Debug, Copy, Clone)]
13+
pub struct RelativeInstant {
14+
#[cfg(feature = "strong")]
15+
relative: Instant,
16+
#[cfg(not(feature = "strong"))]
17+
relative: Duration,
618
}
719

8-
impl Instant {
9-
pub fn now() -> Self {
10-
let mut spec = unsafe { mem::zeroed() };
11-
unsafe {
12-
libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut spec as *mut _);
20+
impl ReferenceInstant {
21+
pub fn new() -> Self {
22+
Self {
23+
#[cfg(not(feature = "strong"))]
24+
instant: Instant::now(),
1325
}
14-
Self { spec }
1526
}
1627

17-
pub const ENCODED_LEN: usize = mem::size_of::<libc::timespec>();
18-
19-
pub fn encode(&self) -> [u8; Self::ENCODED_LEN] {
20-
// SAFETY: transmuting between items of the same length is fine
21-
unsafe { mem::transmute_copy(&self.spec) }
28+
pub fn now(&self) -> RelativeInstant {
29+
RelativeInstant {
30+
#[cfg(feature = "strong")]
31+
relative: Instant::now(),
32+
#[cfg(not(feature = "strong"))]
33+
relative: self.instant.elapsed(),
34+
}
2235
}
36+
}
2337

24-
pub fn decode(bytes: &[u8; Self::ENCODED_LEN]) -> Option<Self> {
25-
// SAFETY: transmuting between items of the same length is fine
26-
let spec: libc::timespec = unsafe { mem::transmute_copy(bytes) };
38+
impl RelativeInstant {
39+
#[cfg(not(feature = "strong"))]
40+
pub const ENCODED_LEN: usize = 12;
2741

28-
if spec.tv_sec >= 0 && spec.tv_nsec >= 0 {
29-
Some(Self { spec })
30-
} else {
31-
None
32-
}
42+
#[cfg(not(feature = "strong"))]
43+
pub fn encode(&self) -> [u8; Self::ENCODED_LEN] {
44+
let mut buf = [0u8; Self::ENCODED_LEN];
45+
let (secs, nanos) = buf.split_at_mut(8);
46+
secs.copy_from_slice(&self.relative.as_secs().to_ne_bytes());
47+
nanos.copy_from_slice(&self.relative.subsec_nanos().to_ne_bytes());
48+
49+
buf
3350
}
34-
}
3551

36-
impl From<Instant> for Duration {
37-
fn from(instant: Instant) -> Self {
38-
Duration::new(instant.spec.tv_sec as _, instant.spec.tv_nsec as _)
52+
#[cfg(not(feature = "strong"))]
53+
pub fn decode(buf: &[u8; Self::ENCODED_LEN]) -> Option<Self> {
54+
let (secs, nanos) = buf.split_at(8);
55+
let secs = u64::from_ne_bytes(secs.try_into().unwrap());
56+
let nanos = u32::from_ne_bytes(nanos.try_into().unwrap());
57+
58+
let relative = Duration::from_secs(secs).checked_add(Duration::from_nanos(nanos.into()))?;
59+
Some(Self { relative })
3960
}
4061
}
4162

42-
impl Sub<Instant> for Instant {
63+
impl Sub<RelativeInstant> for RelativeInstant {
4364
type Output = Duration;
4465

45-
fn sub(self, other: Instant) -> Self::Output {
46-
Duration::from(self).saturating_sub(Duration::from(other))
66+
fn sub(self, rhs: RelativeInstant) -> Self::Output {
67+
#[cfg(feature = "strong")]
68+
{
69+
self.relative.saturating_duration_since(rhs.relative)
70+
}
71+
72+
#[cfg(not(feature = "strong"))]
73+
{
74+
self.relative.saturating_sub(rhs.relative)
75+
}
4776
}
4877
}
4978

5079
#[cfg(test)]
5180
mod tests {
5281
use std::time::Duration;
5382

54-
use super::Instant;
83+
use super::ReferenceInstant;
84+
#[cfg(not(feature = "strong"))]
85+
use super::RelativeInstant;
5586

5687
#[test]
5788
fn passing_time() {
58-
let a = Instant::now();
59-
let b = Instant::now();
89+
let reference = ReferenceInstant::new();
90+
let a = reference.now();
91+
let b = reference.now();
6092

6193
assert!(b - a <= Duration::from_millis(10));
6294
}
6395

6496
#[test]
6597
fn wrong_order() {
66-
let a = Instant::now();
67-
let b = Instant::now();
98+
let reference = ReferenceInstant::new();
99+
let a = reference.now();
100+
let b = reference.now();
68101

69102
assert_eq!(a - b, Duration::ZERO);
70103
}
71104

72105
#[test]
106+
#[cfg(not(feature = "strong"))]
73107
fn encode_decode() {
74-
let a1 = Instant::now();
75-
let a1_duration = Duration::from(a1);
76-
77-
let a2 = Instant::decode(a1.encode()).unwrap();
78-
let a2_duration = Duration::from(a2);
108+
let reference = ReferenceInstant::new();
109+
let a1 = reference.now();
110+
let a2 = RelativeInstant::decode(&a1.encode()).unwrap();
79111

80-
assert_eq!(a1_duration, a2_duration);
112+
assert_eq!(a1.relative, a2.relative);
81113
}
82114
}

src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ pub use self::{
4646
pinger::{MeasureManyStream, Pinger, V4Pinger, V6Pinger},
4747
};
4848

49-
#[cfg(not(feature = "strong"))]
5049
mod instant;
5150
mod ip_version;
5251
pub mod packet;

src/pinger.rs

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
#[cfg(feature = "strong")]
2-
use std::time::Instant;
31
use std::{
42
collections::HashMap,
53
io,
@@ -24,8 +22,7 @@ use tokio::{
2422
task,
2523
};
2624

27-
#[cfg(not(feature = "strong"))]
28-
use crate::instant::Instant;
25+
use crate::instant::{ReferenceInstant, RelativeInstant};
2926
use crate::{
3027
packet::EchoRequestPacket,
3128
raw_pinger::{RawBlockingPinger, RawPinger},
@@ -44,6 +41,7 @@ pub struct Pinger<V: IpVersion> {
4441

4542
struct InnerPinger<V: IpVersion> {
4643
raw: RawPinger<V>,
44+
reference: ReferenceInstant,
4745
round_sender: mpsc::UnboundedSender<RoundMessage<V>>,
4846
identifier: u16,
4947
sequence_number: AtomicU16,
@@ -53,9 +51,9 @@ enum RoundMessage<V: IpVersion> {
5351
Subscribe {
5452
sequence_number: u16,
5553
#[cfg(feature = "strong")]
56-
sender: mpsc::UnboundedSender<(V, Instant)>,
54+
sender: mpsc::UnboundedSender<(V, RelativeInstant)>,
5755
#[cfg(not(feature = "strong"))]
58-
sender: mpsc::UnboundedSender<(V, Instant, Instant)>,
56+
sender: mpsc::UnboundedSender<(V, RelativeInstant, RelativeInstant)>,
5957
},
6058
Unsubscribe {
6159
sequence_number: u16,
@@ -70,6 +68,7 @@ impl<V: IpVersion> Pinger<V> {
7068
/// be beneficial to `Drop` the `Pinger` and recreate it if
7169
/// you are not going to be sending pings for a long period of time.
7270
pub fn new() -> io::Result<Self> {
71+
let reference = ReferenceInstant::new();
7372
let raw = RawPinger::new()?;
7473
let raw_blocking = RawBlockingPinger::new()?;
7574

@@ -81,6 +80,7 @@ impl<V: IpVersion> Pinger<V> {
8180

8281
let inner = Arc::new(InnerPinger {
8382
raw,
83+
reference: reference.clone(),
8484
round_sender: sender,
8585
identifier,
8686
sequence_number: AtomicU16::new(0),
@@ -89,11 +89,14 @@ impl<V: IpVersion> Pinger<V> {
8989
let mut buf = [MaybeUninit::<u8>::uninit(); 1600];
9090

9191
#[cfg(feature = "strong")]
92-
let mut subscribers: HashMap<u16, mpsc::UnboundedSender<(V, Instant)>> = HashMap::new();
92+
let mut subscribers: HashMap<
93+
u16,
94+
mpsc::UnboundedSender<(V, RelativeInstant)>,
95+
> = HashMap::new();
9396
#[cfg(not(feature = "strong"))]
9497
let mut subscribers: HashMap<
9598
u16,
96-
mpsc::UnboundedSender<(V, Instant, Instant)>,
99+
mpsc::UnboundedSender<(V, RelativeInstant, RelativeInstant)>,
97100
> = HashMap::new();
98101
'packets: loop {
99102
let maybe_packet = match raw_blocking.recv(&mut buf) {
@@ -106,13 +109,13 @@ impl<V: IpVersion> Pinger<V> {
106109

107110
match &maybe_packet {
108111
Some(packet) if packet.identifier() == identifier => {
109-
let recv_instant = Instant::now();
112+
let recv_instant = reference.now();
110113

111114
#[cfg(not(feature = "strong"))]
112115
let send_instant = {
113116
let payload = packet.payload();
114-
match Instant::decode(
115-
payload[..Instant::ENCODED_LEN].try_into().unwrap(),
117+
match RelativeInstant::decode(
118+
payload[..RelativeInstant::ENCODED_LEN].try_into().unwrap(),
116119
) {
117120
Some(send_instant) => send_instant,
118121
None => continue 'packets,
@@ -271,11 +274,11 @@ pub struct MeasureManyStream<'a, V: IpVersion, I: Iterator<Item = V>> {
271274
pinger: &'a Pinger<V>,
272275
send_queue: Peekable<I>,
273276
#[cfg(feature = "strong")]
274-
in_flight: HashMap<V, Instant>,
277+
in_flight: HashMap<V, RelativeInstant>,
275278
#[cfg(feature = "strong")]
276-
receiver: mpsc::UnboundedReceiver<(V, Instant)>,
279+
receiver: mpsc::UnboundedReceiver<(V, RelativeInstant)>,
277280
#[cfg(not(feature = "strong"))]
278-
receiver: mpsc::UnboundedReceiver<(V, Instant, Instant)>,
281+
receiver: mpsc::UnboundedReceiver<(V, RelativeInstant, RelativeInstant)>,
279282
sequence_number: u16,
280283
}
281284

@@ -299,7 +302,7 @@ impl<V: IpVersion, I: Iterator<Item = V>> MeasureManyStream<'_, V, I> {
299302
getrandom::fill(&mut payload).expect("generate random payload");
300303
#[cfg(not(feature = "strong"))]
301304
{
302-
let now = Instant::now().encode();
305+
let now = self.pinger.inner.reference.now().encode();
303306
let (now_part, random_part) = payload.split_at_mut(now.len());
304307
now_part.copy_from_slice(&now);
305308
getrandom::fill(random_part).expect("generate random payload");
@@ -313,7 +316,7 @@ impl<V: IpVersion, I: Iterator<Item = V>> MeasureManyStream<'_, V, I> {
313316
match self.pinger.inner.raw.poll_send_to(cx, addr, &packet) {
314317
Poll::Ready(_) => {
315318
#[cfg(feature = "strong")]
316-
let sent_at = Instant::now();
319+
let sent_at = self.pinger.inner.reference.now();
317320

318321
let taken_addr = self.send_queue.next();
319322
debug_assert!(taken_addr.is_some());

0 commit comments

Comments
 (0)