1use crate::{
8 BootTimeline, ClockUpdate, Instant, MonotonicTimeline, NullableHandle, ObjectQuery,
9 SyntheticTimeline, Ticks, Timeline, Topic, ok, sys,
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 NullableHandle,
28 std::marker::PhantomData<(Reference, Output)>,
29);
30
31impl_handle_based!(Clock, [Reference: Timeline, Output: Timeline], [Reference, Output]);
32
33pub type SyntheticClock = Clock<MonotonicTimeline, SyntheticTimeline>;
34pub type SyntheticClockOnBoot = Clock<BootTimeline, SyntheticTimeline>;
35
36impl<Output: Timeline> Clock<MonotonicTimeline, Output> {
37 pub fn create(opts: ClockOpts, backstop: Option<Instant<Output>>) -> Result<Self, Status> {
42 let mut out = 0;
43 let status = match backstop {
44 Some(backstop) => {
45 let args = sys::zx_clock_create_args_v1_t { backstop_time: backstop.into_nanos() };
47 unsafe {
48 sys::zx_clock_create(
49 sys::ZX_CLOCK_ARGS_VERSION_1 | opts.bits(),
50 std::ptr::from_ref(&args).cast::<u8>(),
51 &mut out,
52 )
53 }
54 }
55 None => unsafe { sys::zx_clock_create(opts.bits(), ptr::null(), &mut out) },
56 };
57 ok(status)?;
58 unsafe { Ok(Self::from(NullableHandle::from_raw(out))) }
59 }
60}
61
62impl<Output: Timeline> Clock<BootTimeline, Output> {
63 pub fn create(opts: ClockOpts, backstop: Option<Instant<Output>>) -> Result<Self, Status> {
68 let mut out = 0;
69 let opts = opts | ClockOpts::BOOT;
70 let status = match backstop {
71 Some(backstop) => {
72 let args = sys::zx_clock_create_args_v1_t { backstop_time: backstop.into_nanos() };
74 unsafe {
75 sys::zx_clock_create(
76 sys::ZX_CLOCK_ARGS_VERSION_1 | opts.bits(),
77 &args as *const _ as *const u8,
78 &mut out,
79 )
80 }
81 }
82 None => unsafe { sys::zx_clock_create(opts.bits(), ptr::null(), &mut out) },
83 };
84 ok(status)?;
85 unsafe { Ok(Self::from(NullableHandle::from_raw(out))) }
86 }
87}
88
89impl<Reference: Timeline, Output: Timeline> Clock<Reference, Output> {
90 pub fn read(&self) -> Result<Instant<Output>, Status> {
95 let mut now = 0;
96 let status = unsafe { sys::zx_clock_read(self.raw_handle(), &mut now) };
97 ok(status)?;
98 Ok(Instant::<Output>::from_nanos(now))
99 }
100
101 pub unsafe fn read_mapped(clock_addr: usize) -> Result<Instant<Output>, Status> {
112 let mut now = 0;
113 let status = unsafe {
114 sys::zx_clock_read_mapped(clock_addr as *const u8, &mut now)
116 };
117 ok(status)?;
118 Ok(Instant::<Output>::from_nanos(now))
119 }
120
121 pub fn get_details(&self) -> Result<ClockDetails<Reference, Output>, Status> {
126 let mut out_details = MaybeUninit::<sys::zx_clock_details_v1_t>::uninit();
127 let status = unsafe {
128 sys::zx_clock_get_details(
129 self.raw_handle(),
130 sys::ZX_CLOCK_ARGS_VERSION_1,
131 out_details.as_mut_ptr().cast::<u8>(),
132 )
133 };
134 ok(status)?;
135 let out_details = unsafe { out_details.assume_init() };
136 Ok(out_details.into())
137 }
138
139 pub unsafe fn get_details_mapped(
151 clock_addr: usize,
152 ) -> Result<ClockDetails<Reference, Output>, Status> {
153 let mut out_details = MaybeUninit::<sys::zx_clock_details_v1_t>::uninit();
154 let status = unsafe {
155 sys::zx_clock_get_details_mapped(
157 clock_addr as *const u8,
158 sys::ZX_CLOCK_ARGS_VERSION_1,
159 out_details.as_mut_ptr().cast::<u8>(),
160 )
161 };
162 ok(status)?;
163 let out_details = unsafe { out_details.assume_init() };
164 Ok(out_details.into())
165 }
166
167 pub fn get_mapped_size(clock: &Clock<Reference, Output>) -> Result<usize, Status> {
169 Ok(clock.0.get_info_single::<MappedSizeQuery>()?)
170 }
171
172 pub fn update(&self, update: impl Into<ClockUpdate<Reference, Output>>) -> Result<(), Status> {
177 let update = update.into();
178 let options = update.options();
179 let args = update.args();
180 let status = unsafe {
181 sys::zx_clock_update(self.raw_handle(), options, std::ptr::from_ref(&args).cast::<u8>())
182 };
183 ok(status)?;
184 Ok(())
185 }
186
187 pub fn downcast<NewReference: Timeline>(self) -> Clock<NewReference, SyntheticTimeline> {
190 Clock(self.0, std::marker::PhantomData)
191 }
192}
193
194impl<Reference: Timeline> Clock<Reference, SyntheticTimeline> {
195 pub fn cast<NewReference: Timeline, UserTimeline: Timeline>(
198 self,
199 ) -> Clock<NewReference, UserTimeline> {
200 Clock(self.0, std::marker::PhantomData)
201 }
202}
203
204struct MappedSizeQuery;
205unsafe impl ObjectQuery for MappedSizeQuery {
206 const TOPIC: Topic = Topic::CLOCK_MAPPED_SIZE;
207 type InfoTy = usize;
208}
209
210bitflags! {
211 #[repr(transparent)]
212 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
213 pub struct ClockOpts: u64 {
214 const MONOTONIC = sys::ZX_CLOCK_OPT_MONOTONIC;
217
218 const CONTINUOUS = sys::ZX_CLOCK_OPT_CONTINUOUS | Self::MONOTONIC.bits();
222
223 const AUTO_START = sys::ZX_CLOCK_OPT_AUTO_START;
227
228 const BOOT = sys::ZX_CLOCK_OPT_BOOT;
230
231 const MAPPABLE = sys::ZX_CLOCK_OPT_MAPPABLE;
234 }
235}
236
237#[derive(Debug, Clone, PartialEq, Eq)]
239pub struct ClockDetails<Reference = MonotonicTimeline, Output = SyntheticTimeline> {
240 pub backstop: Instant<Output>,
242
243 pub ticks_to_synthetic: ClockTransformation<Reference, Output>,
245
246 pub reference_to_synthetic: ClockTransformation<Reference, Output>,
248
249 pub error_bounds: u64,
251
252 pub query_ticks: Ticks<Reference>,
255
256 pub last_value_update_ticks: Ticks<Reference>,
258
259 pub last_rate_adjust_update_ticks: Ticks<Reference>,
261
262 pub last_error_bounds_update_ticks: Ticks<Reference>,
264
265 pub generation_counter: u32,
267}
268
269impl<Reference: Timeline, Output: Timeline> From<sys::zx_clock_details_v1_t>
270 for ClockDetails<Reference, Output>
271{
272 fn from(details: sys::zx_clock_details_v1_t) -> Self {
273 ClockDetails {
274 backstop: Instant::from_nanos(details.backstop_time),
275 ticks_to_synthetic: details.reference_ticks_to_synthetic.into(),
276 reference_to_synthetic: details.reference_to_synthetic.into(),
277 error_bounds: details.error_bound,
278 query_ticks: Ticks::from_raw(details.query_ticks),
279 last_value_update_ticks: Ticks::from_raw(details.last_value_update_ticks),
280 last_rate_adjust_update_ticks: Ticks::from_raw(details.last_rate_adjust_update_ticks),
281 last_error_bounds_update_ticks: Ticks::from_raw(details.last_error_bounds_update_ticks),
282 generation_counter: details.generation_counter,
283 }
284 }
285}
286
287#[derive(Debug, Clone, Eq, PartialEq)]
292pub struct ClockTransformation<Reference = MonotonicTimeline, Output = SyntheticTimeline> {
293 pub reference_offset: Instant<Reference>,
295 pub synthetic_offset: Instant<Output>,
298 pub rate: sys::zx_clock_rate_t,
300}
301
302impl<Reference: Timeline, Output: Timeline> From<sys::zx_clock_transformation_t>
303 for ClockTransformation<Reference, Output>
304{
305 fn from(ct: sys::zx_clock_transformation_t) -> Self {
306 ClockTransformation {
307 reference_offset: Instant::<Reference>::from_nanos(ct.reference_offset),
308 synthetic_offset: Instant::<Output>::from_nanos(ct.synthetic_offset),
309 rate: ct.rate,
310 }
311 }
312}
313
314fn transform_clock(r: i64, r_offset: i64, c_offset: i64, r_rate: u32, c_rate: u32) -> i64 {
324 assert!(r_rate != 0, "r_rate may not be zero");
325 let r = r as i128;
326 let r_offset = r_offset as i128;
327 let c_offset = c_offset as i128;
328 let r_rate = r_rate as i128;
329 let c_rate = c_rate as i128;
330 let c = (((r - r_offset) * c_rate) / r_rate) + c_offset;
331 c.try_into().unwrap_or_else(|_| if c.is_positive() { i64::MAX } else { i64::MIN })
332}
333
334impl<Reference: Timeline + Copy, Output: Timeline + Copy> ClockTransformation<Reference, Output> {
341 pub fn apply(&self, time: Instant<Reference>) -> Instant<Output> {
347 let c = transform_clock(
348 time.into_nanos(),
349 self.reference_offset.into_nanos(),
350 self.synthetic_offset.into_nanos(),
351 self.rate.reference_ticks,
352 self.rate.synthetic_ticks,
353 );
354
355 Instant::from_nanos(c)
356 }
357
358 pub fn apply_inverse(&self, time: Instant<Output>) -> Instant<Reference> {
364 let r = transform_clock(
365 time.into_nanos(),
366 self.synthetic_offset.into_nanos(),
367 self.reference_offset.into_nanos(),
368 self.rate.synthetic_ticks,
369 self.rate.reference_ticks,
370 );
371
372 Instant::from_nanos(r as i64)
373 }
374}
375
376#[cfg(test)]
377mod tests {
378 use super::*;
379 use crate::{MonotonicInstant, SyntheticInstant};
380 use assert_matches::assert_matches;
381
382 #[test]
383 fn create_clocks() {
384 assert_matches!(SyntheticClock::create(ClockOpts::empty(), None), Ok(_));
385 assert_matches!(SyntheticClock::create(ClockOpts::MONOTONIC, None), Ok(_));
386 assert_matches!(SyntheticClock::create(ClockOpts::CONTINUOUS, None), Ok(_));
387 assert_matches!(
388 SyntheticClock::create(ClockOpts::AUTO_START | ClockOpts::MONOTONIC, None),
389 Ok(_)
390 );
391 assert_matches!(
392 SyntheticClock::create(ClockOpts::AUTO_START | ClockOpts::CONTINUOUS, None),
393 Ok(_)
394 );
395
396 let backstop = Some(SyntheticInstant::from_nanos(5500));
398 assert_matches!(SyntheticClock::create(ClockOpts::MONOTONIC, backstop), Ok(_));
399 assert_matches!(SyntheticClock::create(ClockOpts::CONTINUOUS, backstop), Ok(_));
400 assert_matches!(
401 SyntheticClock::create(ClockOpts::AUTO_START | ClockOpts::MONOTONIC, backstop),
402 Ok(_)
403 );
404 assert_matches!(
405 SyntheticClock::create(ClockOpts::AUTO_START | ClockOpts::CONTINUOUS, backstop),
406 Ok(_)
407 );
408 }
409
410 #[test]
411 fn read_time() {
412 let clock =
413 SyntheticClock::create(ClockOpts::MONOTONIC, None).expect("failed to create clock");
414 assert_matches!(clock.read(), Ok(_));
415 }
416
417 #[test]
418 fn get_clock_details() {
419 let clock =
421 SyntheticClock::create(ClockOpts::MONOTONIC, None).expect("failed to create clock");
422 let details = clock.get_details().expect("failed to get details");
423 assert_eq!(details.backstop, SyntheticInstant::from_nanos(0));
424
425 let clock =
427 SyntheticClock::create(ClockOpts::MONOTONIC, Some(SyntheticInstant::from_nanos(5500)))
428 .expect("failed to create clock");
429 let details = clock.get_details().expect("failed to get details");
430 assert_eq!(details.backstop, SyntheticInstant::from_nanos(5500));
431 }
432
433 #[test]
434 fn update_clock() {
435 let clock =
436 SyntheticClock::create(ClockOpts::MONOTONIC, None).expect("failed to create clock");
437 let before_details = clock.get_details().expect("failed to get details");
438 assert_eq!(before_details.last_value_update_ticks, Ticks::from_raw(0));
439 assert_eq!(before_details.last_rate_adjust_update_ticks, Ticks::from_raw(0));
440 assert_eq!(before_details.last_error_bounds_update_ticks, Ticks::from_raw(0));
441
442 clock
444 .update(
445 ClockUpdate::builder()
446 .absolute_value(
447 MonotonicInstant::from_nanos(999),
448 SyntheticInstant::from_nanos(42),
449 )
450 .rate_adjust(52)
451 .error_bounds(52),
452 )
453 .expect("failed to update clock");
454 let after_details = clock.get_details().expect("failed to get details");
455 assert!(before_details.generation_counter < after_details.generation_counter);
456 assert!(after_details.last_value_update_ticks > before_details.last_value_update_ticks);
457 assert_eq!(
458 after_details.last_value_update_ticks,
459 after_details.last_rate_adjust_update_ticks
460 );
461 assert_eq!(
462 after_details.last_value_update_ticks,
463 after_details.last_error_bounds_update_ticks
464 );
465 assert_eq!(after_details.error_bounds, 52);
466 assert_eq!(after_details.ticks_to_synthetic.synthetic_offset.into_nanos(), 42);
467 assert_eq!(after_details.reference_to_synthetic.reference_offset.into_nanos(), 999);
468 assert_eq!(after_details.reference_to_synthetic.synthetic_offset.into_nanos(), 42);
469
470 let before_details = after_details;
471
472 clock.update(ClockUpdate::builder().error_bounds(100)).expect("failed to update clock");
474 let after_details = clock.get_details().expect("failed to get details");
475 assert!(before_details.generation_counter < after_details.generation_counter);
476 assert!(
477 after_details.last_error_bounds_update_ticks > before_details.last_value_update_ticks
478 );
479 assert!(
480 after_details.last_error_bounds_update_ticks
481 > after_details.last_rate_adjust_update_ticks
482 );
483 assert_eq!(
484 after_details.last_rate_adjust_update_ticks,
485 after_details.last_value_update_ticks
486 );
487 assert_eq!(after_details.error_bounds, 100);
488 assert_eq!(after_details.ticks_to_synthetic.synthetic_offset.into_nanos(), 42);
489 assert_eq!(after_details.reference_to_synthetic.synthetic_offset.into_nanos(), 42);
490 }
491
492 #[test]
493 fn clock_identity_transformation_roundtrip() {
494 let t_0 = MonotonicInstant::ZERO;
495 let xform = ClockTransformation {
497 reference_offset: MonotonicInstant::from_nanos(0),
498 synthetic_offset: SyntheticInstant::from_nanos(0),
499 rate: sys::zx_clock_rate_t { synthetic_ticks: 1, reference_ticks: 1 },
500 };
501
502 let transformed_time = xform.apply(t_0);
504 let original_time = xform.apply_inverse(transformed_time);
505 assert_eq!(t_0, original_time);
506 }
507
508 #[test]
509 fn clock_trivial_transformation() {
510 let t_0 = MonotonicInstant::ZERO;
511 let xform = ClockTransformation {
513 reference_offset: MonotonicInstant::from_nanos(3),
514 synthetic_offset: SyntheticInstant::from_nanos(2),
515 rate: sys::zx_clock_rate_t { synthetic_ticks: 6, reference_ticks: 2 },
516 };
517
518 let utc_time = xform.apply(t_0);
519 let monotonic_time = xform.apply_inverse(utc_time);
520 assert_eq!(3 * (t_0.into_nanos() - 3) + 2, utc_time.into_nanos());
522
523 assert_eq!(t_0, monotonic_time);
525 }
526
527 #[test]
528 fn clock_transformation_roundtrip() {
529 let t_0 = MonotonicInstant::ZERO;
530 let xform = ClockTransformation {
532 reference_offset: MonotonicInstant::from_nanos(196980085208),
533 synthetic_offset: SyntheticInstant::from_nanos(1616900096031887801),
534 rate: sys::zx_clock_rate_t { synthetic_ticks: 999980, reference_ticks: 1000000 },
535 };
536
537 let transformed_time = xform.apply(t_0);
539 let original_time = xform.apply_inverse(transformed_time);
540 let roundtrip_diff = t_0 - original_time;
541 assert!(roundtrip_diff.into_nanos().abs() <= 1);
542 }
543
544 #[test]
545 fn clock_trailing_transformation_roundtrip() {
546 let t_0 = MonotonicInstant::ZERO;
547 let xform = ClockTransformation {
550 reference_offset: MonotonicInstant::from_nanos(1616900096031887801),
551 synthetic_offset: SyntheticInstant::from_nanos(196980085208),
552 rate: sys::zx_clock_rate_t { synthetic_ticks: 1000000, reference_ticks: 999980 },
553 };
554
555 let transformed_time = xform.apply(t_0);
557 let original_time = xform.apply_inverse(transformed_time);
558 let roundtrip_diff = t_0 - original_time;
559 assert!(roundtrip_diff.into_nanos().abs() <= 1);
560 }
561
562 #[test]
563 fn clock_saturating_transformations() {
564 let t_0 = MonotonicInstant::from_nanos(i64::MAX);
565 let xform = ClockTransformation {
567 reference_offset: MonotonicInstant::from_nanos(0),
568 synthetic_offset: SyntheticInstant::from_nanos(1),
569 rate: sys::zx_clock_rate_t { synthetic_ticks: 1, reference_ticks: 1 },
570 };
571
572 let time = xform.apply(t_0).into_nanos();
574 assert_eq!(time, i64::MAX);
575
576 let t_0 = MonotonicInstant::from_nanos(i64::MIN);
577 let xform = ClockTransformation {
579 reference_offset: MonotonicInstant::from_nanos(1),
580 synthetic_offset: SyntheticInstant::from_nanos(0),
581 rate: sys::zx_clock_rate_t { synthetic_ticks: 1, reference_ticks: 1 },
582 };
583
584 let time = xform.apply(t_0).into_nanos();
586 assert_eq!(time, i64::MIN);
587 }
588}