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