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