1use crate::mm::MemoryAccessorExt;
6use crate::security;
7use crate::signals::SignalEvent;
8use crate::task::{
9 CurrentTask, EventHandler, SignalHandler, SignalHandlerInner, Task, ThreadGroup, Waiter,
10};
11use crate::time::utc::utc_now;
12use crate::time::{ClockId, GenericDuration, Timeline, TimerId, TimerWakeup};
13use fuchsia_runtime::UtcInstant;
14use starnix_logging::{log_debug, log_error, log_trace, track_stub};
15use starnix_types::time::{
16 NANOS_PER_SECOND, duration_from_timespec, duration_to_scheduler_clock, time_from_timespec,
17 timespec_from_duration, timespec_is_zero, timeval_from_time,
18};
19use starnix_uapi::auth::CAP_WAKE_ALARM;
20use starnix_uapi::errors::{EINTR, Errno};
21use starnix_uapi::user_address::{MultiArchUserRef, UserRef};
22use starnix_uapi::{
23 CLOCK_BOOTTIME, CLOCK_BOOTTIME_ALARM, CLOCK_MONOTONIC, CLOCK_MONOTONIC_COARSE,
24 CLOCK_MONOTONIC_RAW, CLOCK_PROCESS_CPUTIME_ID, CLOCK_REALTIME, CLOCK_REALTIME_ALARM,
25 CLOCK_REALTIME_COARSE, CLOCK_TAI, CLOCK_THREAD_CPUTIME_ID, MAX_CLOCKS, TIMER_ABSTIME, errno,
26 error, from_status_like_fdio, pid_t, timespec, timezone, tms, uapi,
27};
28use zx::{
29 Task as _, {self as zx},
30};
31
32pub type TimeSpecPtr = MultiArchUserRef<uapi::timespec, uapi::arch32::timespec>;
33pub type ITimerSpecPtr = MultiArchUserRef<uapi::itimerspec, uapi::arch32::itimerspec>;
34pub type ITimerValPtr = MultiArchUserRef<uapi::itimerval, uapi::arch32::itimerval>;
35pub type TimeValPtr = MultiArchUserRef<uapi::timeval, uapi::arch32::timeval>;
36type TimeZonePtr = MultiArchUserRef<uapi::timezone, uapi::arch32::timezone>;
37
38fn get_clock_res(current_task: &CurrentTask, which_clock: i32) -> Result<timespec, Errno> {
39 match which_clock as u32 {
40 CLOCK_REALTIME
41 | CLOCK_REALTIME_ALARM
42 | CLOCK_REALTIME_COARSE
43 | CLOCK_MONOTONIC
44 | CLOCK_MONOTONIC_COARSE
45 | CLOCK_MONOTONIC_RAW
46 | CLOCK_BOOTTIME
47 | CLOCK_BOOTTIME_ALARM
48 | CLOCK_THREAD_CPUTIME_ID
49 | CLOCK_PROCESS_CPUTIME_ID => Ok(timespec { tv_sec: 0, tv_nsec: 1 }),
50 _ => {
51 let _ = get_dynamic_clock(current_task, which_clock)?;
53 Ok(timespec { tv_sec: 0, tv_nsec: 1 })
54 }
55 }
56}
57
58pub fn sys_clock_getres(
59 current_task: &CurrentTask,
60 which_clock: i32,
61 tp_addr: TimeSpecPtr,
62) -> Result<(), Errno> {
63 if which_clock < 0 && !is_valid_cpu_clock(which_clock) {
64 return error!(EINVAL);
65 }
66 if tp_addr.is_null() {
67 return Ok(());
68 }
69 let tv = get_clock_res(current_task, which_clock)?;
70 current_task.write_multi_arch_object(tp_addr, tv)?;
71 Ok(())
72}
73
74fn get_clock_gettime(current_task: &CurrentTask, which_clock: i32) -> Result<timespec, Errno> {
75 let nanos = if which_clock < 0 {
76 get_dynamic_clock(current_task, which_clock)?
77 } else {
78 match which_clock as u32 {
79 CLOCK_REALTIME | CLOCK_REALTIME_COARSE => utc_now().into_nanos(),
80 CLOCK_MONOTONIC | CLOCK_MONOTONIC_COARSE | CLOCK_MONOTONIC_RAW => {
81 zx::MonotonicInstant::get().into_nanos()
82 }
83 CLOCK_BOOTTIME => zx::BootInstant::get().into_nanos(),
84 CLOCK_THREAD_CPUTIME_ID => get_thread_cpu_time(current_task)?,
85 CLOCK_PROCESS_CPUTIME_ID => get_process_cpu_time(current_task.thread_group())?,
86 _ => return error!(EINVAL),
87 }
88 };
89 Ok(timespec { tv_sec: nanos / NANOS_PER_SECOND, tv_nsec: nanos % NANOS_PER_SECOND })
90}
91
92pub fn sys_clock_gettime(
93 current_task: &CurrentTask,
94 which_clock: i32,
95 tp_addr: TimeSpecPtr,
96) -> Result<(), Errno> {
97 let tv = get_clock_gettime(current_task, which_clock)?;
98 current_task.write_multi_arch_object(tp_addr, tv)?;
99 Ok(())
100}
101
102pub fn sys_gettimeofday(
103 current_task: &CurrentTask,
104 user_tv: TimeValPtr,
105 user_tz: TimeZonePtr,
106) -> Result<(), Errno> {
107 if !user_tv.is_null() {
108 let tv = timeval_from_time(utc_now());
109 current_task.write_multi_arch_object(user_tv, tv)?;
110 }
111 if !user_tz.is_null() {
112 current_task.mm()?.check_plausible(user_tz.addr(), std::mem::size_of::<timezone>())?;
114 track_stub!(TODO("https://fxbug.dev/322874502"), "gettimeofday tz argument");
115 }
116 Ok(())
117}
118
119pub fn sys_settimeofday(
120 current_task: &CurrentTask,
121 tv: TimeValPtr,
122 _tz: TimeZonePtr,
123) -> Result<(), Errno> {
124 const SEC_IN_NANOS: i64 = 1_000_000_000;
125 const USEC_IN_NANOS: i64 = 1000;
126 let kernel = current_task.kernel();
127 if let Some(ref proxy) = kernel.time_adjustment_proxy {
128 let boot_now = zx::BootInstant::get();
130 let tv = current_task.read_multi_arch_object(tv)?;
131
132 let utc_now_sec_as_nanos =
134 tv.tv_sec.checked_mul(SEC_IN_NANOS).ok_or_else(|| errno!(EINVAL))?;
135 let utc_now_usec_as_nanos =
136 tv.tv_usec.checked_mul(USEC_IN_NANOS).ok_or_else(|| errno!(EINVAL))?;
137 let utc_now_nanos = utc_now_sec_as_nanos
138 .checked_add(utc_now_usec_as_nanos)
139 .ok_or_else(|| errno!(EINVAL))?;
140 log_debug!(
141 "settimeofday: reporting reference: boot_now={:?}, utc_now_nanos={:?}",
142 boot_now,
143 utc_now_nanos
144 );
145 proxy
146 .report_boot_to_utc_mapping(
147 boot_now.into(),
148 utc_now_nanos,
149 zx::MonotonicInstant::INFINITE,
150 )
151 .map_err(|e| {
152 log_error!("FIDL error: {:?}", e);
153 errno!(ENOSYS)
157 })?
158 .map_err(|e| {
159 log_error!("remote error: {:?}", e);
160 errno!(EINVAL)
163 })
164 } else {
165 log_debug!("settimeofday: No functionality");
167 error!(ENOSYS)
168 }
169}
170
171pub fn sys_clock_nanosleep(
172 current_task: &mut CurrentTask,
173 which_clock: ClockId,
174 flags: u32,
175 user_request: TimeSpecPtr,
176 user_remaining: TimeSpecPtr,
177) -> Result<(), Errno> {
178 if which_clock < 0 {
179 return error!(EINVAL);
180 }
181 let which_clock = which_clock as u32;
182 let is_absolute = flags == TIMER_ABSTIME;
183 match which_clock {
190 CLOCK_REALTIME | CLOCK_MONOTONIC | CLOCK_BOOTTIME => {}
191 CLOCK_TAI => {
192 track_stub!(TODO("https://fxbug.dev/322875165"), "clock_nanosleep, CLOCK_TAI", flags);
193 return error!(EINVAL);
194 }
195 CLOCK_PROCESS_CPUTIME_ID => {
196 track_stub!(
197 TODO("https://fxbug.dev/322874886"),
198 "clock_nanosleep, CLOCK_PROCESS_CPUTIME_ID",
199 flags
200 );
201 return error!(EINVAL);
202 }
203 _ => return error!(ENOTSUP),
204 }
205
206 let request = current_task.read_multi_arch_object(user_request)?;
207 log_trace!("clock_nanosleep({}, {}, {:?})", which_clock, flags, request);
208
209 if timespec_is_zero(request) {
210 return Ok(());
211 }
212
213 if which_clock == CLOCK_REALTIME {
214 return clock_nanosleep_relative_to_utc(current_task, request, is_absolute, user_remaining);
215 }
216
217 let boot_deadline = if is_absolute {
219 time_from_timespec(request)?
220 } else {
221 zx::BootInstant::after(duration_from_timespec(request)?)
222 };
223
224 clock_nanosleep_boot_with_deadline(
225 current_task,
226 is_absolute,
227 boot_deadline,
228 None,
229 user_remaining,
230 )
231}
232
233fn clock_nanosleep_relative_to_utc(
236 current_task: &mut CurrentTask,
237 request: timespec,
238 is_absolute: bool,
239 user_remaining: TimeSpecPtr,
240) -> Result<(), Errno> {
241 let clock_deadline_absolute = if is_absolute {
242 time_from_timespec(request)?
243 } else {
244 utc_now() + duration_from_timespec(request)?
245 };
246 loop {
247 let (boot_deadline, _) =
251 crate::time::utc::estimate_boot_deadline_from_utc(clock_deadline_absolute);
252 clock_nanosleep_boot_with_deadline(
253 current_task,
254 is_absolute,
255 boot_deadline,
256 Some(clock_deadline_absolute),
257 user_remaining,
258 )?;
259 let clock_now = utc_now();
261 if clock_now >= clock_deadline_absolute {
262 return Ok(());
263 }
264 log_trace!(
265 "clock_nanosleep_relative_to_clock short by {:?}, sleeping again",
266 clock_deadline_absolute - clock_now
267 );
268 }
269}
270
271fn clock_nanosleep_boot_with_deadline(
272 current_task: &mut CurrentTask,
273 is_absolute: bool,
274 deadline: zx::BootInstant,
275 original_utc_deadline: Option<UtcInstant>,
276 user_remaining: TimeSpecPtr,
277) -> Result<(), Errno> {
278 let waiter = Waiter::new();
279 let timer = zx::BootTimer::create();
280 let signal_handler = SignalHandler {
281 inner: SignalHandlerInner::None,
282 event_handler: EventHandler::None,
283 err_code: None,
284 };
285 waiter
286 .wake_on_zircon_signals(&timer, zx::Signals::TIMER_SIGNALED, signal_handler)
287 .expect("wait can only fail in OOM conditions");
288 let timer_slack = current_task.read().get_timerslack();
289 timer.set(deadline, timer_slack).expect("timer set cannot fail with valid handles and slack");
290 match waiter.wait(current_task) {
291 Err(err) if err == EINTR && is_absolute => error!(ERESTARTNOHAND),
292 Err(err) if err == EINTR => {
293 if !user_remaining.is_null() {
294 let remaining = match original_utc_deadline {
295 Some(original_utc_deadline) => {
296 GenericDuration::from(original_utc_deadline - utc_now())
297 }
298 None => GenericDuration::from(deadline - zx::BootInstant::get()),
299 };
300 let remaining = timespec_from_duration(*std::cmp::max(
301 GenericDuration::from_nanos(0),
302 remaining,
303 ));
304 current_task.write_multi_arch_object(user_remaining, remaining)?;
305 }
306 current_task.set_syscall_restart_func(move |current_task| {
307 clock_nanosleep_boot_with_deadline(
308 current_task,
309 is_absolute,
310 deadline,
311 original_utc_deadline,
312 user_remaining,
313 )
314 });
315 error!(ERESTART_RESTARTBLOCK)
316 }
317 non_eintr => non_eintr,
318 }
319}
320
321pub fn sys_nanosleep(
322 current_task: &mut CurrentTask,
323 user_request: TimeSpecPtr,
324 user_remaining: TimeSpecPtr,
325) -> Result<(), Errno> {
326 sys_clock_nanosleep(current_task, CLOCK_REALTIME as ClockId, 0, user_request, user_remaining)
327}
328
329fn get_thread_cpu_time(task: &Task) -> Result<i64, Errno> {
331 Ok(task.thread_runtime_info()?.cpu_time)
332}
333
334fn get_process_cpu_time(tg: &ThreadGroup) -> Result<i64, Errno> {
336 Ok(tg.process.get_runtime_info().map_err(|status| from_status_like_fdio!(status))?.cpu_time)
337}
338
339fn which_cpu_clock(clock: i32) -> i32 {
341 const CPU_CLOCK_MASK: i32 = 3;
342 clock & CPU_CLOCK_MASK
343}
344
345fn is_valid_cpu_clock(clock: i32) -> bool {
347 const MAX_CPU_CLOCK: i32 = 3;
348 if clock & 7 == 7 {
349 return false;
350 }
351 if which_cpu_clock(clock) >= MAX_CPU_CLOCK {
352 return false;
353 }
354
355 true
356}
357
358fn pid_of_clock_id(clock: i32) -> pid_t {
360 !(clock >> 3) as pid_t
362}
363
364fn is_thread_clock(clock: i32) -> bool {
366 const PER_THREAD_MASK: i32 = 4;
367 clock & PER_THREAD_MASK != 0
368}
369
370fn get_dynamic_clock(current_task: &CurrentTask, which_clock: i32) -> Result<i64, Errno> {
380 if !is_valid_cpu_clock(which_clock) {
381 return error!(EINVAL);
382 }
383
384 let pid = pid_of_clock_id(which_clock);
385 let target_pid = current_task.kernel().pids.get(pid).map_err(|_| errno!(EINVAL))?;
386
387 if is_thread_clock(which_clock) {
388 let task = target_pid.get_task().map_err(|_| errno!(EINVAL))?;
389 get_thread_cpu_time(&task)
390 } else {
391 let tg = target_pid.get_thread_group().map_err(|_| errno!(EINVAL))?;
392 get_process_cpu_time(&tg)
393 }
394}
395
396pub fn sys_timer_create(
397 current_task: &CurrentTask,
398 clock_id: ClockId,
399 event: MultiArchUserRef<uapi::sigevent, uapi::arch32::sigevent>,
400 timerid: UserRef<TimerId>,
401) -> Result<(), Errno> {
402 if clock_id >= MAX_CLOCKS as TimerId {
403 return error!(EINVAL);
404 }
405 let user_event = if event.addr().is_null() {
406 None
407 } else {
408 Some(current_task.read_multi_arch_object(event)?)
409 };
410
411 let mut checked_signal_event: Option<SignalEvent> = None;
412 let thread_group = current_task.thread_group();
413 if let Some(user_event) = user_event {
414 let signal_event: SignalEvent = user_event.try_into()?;
415 if !signal_event.is_valid(&thread_group.read()) {
416 return error!(EINVAL);
417 }
418 checked_signal_event = Some(signal_event);
419 }
420 let timeline = match clock_id as u32 {
421 CLOCK_REALTIME => Timeline::RealTime,
422 CLOCK_MONOTONIC => Timeline::Monotonic,
423 CLOCK_BOOTTIME => Timeline::BootInstant,
424 CLOCK_REALTIME_ALARM => Timeline::RealTime,
425 CLOCK_BOOTTIME_ALARM => Timeline::BootInstant,
426 CLOCK_TAI => {
427 track_stub!(TODO("https://fxbug.dev/349191834"), "timers w/ TAI");
428 return error!(ENOTSUP);
429 }
430 CLOCK_PROCESS_CPUTIME_ID => {
431 track_stub!(TODO("https://fxbug.dev/349188105"), "timers w/ calling process cpu time");
432 return error!(ENOTSUP);
433 }
434 CLOCK_THREAD_CPUTIME_ID => {
435 track_stub!(TODO("https://fxbug.dev/349188105"), "timers w/ calling thread cpu time");
436 return error!(ENOTSUP);
437 }
438 _ => {
439 track_stub!(TODO("https://fxbug.dev/349188105"), "timers w/ dynamic process clocks");
440 return error!(ENOTSUP);
441 }
442 };
443 let timer_wakeup = match clock_id as u32 {
444 CLOCK_BOOTTIME_ALARM | CLOCK_REALTIME_ALARM => {
445 security::check_task_capable(current_task, CAP_WAKE_ALARM)?;
446 TimerWakeup::Alarm
447 }
448 _ => TimerWakeup::Regular,
449 };
450
451 let id = &thread_group.timers.create(timeline, timer_wakeup, checked_signal_event)?;
452 current_task.write_object(timerid, &id)?;
453 Ok(())
454}
455
456pub fn sys_timer_delete(current_task: &CurrentTask, id: TimerId) -> Result<(), Errno> {
457 current_task.thread_group().timers.delete(current_task, id)
458}
459
460pub fn sys_timer_gettime(
461 current_task: &CurrentTask,
462 id: TimerId,
463 curr_value: ITimerSpecPtr,
464) -> Result<(), Errno> {
465 let timers = ¤t_task.thread_group().timers;
466 current_task.write_multi_arch_object(curr_value, timers.get_time(id)?)?;
467 Ok(())
468}
469
470pub fn sys_timer_getoverrun(current_task: &CurrentTask, id: TimerId) -> Result<i32, Errno> {
471 current_task.thread_group().timers.get_overrun(id)
472}
473
474pub fn sys_timer_settime(
475 current_task: &CurrentTask,
476 id: TimerId,
477 flags: i32,
478 user_new_value: ITimerSpecPtr,
479 user_old_value: ITimerSpecPtr,
480) -> Result<(), Errno> {
481 if user_new_value.is_null() {
482 return error!(EINVAL);
483 }
484 let new_value = current_task.read_multi_arch_object(user_new_value)?;
485
486 if !user_old_value.is_null() {
489 current_task.write_multi_arch_object(user_old_value, Default::default())?;
490 }
491
492 let old_value =
493 current_task.thread_group().timers.set_time(current_task, id, flags, new_value)?;
494
495 if !user_old_value.is_null() {
496 current_task.write_multi_arch_object(user_old_value, old_value)?;
497 }
498 Ok(())
499}
500
501pub fn sys_getitimer(
502 current_task: &CurrentTask,
503 which: u32,
504 user_curr_value: ITimerValPtr,
505) -> Result<(), Errno> {
506 let remaining = current_task.thread_group().get_itimer(which)?;
507 current_task.write_multi_arch_object(user_curr_value, remaining)?;
508 Ok(())
509}
510
511pub fn sys_setitimer(
512 current_task: &CurrentTask,
513 which: u32,
514 user_new_value: ITimerValPtr,
515 user_old_value: ITimerValPtr,
516) -> Result<(), Errno> {
517 let new_value = current_task.read_multi_arch_object(user_new_value)?;
518
519 let old_value = current_task.thread_group().set_itimer(current_task, which, new_value)?;
520
521 if !user_old_value.is_null() {
522 current_task.write_multi_arch_object(user_old_value, old_value)?;
523 }
524
525 Ok(())
526}
527
528pub fn sys_times(current_task: &CurrentTask, buf: UserRef<tms>) -> Result<i64, Errno> {
529 if !buf.is_null() {
530 let thread_group = current_task.thread_group();
531 let process_time_stats = thread_group.time_stats();
532 let children_time_stats = thread_group.read().children_time_stats;
533 let tms_result = tms {
534 tms_utime: duration_to_scheduler_clock(process_time_stats.user_time),
535 tms_stime: duration_to_scheduler_clock(process_time_stats.system_time),
536 tms_cutime: duration_to_scheduler_clock(children_time_stats.user_time),
537 tms_cstime: duration_to_scheduler_clock(children_time_stats.system_time),
538 };
539 current_task.write_object(buf, &tms_result)?;
540 }
541
542 Ok(duration_to_scheduler_clock(zx::MonotonicInstant::get() - zx::MonotonicInstant::ZERO))
543}
544
545#[cfg(target_arch = "aarch64")]
547mod arch32 {
548 use crate::task::CurrentTask;
549 use crate::time::TimerId;
550 use starnix_uapi::errors::Errno;
551 use starnix_uapi::uapi;
552 use starnix_uapi::user_address::UserRef;
553 use static_assertions::const_assert;
554
555 pub fn sys_arch32_clock_gettime64(
556 current_task: &CurrentTask,
557 which_clock: i32,
558 tp_addr: UserRef<uapi::timespec>,
559 ) -> Result<(), Errno> {
560 const_assert!(
561 std::mem::size_of::<uapi::timespec>()
562 == std::mem::size_of::<uapi::arch32::__kernel_timespec>()
563 );
564 super::sys_clock_gettime(current_task, which_clock, tp_addr.into())
565 }
566
567 pub fn sys_arch32_timer_gettime64(
568 current_task: &CurrentTask,
569 id: TimerId,
570 curr_value: UserRef<uapi::itimerspec>,
571 ) -> Result<(), Errno> {
572 const_assert!(
573 std::mem::size_of::<uapi::itimerspec>()
574 == std::mem::size_of::<uapi::arch32::__kernel_itimerspec>()
575 );
576 super::sys_timer_gettime(current_task, id, curr_value.into())
577 }
578
579 pub use super::{
580 sys_clock_getres as sys_arch32_clock_getres, sys_clock_gettime as sys_arch32_clock_gettime,
581 sys_getitimer as sys_arch32_getitimer, sys_gettimeofday as sys_arch32_gettimeofday,
582 sys_nanosleep as sys_arch32_nanosleep, sys_setitimer as sys_arch32_setitimer,
583 sys_settimeofday as sys_arch32_settimeofday, sys_timer_create as sys_arch32_timer_create,
584 sys_timer_delete as sys_arch32_timer_delete,
585 sys_timer_getoverrun as sys_arch32_timer_getoverrun,
586 sys_timer_gettime as sys_arch32_timer_gettime,
587 sys_timer_settime as sys_arch32_timer_settime,
588 };
589}
590
591#[cfg(target_arch = "aarch64")]
592pub use arch32::*;
593
594#[cfg(test)]
595mod test {
596 use super::*;
597 use crate::mm::PAGE_SIZE;
598 use crate::testing::{map_memory, spawn_kernel_and_run};
599 use crate::time::utc::UtcClockOverrideGuard;
600 use fuchsia_runtime::{UtcDuration, UtcTimeline};
601 use starnix_uapi::signals;
602 use starnix_uapi::user_address::UserAddress;
603 use std::sync::Arc;
604 use test_util::{assert_geq, assert_leq};
605 use zx::{BootTimeline, Clock, ClockUpdate};
606
607 type UtcClock = Clock<BootTimeline, UtcTimeline>;
609 type UtcClockUpdate = ClockUpdate<BootTimeline, UtcTimeline>;
610
611 #[::fuchsia::test]
612 async fn test_nanosleep_without_remainder() {
613 spawn_kernel_and_run(async |current_task| {
614 let thread = std::thread::spawn({
615 let task = current_task.weak_task();
616 move || {
617 let task = task.upgrade().expect("task must be alive");
618 while !task.read().is_blocked() {
620 std::thread::sleep(std::time::Duration::from_millis(10));
621 }
622 task.interrupt();
623 }
624 });
625
626 let duration = timespec_from_duration(zx::MonotonicDuration::from_seconds(60));
627 let address = map_memory(
628 ¤t_task,
629 UserAddress::default(),
630 std::mem::size_of::<timespec>() as u64,
631 );
632 let address_ptr = UserRef::<timespec>::from(address);
633 current_task.write_object(address_ptr, &duration).expect("write_object");
634
635 assert_eq!(
638 sys_nanosleep(current_task, address_ptr.into(), UserRef::default().into()),
639 error!(ERESTART_RESTARTBLOCK)
640 );
641
642 thread.join().expect("join");
643 })
644 .await;
645 }
646
647 #[::fuchsia::test]
648 async fn test_clock_nanosleep_relative_to_slow_clock() {
649 spawn_kernel_and_run(async |current_task| {
650 let test_clock = UtcClock::create(zx::ClockOpts::AUTO_START, None).unwrap();
651 let _test_clock_guard = UtcClockOverrideGuard::new(
652 test_clock.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
653 );
654
655 let slow_clock_update = UtcClockUpdate::builder().rate_adjust(-1000).build();
657 test_clock.update(slow_clock_update).unwrap();
658
659 let before = test_clock.read().unwrap();
660
661 let tv = timespec { tv_sec: 1, tv_nsec: 0 };
662
663 let remaining = UserRef::new(UserAddress::default());
664
665 super::clock_nanosleep_relative_to_utc(current_task, tv, false, remaining.into())
666 .unwrap();
667 let elapsed = test_clock.read().unwrap() - before;
668 assert!(elapsed >= UtcDuration::from_seconds(1));
669 })
670 .await;
671 }
672
673 #[::fuchsia::test]
674 async fn test_clock_nanosleep_interrupted_relative_to_fast_utc_clock() {
675 spawn_kernel_and_run(async |current_task| {
676 let test_clock = UtcClock::create(zx::ClockOpts::AUTO_START, None).unwrap();
677 let _test_clock_guard = UtcClockOverrideGuard::new(
678 test_clock.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
679 );
680
681 let slow_clock_update = UtcClockUpdate::builder().rate_adjust(1000).build();
683 test_clock.update(slow_clock_update).unwrap();
684
685 let before = test_clock.read().unwrap();
686
687 let tv = timespec { tv_sec: 2, tv_nsec: 0 };
688
689 let remaining = {
690 let addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
691 UserRef::new(addr)
692 };
693
694 let interruption_target =
697 zx::MonotonicInstant::get() + zx::MonotonicDuration::from_seconds(1);
698
699 let thread_group = Arc::downgrade(current_task.thread_group());
700 let thread_join_handle = std::thread::Builder::new()
701 .name("clock_nanosleep_interruptor".to_string())
702 .spawn(move || {
703 std::thread::sleep(std::time::Duration::from_nanos(
704 (interruption_target - zx::MonotonicInstant::get()).into_nanos() as u64,
705 ));
706 if let Some(thread_group) = thread_group.upgrade() {
707 let signal = signals::SIGALRM;
708 thread_group
709 .write()
710 .send_signal(crate::signals::SignalInfo::kernel(signal));
711 }
712 })
713 .unwrap();
714
715 let result =
716 super::clock_nanosleep_relative_to_utc(current_task, tv, false, remaining.into());
717
718 let mut remaining_written = Default::default();
722 if result.is_err() {
723 assert_eq!(result, error!(ERESTART_RESTARTBLOCK));
724 remaining_written = current_task.read_object(remaining).unwrap();
725 }
726 assert_leq!(
727 duration_from_timespec::<zx::MonotonicTimeline>(remaining_written).unwrap(),
728 zx::MonotonicDuration::from_seconds(2)
729 );
730 let elapsed = test_clock.read().unwrap() - before;
731 thread_join_handle.join().unwrap();
732
733 assert_geq!(
734 elapsed + duration_from_timespec(remaining_written).unwrap(),
735 UtcDuration::from_seconds(2)
736 );
737 })
738 .await;
739 }
740}