1use crate::{
8 AsHandleRef, BootTimeline, ClockUpdate, Handle, HandleBased, HandleRef, Instant,
9 MonotonicTimeline, ObjectQuery, SyntheticTimeline, Timeline, Topic, object_get_info_single, ok,
10 sys,
11};
12use bitflags::bitflags;
13use std::mem::MaybeUninit;
14use std::ptr;
15use zx_status::Status;
16
17#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
26#[repr(transparent)]
27pub struct Clock<Reference = MonotonicTimeline, Output = SyntheticTimeline>(
28 Handle,
29 std::marker::PhantomData<(Reference, Output)>,
30);
31
32pub type SyntheticClock = Clock<MonotonicTimeline, SyntheticTimeline>;
33pub type SyntheticClockOnBoot = Clock<BootTimeline, SyntheticTimeline>;
34
35impl<Output: Timeline> Clock<MonotonicTimeline, Output> {
36 pub fn create(opts: ClockOpts, backstop: Option<Instant<Output>>) -> Result<Self, Status> {
41 let mut out = 0;
42 let status = match backstop {
43 Some(backstop) => {
44 let args = sys::zx_clock_create_args_v1_t { backstop_time: backstop.into_nanos() };
46 unsafe {
47 sys::zx_clock_create(
48 sys::ZX_CLOCK_ARGS_VERSION_1 | opts.bits(),
49 std::ptr::from_ref(&args).cast::<u8>(),
50 &mut out,
51 )
52 }
53 }
54 None => unsafe { sys::zx_clock_create(opts.bits(), ptr::null(), &mut out) },
55 };
56 ok(status)?;
57 unsafe { Ok(Self::from(Handle::from_raw(out))) }
58 }
59}
60
61impl<Output: Timeline> Clock<BootTimeline, Output> {
62 pub fn create(opts: ClockOpts, backstop: Option<Instant<Output>>) -> Result<Self, Status> {
67 let mut out = 0;
68 let opts = opts | ClockOpts::BOOT;
69 let status = match backstop {
70 Some(backstop) => {
71 let args = sys::zx_clock_create_args_v1_t { backstop_time: backstop.into_nanos() };
73 unsafe {
74 sys::zx_clock_create(
75 sys::ZX_CLOCK_ARGS_VERSION_1 | opts.bits(),
76 &args as *const _ as *const u8,
77 &mut out,
78 )
79 }
80 }
81 None => unsafe { sys::zx_clock_create(opts.bits(), ptr::null(), &mut out) },
82 };
83 ok(status)?;
84 unsafe { Ok(Self::from(Handle::from_raw(out))) }
85 }
86}
87
88impl<Reference: Timeline, Output: Timeline> Clock<Reference, Output> {
89 pub fn read(&self) -> Result<Instant<Output>, Status> {
94 let mut now = 0;
95 let status = unsafe { sys::zx_clock_read(self.raw_handle(), &mut now) };
96 ok(status)?;
97 Ok(Instant::<Output>::from_nanos(now))
98 }
99
100 pub unsafe fn read_mapped(clock_addr: usize) -> Result<Instant<Output>, Status> {
111 let mut now = 0;
112 let status = unsafe {
113 sys::zx_clock_read_mapped(clock_addr as *const u8, &mut now)
115 };
116 ok(status)?;
117 Ok(Instant::<Output>::from_nanos(now))
118 }
119
120 pub fn get_details(&self) -> Result<ClockDetails<Reference, Output>, Status> {
125 let mut out_details = MaybeUninit::<sys::zx_clock_details_v1_t>::uninit();
126 let status = unsafe {
127 sys::zx_clock_get_details(
128 self.raw_handle(),
129 sys::ZX_CLOCK_ARGS_VERSION_1,
130 out_details.as_mut_ptr().cast::<u8>(),
131 )
132 };
133 ok(status)?;
134 let out_details = unsafe { out_details.assume_init() };
135 Ok(out_details.into())
136 }
137
138 pub unsafe fn get_details_mapped(
150 clock_addr: usize,
151 ) -> Result<ClockDetails<Reference, Output>, Status> {
152 let mut out_details = MaybeUninit::<sys::zx_clock_details_v1_t>::uninit();
153 let status = unsafe {
154 sys::zx_clock_get_details_mapped(
156 clock_addr as *const u8,
157 sys::ZX_CLOCK_ARGS_VERSION_1,
158 out_details.as_mut_ptr().cast::<u8>(),
159 )
160 };
161 ok(status)?;
162 let out_details = unsafe { out_details.assume_init() };
163 Ok(out_details.into())
164 }
165
166 pub fn get_mapped_size(clock: &Clock<Reference, Output>) -> Result<usize, Status> {
168 Ok(object_get_info_single::<MappedSizeQuery>(clock.as_handle_ref())?)
169 }
170
171 pub fn update(&self, update: impl Into<ClockUpdate<Reference, Output>>) -> Result<(), Status> {
176 let update = update.into();
177 let options = update.options();
178 let args = update.args();
179 let status = unsafe {
180 sys::zx_clock_update(self.raw_handle(), options, std::ptr::from_ref(&args).cast::<u8>())
181 };
182 ok(status)?;
183 Ok(())
184 }
185
186 pub fn downcast<NewReference: Timeline>(self) -> Clock<NewReference, SyntheticTimeline> {
189 Clock(self.0, std::marker::PhantomData)
190 }
191}
192
193impl<Reference: Timeline> Clock<Reference, SyntheticTimeline> {
194 pub fn cast<NewReference: Timeline, UserTimeline: Timeline>(
197 self,
198 ) -> Clock<NewReference, UserTimeline> {
199 Clock(self.0, std::marker::PhantomData)
200 }
201}
202
203impl<Reference: Timeline, Output: Timeline> AsHandleRef for Clock<Reference, Output> {
204 fn as_handle_ref(&self) -> HandleRef<'_> {
205 self.0.as_handle_ref()
206 }
207}
208
209impl<Reference: Timeline, Output: Timeline> From<Handle> for Clock<Reference, Output> {
210 fn from(handle: Handle) -> Self {
211 Clock(handle, std::marker::PhantomData)
212 }
213}
214
215impl<Reference: Timeline, Output: Timeline> From<Clock<Reference, Output>> for Handle {
216 fn from(x: Clock<Reference, Output>) -> Handle {
217 x.0
218 }
219}
220
221impl<Reference: Timeline, Output: Timeline> HandleBased for Clock<Reference, Output> {}
222
223struct MappedSizeQuery;
224unsafe impl ObjectQuery for MappedSizeQuery {
225 const TOPIC: Topic = Topic::CLOCK_MAPPED_SIZE;
226 type InfoTy = usize;
227}
228
229bitflags! {
230 #[repr(transparent)]
231 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
232 pub struct ClockOpts: u64 {
233 const MONOTONIC = sys::ZX_CLOCK_OPT_MONOTONIC;
236
237 const CONTINUOUS = sys::ZX_CLOCK_OPT_CONTINUOUS | Self::MONOTONIC.bits();
241
242 const AUTO_START = sys::ZX_CLOCK_OPT_AUTO_START;
246
247 const BOOT = sys::ZX_CLOCK_OPT_BOOT;
249
250 const MAPPABLE = sys::ZX_CLOCK_OPT_MAPPABLE;
253 }
254}
255
256#[derive(Debug, Clone, PartialEq, Eq)]
258pub struct ClockDetails<Reference = MonotonicTimeline, Output = SyntheticTimeline> {
259 pub backstop: Instant<Output>,
261
262 pub ticks_to_synthetic: ClockTransformation<Reference, Output>,
264
265 pub reference_to_synthetic: ClockTransformation<Reference, Output>,
267
268 pub error_bounds: u64,
270
271 pub query_ticks: sys::zx_ticks_t,
274
275 pub last_value_update_ticks: sys::zx_ticks_t,
278
279 pub last_rate_adjust_update_ticks: sys::zx_ticks_t,
282
283 pub last_error_bounds_update_ticks: sys::zx_ticks_t,
286
287 pub generation_counter: u32,
289}
290
291impl<Reference: Timeline, Output: Timeline> From<sys::zx_clock_details_v1_t>
292 for ClockDetails<Reference, Output>
293{
294 fn from(details: sys::zx_clock_details_v1_t) -> Self {
295 ClockDetails {
296 backstop: Instant::from_nanos(details.backstop_time),
297 ticks_to_synthetic: details.reference_ticks_to_synthetic.into(),
298 reference_to_synthetic: details.reference_to_synthetic.into(),
299 error_bounds: details.error_bound,
300 query_ticks: details.query_ticks,
301 last_value_update_ticks: details.last_value_update_ticks,
302 last_rate_adjust_update_ticks: details.last_rate_adjust_update_ticks,
303 last_error_bounds_update_ticks: details.last_error_bounds_update_ticks,
304 generation_counter: details.generation_counter,
305 }
306 }
307}
308
309#[derive(Debug, Clone, Eq, PartialEq)]
314pub struct ClockTransformation<Reference = MonotonicTimeline, Output = SyntheticTimeline> {
315 pub reference_offset: Instant<Reference>,
317 pub synthetic_offset: Instant<Output>,
320 pub rate: sys::zx_clock_rate_t,
322}
323
324impl<Reference: Timeline, Output: Timeline> From<sys::zx_clock_transformation_t>
325 for ClockTransformation<Reference, Output>
326{
327 fn from(ct: sys::zx_clock_transformation_t) -> Self {
328 ClockTransformation {
329 reference_offset: Instant::<Reference>::from_nanos(ct.reference_offset),
330 synthetic_offset: Instant::<Output>::from_nanos(ct.synthetic_offset),
331 rate: ct.rate,
332 }
333 }
334}
335
336fn transform_clock(r: i64, r_offset: i64, c_offset: i64, r_rate: u32, c_rate: u32) -> i64 {
346 assert!(r_rate != 0, "r_rate may not be zero");
347 let r = r as i128;
348 let r_offset = r_offset as i128;
349 let c_offset = c_offset as i128;
350 let r_rate = r_rate as i128;
351 let c_rate = c_rate as i128;
352 let c = (((r - r_offset) * c_rate) / r_rate) + c_offset;
353 c.try_into().unwrap_or_else(|_| if c.is_positive() { i64::MAX } else { i64::MIN })
354}
355
356impl<Reference: Timeline + Copy, Output: Timeline + Copy> ClockTransformation<Reference, Output> {
363 pub fn apply(&self, time: Instant<Reference>) -> Instant<Output> {
369 let c = transform_clock(
370 time.into_nanos(),
371 self.reference_offset.into_nanos(),
372 self.synthetic_offset.into_nanos(),
373 self.rate.reference_ticks,
374 self.rate.synthetic_ticks,
375 );
376
377 Instant::from_nanos(c)
378 }
379
380 pub fn apply_inverse(&self, time: Instant<Output>) -> Instant<Reference> {
386 let r = transform_clock(
387 time.into_nanos(),
388 self.synthetic_offset.into_nanos(),
389 self.reference_offset.into_nanos(),
390 self.rate.synthetic_ticks,
391 self.rate.reference_ticks,
392 );
393
394 Instant::from_nanos(r as i64)
395 }
396}
397
398#[cfg(test)]
399mod tests {
400 use super::*;
401 use crate::{MonotonicInstant, SyntheticInstant};
402 use assert_matches::assert_matches;
403
404 #[test]
405 fn create_clocks() {
406 assert_matches!(SyntheticClock::create(ClockOpts::empty(), None), Ok(_));
407 assert_matches!(SyntheticClock::create(ClockOpts::MONOTONIC, None), Ok(_));
408 assert_matches!(SyntheticClock::create(ClockOpts::CONTINUOUS, None), Ok(_));
409 assert_matches!(
410 SyntheticClock::create(ClockOpts::AUTO_START | ClockOpts::MONOTONIC, None),
411 Ok(_)
412 );
413 assert_matches!(
414 SyntheticClock::create(ClockOpts::AUTO_START | ClockOpts::CONTINUOUS, None),
415 Ok(_)
416 );
417
418 let backstop = Some(SyntheticInstant::from_nanos(5500));
420 assert_matches!(SyntheticClock::create(ClockOpts::MONOTONIC, backstop), Ok(_));
421 assert_matches!(SyntheticClock::create(ClockOpts::CONTINUOUS, backstop), Ok(_));
422 assert_matches!(
423 SyntheticClock::create(ClockOpts::AUTO_START | ClockOpts::MONOTONIC, backstop),
424 Ok(_)
425 );
426 assert_matches!(
427 SyntheticClock::create(ClockOpts::AUTO_START | ClockOpts::CONTINUOUS, backstop),
428 Ok(_)
429 );
430 }
431
432 #[test]
433 fn read_time() {
434 let clock =
435 SyntheticClock::create(ClockOpts::MONOTONIC, None).expect("failed to create clock");
436 assert_matches!(clock.read(), Ok(_));
437 }
438
439 #[test]
440 fn get_clock_details() {
441 let clock =
443 SyntheticClock::create(ClockOpts::MONOTONIC, None).expect("failed to create clock");
444 let details = clock.get_details().expect("failed to get details");
445 assert_eq!(details.backstop, SyntheticInstant::from_nanos(0));
446
447 let clock =
449 SyntheticClock::create(ClockOpts::MONOTONIC, Some(SyntheticInstant::from_nanos(5500)))
450 .expect("failed to create clock");
451 let details = clock.get_details().expect("failed to get details");
452 assert_eq!(details.backstop, SyntheticInstant::from_nanos(5500));
453 }
454
455 #[test]
456 fn update_clock() {
457 let clock =
458 SyntheticClock::create(ClockOpts::MONOTONIC, None).expect("failed to create clock");
459 let before_details = clock.get_details().expect("failed to get details");
460 assert_eq!(before_details.last_value_update_ticks, 0);
461 assert_eq!(before_details.last_rate_adjust_update_ticks, 0);
462 assert_eq!(before_details.last_error_bounds_update_ticks, 0);
463
464 clock
466 .update(
467 ClockUpdate::builder()
468 .absolute_value(
469 MonotonicInstant::from_nanos(999),
470 SyntheticInstant::from_nanos(42),
471 )
472 .rate_adjust(52)
473 .error_bounds(52),
474 )
475 .expect("failed to update clock");
476 let after_details = clock.get_details().expect("failed to get details");
477 assert!(before_details.generation_counter < after_details.generation_counter);
478 assert!(after_details.last_value_update_ticks > before_details.last_value_update_ticks);
479 assert_eq!(
480 after_details.last_value_update_ticks,
481 after_details.last_rate_adjust_update_ticks
482 );
483 assert_eq!(
484 after_details.last_value_update_ticks,
485 after_details.last_error_bounds_update_ticks
486 );
487 assert_eq!(after_details.error_bounds, 52);
488 assert_eq!(after_details.ticks_to_synthetic.synthetic_offset.into_nanos(), 42);
489 assert_eq!(after_details.reference_to_synthetic.reference_offset.into_nanos(), 999);
490 assert_eq!(after_details.reference_to_synthetic.synthetic_offset.into_nanos(), 42);
491
492 let before_details = after_details;
493
494 clock.update(ClockUpdate::builder().error_bounds(100)).expect("failed to update clock");
496 let after_details = clock.get_details().expect("failed to get details");
497 assert!(before_details.generation_counter < after_details.generation_counter);
498 assert!(
499 after_details.last_error_bounds_update_ticks > before_details.last_value_update_ticks
500 );
501 assert!(
502 after_details.last_error_bounds_update_ticks
503 > after_details.last_rate_adjust_update_ticks
504 );
505 assert_eq!(
506 after_details.last_rate_adjust_update_ticks,
507 after_details.last_value_update_ticks
508 );
509 assert_eq!(after_details.error_bounds, 100);
510 assert_eq!(after_details.ticks_to_synthetic.synthetic_offset.into_nanos(), 42);
511 assert_eq!(after_details.reference_to_synthetic.synthetic_offset.into_nanos(), 42);
512 }
513
514 #[test]
515 fn clock_identity_transformation_roundtrip() {
516 let t_0 = MonotonicInstant::ZERO;
517 let xform = ClockTransformation {
519 reference_offset: MonotonicInstant::from_nanos(0),
520 synthetic_offset: SyntheticInstant::from_nanos(0),
521 rate: sys::zx_clock_rate_t { synthetic_ticks: 1, reference_ticks: 1 },
522 };
523
524 let transformed_time = xform.apply(t_0);
526 let original_time = xform.apply_inverse(transformed_time);
527 assert_eq!(t_0, original_time);
528 }
529
530 #[test]
531 fn clock_trivial_transformation() {
532 let t_0 = MonotonicInstant::ZERO;
533 let xform = ClockTransformation {
535 reference_offset: MonotonicInstant::from_nanos(3),
536 synthetic_offset: SyntheticInstant::from_nanos(2),
537 rate: sys::zx_clock_rate_t { synthetic_ticks: 6, reference_ticks: 2 },
538 };
539
540 let utc_time = xform.apply(t_0);
541 let monotonic_time = xform.apply_inverse(utc_time);
542 assert_eq!(3 * (t_0.into_nanos() - 3) + 2, utc_time.into_nanos());
544
545 assert_eq!(t_0, monotonic_time);
547 }
548
549 #[test]
550 fn clock_transformation_roundtrip() {
551 let t_0 = MonotonicInstant::ZERO;
552 let xform = ClockTransformation {
554 reference_offset: MonotonicInstant::from_nanos(196980085208),
555 synthetic_offset: SyntheticInstant::from_nanos(1616900096031887801),
556 rate: sys::zx_clock_rate_t { synthetic_ticks: 999980, reference_ticks: 1000000 },
557 };
558
559 let transformed_time = xform.apply(t_0);
561 let original_time = xform.apply_inverse(transformed_time);
562 let roundtrip_diff = t_0 - original_time;
563 assert!(roundtrip_diff.into_nanos().abs() <= 1);
564 }
565
566 #[test]
567 fn clock_trailing_transformation_roundtrip() {
568 let t_0 = MonotonicInstant::ZERO;
569 let xform = ClockTransformation {
572 reference_offset: MonotonicInstant::from_nanos(1616900096031887801),
573 synthetic_offset: SyntheticInstant::from_nanos(196980085208),
574 rate: sys::zx_clock_rate_t { synthetic_ticks: 1000000, reference_ticks: 999980 },
575 };
576
577 let transformed_time = xform.apply(t_0);
579 let original_time = xform.apply_inverse(transformed_time);
580 let roundtrip_diff = t_0 - original_time;
581 assert!(roundtrip_diff.into_nanos().abs() <= 1);
582 }
583
584 #[test]
585 fn clock_saturating_transformations() {
586 let t_0 = MonotonicInstant::from_nanos(i64::MAX);
587 let xform = ClockTransformation {
589 reference_offset: MonotonicInstant::from_nanos(0),
590 synthetic_offset: SyntheticInstant::from_nanos(1),
591 rate: sys::zx_clock_rate_t { synthetic_ticks: 1, reference_ticks: 1 },
592 };
593
594 let time = xform.apply(t_0).into_nanos();
596 assert_eq!(time, i64::MAX);
597
598 let t_0 = MonotonicInstant::from_nanos(i64::MIN);
599 let xform = ClockTransformation {
601 reference_offset: MonotonicInstant::from_nanos(1),
602 synthetic_offset: SyntheticInstant::from_nanos(0),
603 rate: sys::zx_clock_rate_t { synthetic_ticks: 1, reference_ticks: 1 },
604 };
605
606 let time = xform.apply(t_0).into_nanos();
608 assert_eq!(time, i64::MIN);
609 }
610}