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