1use crate::{
8 AsHandleRef, BootTimeline, ClockUpdate, HandleBased, HandleRef, Instant, MonotonicTimeline,
9 NullableHandle, ObjectQuery, 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
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(NullableHandle::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(NullableHandle::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: usize) -> Result<Instant<Output>, Status> {
110 let mut now = 0;
111 let status = unsafe {
112 sys::zx_clock_read_mapped(clock_addr as *const u8, &mut now)
114 };
115 ok(status)?;
116 Ok(Instant::<Output>::from_nanos(now))
117 }
118
119 pub fn get_details(&self) -> Result<ClockDetails<Reference, Output>, Status> {
124 let mut out_details = MaybeUninit::<sys::zx_clock_details_v1_t>::uninit();
125 let status = unsafe {
126 sys::zx_clock_get_details(
127 self.raw_handle(),
128 sys::ZX_CLOCK_ARGS_VERSION_1,
129 out_details.as_mut_ptr().cast::<u8>(),
130 )
131 };
132 ok(status)?;
133 let out_details = unsafe { out_details.assume_init() };
134 Ok(out_details.into())
135 }
136
137 pub unsafe fn get_details_mapped(
149 clock_addr: usize,
150 ) -> Result<ClockDetails<Reference, Output>, Status> {
151 let mut out_details = MaybeUninit::<sys::zx_clock_details_v1_t>::uninit();
152 let status = unsafe {
153 sys::zx_clock_get_details_mapped(
155 clock_addr as *const u8,
156 sys::ZX_CLOCK_ARGS_VERSION_1,
157 out_details.as_mut_ptr().cast::<u8>(),
158 )
159 };
160 ok(status)?;
161 let out_details = unsafe { out_details.assume_init() };
162 Ok(out_details.into())
163 }
164
165 pub fn get_mapped_size(clock: &Clock<Reference, Output>) -> Result<usize, Status> {
167 Ok(clock.0.get_info_single::<MappedSizeQuery>()?)
168 }
169
170 pub fn update(&self, update: impl Into<ClockUpdate<Reference, Output>>) -> Result<(), Status> {
175 let update = update.into();
176 let options = update.options();
177 let args = update.args();
178 let status = unsafe {
179 sys::zx_clock_update(self.raw_handle(), options, std::ptr::from_ref(&args).cast::<u8>())
180 };
181 ok(status)?;
182 Ok(())
183 }
184
185 pub fn downcast<NewReference: Timeline>(self) -> Clock<NewReference, SyntheticTimeline> {
188 Clock(self.0, std::marker::PhantomData)
189 }
190
191 delegated_concrete_handle_based_impls!(|h| Self(h, std::marker::PhantomData));
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
204impl<Reference: Timeline, Output: Timeline> AsHandleRef for Clock<Reference, Output> {
205 fn as_handle_ref(&self) -> HandleRef<'_> {
206 self.0.as_handle_ref()
207 }
208}
209
210impl<Reference: Timeline, Output: Timeline> From<NullableHandle> for Clock<Reference, Output> {
211 fn from(handle: NullableHandle) -> Self {
212 Clock(handle, std::marker::PhantomData)
213 }
214}
215
216impl<Reference: Timeline, Output: Timeline> From<Clock<Reference, Output>> for NullableHandle {
217 fn from(x: Clock<Reference, Output>) -> NullableHandle {
218 x.0
219 }
220}
221
222impl<Reference: Timeline, Output: Timeline> HandleBased for Clock<Reference, Output> {}
223
224struct MappedSizeQuery;
225unsafe impl ObjectQuery for MappedSizeQuery {
226 const TOPIC: Topic = Topic::CLOCK_MAPPED_SIZE;
227 type InfoTy = usize;
228}
229
230bitflags! {
231 #[repr(transparent)]
232 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
233 pub struct ClockOpts: u64 {
234 const MONOTONIC = sys::ZX_CLOCK_OPT_MONOTONIC;
237
238 const CONTINUOUS = sys::ZX_CLOCK_OPT_CONTINUOUS | Self::MONOTONIC.bits();
242
243 const AUTO_START = sys::ZX_CLOCK_OPT_AUTO_START;
247
248 const BOOT = sys::ZX_CLOCK_OPT_BOOT;
250
251 const MAPPABLE = sys::ZX_CLOCK_OPT_MAPPABLE;
254 }
255}
256
257#[derive(Debug, Clone, PartialEq, Eq)]
259pub struct ClockDetails<Reference = MonotonicTimeline, Output = SyntheticTimeline> {
260 pub backstop: Instant<Output>,
262
263 pub ticks_to_synthetic: ClockTransformation<Reference, Output>,
265
266 pub reference_to_synthetic: ClockTransformation<Reference, Output>,
268
269 pub error_bounds: u64,
271
272 pub query_ticks: Ticks<Reference>,
275
276 pub last_value_update_ticks: Ticks<Reference>,
278
279 pub last_rate_adjust_update_ticks: Ticks<Reference>,
281
282 pub last_error_bounds_update_ticks: Ticks<Reference>,
284
285 pub generation_counter: u32,
287}
288
289impl<Reference: Timeline, Output: Timeline> From<sys::zx_clock_details_v1_t>
290 for ClockDetails<Reference, Output>
291{
292 fn from(details: sys::zx_clock_details_v1_t) -> Self {
293 ClockDetails {
294 backstop: Instant::from_nanos(details.backstop_time),
295 ticks_to_synthetic: details.reference_ticks_to_synthetic.into(),
296 reference_to_synthetic: details.reference_to_synthetic.into(),
297 error_bounds: details.error_bound,
298 query_ticks: Ticks::from_raw(details.query_ticks),
299 last_value_update_ticks: Ticks::from_raw(details.last_value_update_ticks),
300 last_rate_adjust_update_ticks: Ticks::from_raw(details.last_rate_adjust_update_ticks),
301 last_error_bounds_update_ticks: Ticks::from_raw(details.last_error_bounds_update_ticks),
302 generation_counter: details.generation_counter,
303 }
304 }
305}
306
307#[derive(Debug, Clone, Eq, PartialEq)]
312pub struct ClockTransformation<Reference = MonotonicTimeline, Output = SyntheticTimeline> {
313 pub reference_offset: Instant<Reference>,
315 pub synthetic_offset: Instant<Output>,
318 pub rate: sys::zx_clock_rate_t,
320}
321
322impl<Reference: Timeline, Output: Timeline> From<sys::zx_clock_transformation_t>
323 for ClockTransformation<Reference, Output>
324{
325 fn from(ct: sys::zx_clock_transformation_t) -> Self {
326 ClockTransformation {
327 reference_offset: Instant::<Reference>::from_nanos(ct.reference_offset),
328 synthetic_offset: Instant::<Output>::from_nanos(ct.synthetic_offset),
329 rate: ct.rate,
330 }
331 }
332}
333
334fn transform_clock(r: i64, r_offset: i64, c_offset: i64, r_rate: u32, c_rate: u32) -> i64 {
344 assert!(r_rate != 0, "r_rate may not be zero");
345 let r = r as i128;
346 let r_offset = r_offset as i128;
347 let c_offset = c_offset as i128;
348 let r_rate = r_rate as i128;
349 let c_rate = c_rate as i128;
350 let c = (((r - r_offset) * c_rate) / r_rate) + c_offset;
351 c.try_into().unwrap_or_else(|_| if c.is_positive() { i64::MAX } else { i64::MIN })
352}
353
354impl<Reference: Timeline + Copy, Output: Timeline + Copy> ClockTransformation<Reference, Output> {
361 pub fn apply(&self, time: Instant<Reference>) -> Instant<Output> {
367 let c = transform_clock(
368 time.into_nanos(),
369 self.reference_offset.into_nanos(),
370 self.synthetic_offset.into_nanos(),
371 self.rate.reference_ticks,
372 self.rate.synthetic_ticks,
373 );
374
375 Instant::from_nanos(c)
376 }
377
378 pub fn apply_inverse(&self, time: Instant<Output>) -> Instant<Reference> {
384 let r = transform_clock(
385 time.into_nanos(),
386 self.synthetic_offset.into_nanos(),
387 self.reference_offset.into_nanos(),
388 self.rate.synthetic_ticks,
389 self.rate.reference_ticks,
390 );
391
392 Instant::from_nanos(r as i64)
393 }
394}
395
396#[cfg(test)]
397mod tests {
398 use super::*;
399 use crate::{MonotonicInstant, SyntheticInstant};
400 use assert_matches::assert_matches;
401
402 #[test]
403 fn create_clocks() {
404 assert_matches!(SyntheticClock::create(ClockOpts::empty(), None), Ok(_));
405 assert_matches!(SyntheticClock::create(ClockOpts::MONOTONIC, None), Ok(_));
406 assert_matches!(SyntheticClock::create(ClockOpts::CONTINUOUS, None), Ok(_));
407 assert_matches!(
408 SyntheticClock::create(ClockOpts::AUTO_START | ClockOpts::MONOTONIC, None),
409 Ok(_)
410 );
411 assert_matches!(
412 SyntheticClock::create(ClockOpts::AUTO_START | ClockOpts::CONTINUOUS, None),
413 Ok(_)
414 );
415
416 let backstop = Some(SyntheticInstant::from_nanos(5500));
418 assert_matches!(SyntheticClock::create(ClockOpts::MONOTONIC, backstop), Ok(_));
419 assert_matches!(SyntheticClock::create(ClockOpts::CONTINUOUS, backstop), Ok(_));
420 assert_matches!(
421 SyntheticClock::create(ClockOpts::AUTO_START | ClockOpts::MONOTONIC, backstop),
422 Ok(_)
423 );
424 assert_matches!(
425 SyntheticClock::create(ClockOpts::AUTO_START | ClockOpts::CONTINUOUS, backstop),
426 Ok(_)
427 );
428 }
429
430 #[test]
431 fn read_time() {
432 let clock =
433 SyntheticClock::create(ClockOpts::MONOTONIC, None).expect("failed to create clock");
434 assert_matches!(clock.read(), Ok(_));
435 }
436
437 #[test]
438 fn get_clock_details() {
439 let clock =
441 SyntheticClock::create(ClockOpts::MONOTONIC, None).expect("failed to create clock");
442 let details = clock.get_details().expect("failed to get details");
443 assert_eq!(details.backstop, SyntheticInstant::from_nanos(0));
444
445 let clock =
447 SyntheticClock::create(ClockOpts::MONOTONIC, Some(SyntheticInstant::from_nanos(5500)))
448 .expect("failed to create clock");
449 let details = clock.get_details().expect("failed to get details");
450 assert_eq!(details.backstop, SyntheticInstant::from_nanos(5500));
451 }
452
453 #[test]
454 fn update_clock() {
455 let clock =
456 SyntheticClock::create(ClockOpts::MONOTONIC, None).expect("failed to create clock");
457 let before_details = clock.get_details().expect("failed to get details");
458 assert_eq!(before_details.last_value_update_ticks, Ticks::from_raw(0));
459 assert_eq!(before_details.last_rate_adjust_update_ticks, Ticks::from_raw(0));
460 assert_eq!(before_details.last_error_bounds_update_ticks, Ticks::from_raw(0));
461
462 clock
464 .update(
465 ClockUpdate::builder()
466 .absolute_value(
467 MonotonicInstant::from_nanos(999),
468 SyntheticInstant::from_nanos(42),
469 )
470 .rate_adjust(52)
471 .error_bounds(52),
472 )
473 .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!(after_details.last_value_update_ticks > before_details.last_value_update_ticks);
477 assert_eq!(
478 after_details.last_value_update_ticks,
479 after_details.last_rate_adjust_update_ticks
480 );
481 assert_eq!(
482 after_details.last_value_update_ticks,
483 after_details.last_error_bounds_update_ticks
484 );
485 assert_eq!(after_details.error_bounds, 52);
486 assert_eq!(after_details.ticks_to_synthetic.synthetic_offset.into_nanos(), 42);
487 assert_eq!(after_details.reference_to_synthetic.reference_offset.into_nanos(), 999);
488 assert_eq!(after_details.reference_to_synthetic.synthetic_offset.into_nanos(), 42);
489
490 let before_details = after_details;
491
492 clock.update(ClockUpdate::builder().error_bounds(100)).expect("failed to update clock");
494 let after_details = clock.get_details().expect("failed to get details");
495 assert!(before_details.generation_counter < after_details.generation_counter);
496 assert!(
497 after_details.last_error_bounds_update_ticks > before_details.last_value_update_ticks
498 );
499 assert!(
500 after_details.last_error_bounds_update_ticks
501 > after_details.last_rate_adjust_update_ticks
502 );
503 assert_eq!(
504 after_details.last_rate_adjust_update_ticks,
505 after_details.last_value_update_ticks
506 );
507 assert_eq!(after_details.error_bounds, 100);
508 assert_eq!(after_details.ticks_to_synthetic.synthetic_offset.into_nanos(), 42);
509 assert_eq!(after_details.reference_to_synthetic.synthetic_offset.into_nanos(), 42);
510 }
511
512 #[test]
513 fn clock_identity_transformation_roundtrip() {
514 let t_0 = MonotonicInstant::ZERO;
515 let xform = ClockTransformation {
517 reference_offset: MonotonicInstant::from_nanos(0),
518 synthetic_offset: SyntheticInstant::from_nanos(0),
519 rate: sys::zx_clock_rate_t { synthetic_ticks: 1, reference_ticks: 1 },
520 };
521
522 let transformed_time = xform.apply(t_0);
524 let original_time = xform.apply_inverse(transformed_time);
525 assert_eq!(t_0, original_time);
526 }
527
528 #[test]
529 fn clock_trivial_transformation() {
530 let t_0 = MonotonicInstant::ZERO;
531 let xform = ClockTransformation {
533 reference_offset: MonotonicInstant::from_nanos(3),
534 synthetic_offset: SyntheticInstant::from_nanos(2),
535 rate: sys::zx_clock_rate_t { synthetic_ticks: 6, reference_ticks: 2 },
536 };
537
538 let utc_time = xform.apply(t_0);
539 let monotonic_time = xform.apply_inverse(utc_time);
540 assert_eq!(3 * (t_0.into_nanos() - 3) + 2, utc_time.into_nanos());
542
543 assert_eq!(t_0, monotonic_time);
545 }
546
547 #[test]
548 fn clock_transformation_roundtrip() {
549 let t_0 = MonotonicInstant::ZERO;
550 let xform = ClockTransformation {
552 reference_offset: MonotonicInstant::from_nanos(196980085208),
553 synthetic_offset: SyntheticInstant::from_nanos(1616900096031887801),
554 rate: sys::zx_clock_rate_t { synthetic_ticks: 999980, reference_ticks: 1000000 },
555 };
556
557 let transformed_time = xform.apply(t_0);
559 let original_time = xform.apply_inverse(transformed_time);
560 let roundtrip_diff = t_0 - original_time;
561 assert!(roundtrip_diff.into_nanos().abs() <= 1);
562 }
563
564 #[test]
565 fn clock_trailing_transformation_roundtrip() {
566 let t_0 = MonotonicInstant::ZERO;
567 let xform = ClockTransformation {
570 reference_offset: MonotonicInstant::from_nanos(1616900096031887801),
571 synthetic_offset: SyntheticInstant::from_nanos(196980085208),
572 rate: sys::zx_clock_rate_t { synthetic_ticks: 1000000, reference_ticks: 999980 },
573 };
574
575 let transformed_time = xform.apply(t_0);
577 let original_time = xform.apply_inverse(transformed_time);
578 let roundtrip_diff = t_0 - original_time;
579 assert!(roundtrip_diff.into_nanos().abs() <= 1);
580 }
581
582 #[test]
583 fn clock_saturating_transformations() {
584 let t_0 = MonotonicInstant::from_nanos(i64::MAX);
585 let xform = ClockTransformation {
587 reference_offset: MonotonicInstant::from_nanos(0),
588 synthetic_offset: SyntheticInstant::from_nanos(1),
589 rate: sys::zx_clock_rate_t { synthetic_ticks: 1, reference_ticks: 1 },
590 };
591
592 let time = xform.apply(t_0).into_nanos();
594 assert_eq!(time, i64::MAX);
595
596 let t_0 = MonotonicInstant::from_nanos(i64::MIN);
597 let xform = ClockTransformation {
599 reference_offset: MonotonicInstant::from_nanos(1),
600 synthetic_offset: SyntheticInstant::from_nanos(0),
601 rate: sys::zx_clock_rate_t { synthetic_ticks: 1, reference_ticks: 1 },
602 };
603
604 let time = xform.apply(t_0).into_nanos();
606 assert_eq!(time, i64::MIN);
607 }
608}