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 weak_task = current_task.get_task(tid);
357 let task = weak_task.upgrade().ok_or_else(|| errno!(EINVAL))?;
358 Ok(task.thread_runtime_info()?.cpu_time)
359}
360
361fn get_process_cpu_time(current_task: &CurrentTask, pid: pid_t) -> Result<i64, Errno> {
367 let pids = current_task.kernel().pids.read();
368 let tg = pids.get_thread_group(pid).ok_or_else(|| errno!(EINVAL))?;
369 Ok(tg.process.get_runtime_info().map_err(|status| from_status_like_fdio!(status))?.cpu_time)
370}
371
372fn which_cpu_clock(clock: i32) -> i32 {
374 const CPU_CLOCK_MASK: i32 = 3;
375 clock & CPU_CLOCK_MASK
376}
377
378fn is_valid_cpu_clock(clock: i32) -> bool {
380 const MAX_CPU_CLOCK: i32 = 3;
381 if clock & 7 == 7 {
382 return false;
383 }
384 if which_cpu_clock(clock) >= MAX_CPU_CLOCK {
385 return false;
386 }
387
388 true
389}
390
391fn pid_of_clock_id(clock: i32) -> pid_t {
393 !(clock >> 3) as pid_t
395}
396
397fn is_thread_clock(clock: i32) -> bool {
399 const PER_THREAD_MASK: i32 = 4;
400 clock & PER_THREAD_MASK != 0
401}
402
403fn get_dynamic_clock(current_task: &CurrentTask, which_clock: i32) -> Result<i64, Errno> {
413 if !is_valid_cpu_clock(which_clock) {
414 return error!(EINVAL);
415 }
416
417 let pid = pid_of_clock_id(which_clock);
418
419 if is_thread_clock(which_clock) {
420 get_thread_cpu_time(current_task, pid)
421 } else {
422 get_process_cpu_time(current_task, pid)
423 }
424}
425
426pub fn sys_timer_create(
427 _locked: &mut Locked<Unlocked>,
428 current_task: &CurrentTask,
429 clock_id: ClockId,
430 event: MultiArchUserRef<uapi::sigevent, uapi::arch32::sigevent>,
431 timerid: UserRef<TimerId>,
432) -> Result<(), Errno> {
433 if clock_id >= MAX_CLOCKS as TimerId {
434 return error!(EINVAL);
435 }
436 let user_event = if event.addr().is_null() {
437 None
438 } else {
439 Some(current_task.read_multi_arch_object(event)?)
440 };
441
442 let mut checked_signal_event: Option<SignalEvent> = None;
443 let thread_group = current_task.thread_group();
444 if let Some(user_event) = user_event {
445 let signal_event: SignalEvent = user_event.try_into()?;
446 if !signal_event.is_valid(&thread_group.read()) {
447 return error!(EINVAL);
448 }
449 checked_signal_event = Some(signal_event);
450 }
451 let timeline = match clock_id as u32 {
452 CLOCK_REALTIME => Timeline::RealTime,
453 CLOCK_MONOTONIC => Timeline::Monotonic,
454 CLOCK_BOOTTIME => Timeline::BootInstant,
455 CLOCK_REALTIME_ALARM => Timeline::RealTime,
456 CLOCK_BOOTTIME_ALARM => Timeline::BootInstant,
457 CLOCK_TAI => {
458 track_stub!(TODO("https://fxbug.dev/349191834"), "timers w/ TAI");
459 return error!(ENOTSUP);
460 }
461 CLOCK_PROCESS_CPUTIME_ID => {
462 track_stub!(TODO("https://fxbug.dev/349188105"), "timers w/ calling process cpu time");
463 return error!(ENOTSUP);
464 }
465 CLOCK_THREAD_CPUTIME_ID => {
466 track_stub!(TODO("https://fxbug.dev/349188105"), "timers w/ calling thread cpu time");
467 return error!(ENOTSUP);
468 }
469 _ => {
470 track_stub!(TODO("https://fxbug.dev/349188105"), "timers w/ dynamic process clocks");
471 return error!(ENOTSUP);
472 }
473 };
474 let timer_wakeup = match clock_id as u32 {
475 CLOCK_BOOTTIME_ALARM | CLOCK_REALTIME_ALARM => {
476 security::check_task_capable(current_task, CAP_WAKE_ALARM)?;
477 TimerWakeup::Alarm
478 }
479 _ => TimerWakeup::Regular,
480 };
481
482 let id = &thread_group.timers.create(timeline, timer_wakeup, checked_signal_event)?;
483 current_task.write_object(timerid, &id)?;
484 Ok(())
485}
486
487pub fn sys_timer_delete(
488 _locked: &mut Locked<Unlocked>,
489 current_task: &CurrentTask,
490 id: TimerId,
491) -> Result<(), Errno> {
492 current_task.thread_group().timers.delete(current_task, id)
493}
494
495pub fn sys_timer_gettime(
496 _locked: &mut Locked<Unlocked>,
497 current_task: &CurrentTask,
498 id: TimerId,
499 curr_value: ITimerSpecPtr,
500) -> Result<(), Errno> {
501 let timers = ¤t_task.thread_group().timers;
502 current_task.write_multi_arch_object(curr_value, timers.get_time(id)?)?;
503 Ok(())
504}
505
506pub fn sys_timer_getoverrun(
507 _locked: &mut Locked<Unlocked>,
508 current_task: &CurrentTask,
509 id: TimerId,
510) -> Result<i32, Errno> {
511 current_task.thread_group().timers.get_overrun(id)
512}
513
514pub fn sys_timer_settime(
515 _locked: &mut Locked<Unlocked>,
516 current_task: &CurrentTask,
517 id: TimerId,
518 flags: i32,
519 user_new_value: ITimerSpecPtr,
520 user_old_value: ITimerSpecPtr,
521) -> Result<(), Errno> {
522 if user_new_value.is_null() {
523 return error!(EINVAL);
524 }
525 let new_value = current_task.read_multi_arch_object(user_new_value)?;
526
527 if !user_old_value.is_null() {
530 current_task.write_multi_arch_object(user_old_value, Default::default())?;
531 }
532
533 let old_value =
534 current_task.thread_group().timers.set_time(current_task, id, flags, new_value)?;
535
536 if !user_old_value.is_null() {
537 current_task.write_multi_arch_object(user_old_value, old_value)?;
538 }
539 Ok(())
540}
541
542pub fn sys_getitimer(
543 _locked: &mut Locked<Unlocked>,
544 current_task: &CurrentTask,
545 which: u32,
546 user_curr_value: ITimerValPtr,
547) -> Result<(), Errno> {
548 let remaining = current_task.thread_group().get_itimer(which)?;
549 current_task.write_multi_arch_object(user_curr_value, remaining)?;
550 Ok(())
551}
552
553pub fn sys_setitimer(
554 _locked: &mut Locked<Unlocked>,
555 current_task: &CurrentTask,
556 which: u32,
557 user_new_value: ITimerValPtr,
558 user_old_value: ITimerValPtr,
559) -> Result<(), Errno> {
560 let new_value = current_task.read_multi_arch_object(user_new_value)?;
561
562 let old_value = current_task.thread_group().set_itimer(current_task, which, new_value)?;
563
564 if !user_old_value.is_null() {
565 current_task.write_multi_arch_object(user_old_value, old_value)?;
566 }
567
568 Ok(())
569}
570
571pub fn sys_times(
572 _locked: &mut Locked<Unlocked>,
573 current_task: &CurrentTask,
574 buf: UserRef<tms>,
575) -> Result<i64, Errno> {
576 if !buf.is_null() {
577 let thread_group = current_task.thread_group();
578 let process_time_stats = thread_group.time_stats();
579 let children_time_stats = thread_group.read().children_time_stats;
580 let tms_result = tms {
581 tms_utime: duration_to_scheduler_clock(process_time_stats.user_time),
582 tms_stime: duration_to_scheduler_clock(process_time_stats.system_time),
583 tms_cutime: duration_to_scheduler_clock(children_time_stats.user_time),
584 tms_cstime: duration_to_scheduler_clock(children_time_stats.system_time),
585 };
586 current_task.write_object(buf, &tms_result)?;
587 }
588
589 Ok(duration_to_scheduler_clock(zx::MonotonicInstant::get() - zx::MonotonicInstant::ZERO))
590}
591
592#[cfg(target_arch = "aarch64")]
594mod arch32 {
595 use crate::task::CurrentTask;
596 use crate::time::TimerId;
597 use starnix_sync::{Locked, Unlocked};
598 use starnix_uapi::errors::Errno;
599 use starnix_uapi::uapi;
600 use starnix_uapi::user_address::UserRef;
601 use static_assertions::const_assert;
602
603 pub fn sys_arch32_clock_gettime64(
604 locked: &mut Locked<Unlocked>,
605 current_task: &CurrentTask,
606 which_clock: i32,
607 tp_addr: UserRef<uapi::timespec>,
608 ) -> Result<(), Errno> {
609 const_assert!(
610 std::mem::size_of::<uapi::timespec>()
611 == std::mem::size_of::<uapi::arch32::__kernel_timespec>()
612 );
613 super::sys_clock_gettime(locked, current_task, which_clock, tp_addr.into())
614 }
615
616 pub fn sys_arch32_timer_gettime64(
617 locked: &mut Locked<Unlocked>,
618 current_task: &CurrentTask,
619 id: TimerId,
620 curr_value: UserRef<uapi::itimerspec>,
621 ) -> Result<(), Errno> {
622 const_assert!(
623 std::mem::size_of::<uapi::itimerspec>()
624 == std::mem::size_of::<uapi::arch32::__kernel_itimerspec>()
625 );
626 super::sys_timer_gettime(locked, current_task, id, curr_value.into())
627 }
628
629 pub use super::{
630 sys_clock_getres as sys_arch32_clock_getres, sys_clock_gettime as sys_arch32_clock_gettime,
631 sys_gettimeofday as sys_arch32_gettimeofday, sys_nanosleep as sys_arch32_nanosleep,
632 sys_setitimer as sys_arch32_setitimer, sys_settimeofday as sys_arch32_settimeofday,
633 sys_timer_create as sys_arch32_timer_create, sys_timer_delete as sys_arch32_timer_delete,
634 sys_timer_getoverrun as sys_arch32_timer_getoverrun,
635 sys_timer_gettime as sys_arch32_timer_gettime,
636 sys_timer_settime as sys_arch32_timer_settime,
637 };
638}
639
640#[cfg(target_arch = "aarch64")]
641pub use arch32::*;
642
643#[cfg(test)]
644mod test {
645 use super::*;
646 use crate::mm::PAGE_SIZE;
647 use crate::testing::{map_memory, spawn_kernel_and_run};
648 use crate::time::utc::UtcClockOverrideGuard;
649 use fuchsia_runtime::{UtcDuration, UtcTimeline};
650 use starnix_uapi::signals;
651 use starnix_uapi::user_address::UserAddress;
652 use std::sync::Arc;
653 use test_util::{assert_geq, assert_leq};
654 use zx::{self as zx, BootTimeline, Clock, ClockUpdate, HandleBased};
655
656 type UtcClock = Clock<BootTimeline, UtcTimeline>;
658 type UtcClockUpdate = ClockUpdate<BootTimeline, UtcTimeline>;
659
660 #[::fuchsia::test]
661 async fn test_nanosleep_without_remainder() {
662 spawn_kernel_and_run(async |locked, current_task| {
663 let thread = std::thread::spawn({
664 let task = current_task.weak_task();
665 move || {
666 let task = task.upgrade().expect("task must be alive");
667 while !task.read().is_blocked() {
669 std::thread::sleep(std::time::Duration::from_millis(10));
670 }
671 task.interrupt();
672 }
673 });
674
675 let duration = timespec_from_duration(zx::MonotonicDuration::from_seconds(60));
676 let address = map_memory(
677 locked,
678 ¤t_task,
679 UserAddress::default(),
680 std::mem::size_of::<timespec>() as u64,
681 );
682 let address_ptr = UserRef::<timespec>::from(address);
683 current_task.write_object(address_ptr, &duration).expect("write_object");
684
685 assert_eq!(
688 sys_nanosleep(locked, current_task, address_ptr.into(), UserRef::default().into()),
689 error!(ERESTART_RESTARTBLOCK)
690 );
691
692 thread.join().expect("join");
693 })
694 .await;
695 }
696
697 #[::fuchsia::test]
698 async fn test_clock_nanosleep_relative_to_slow_clock() {
699 spawn_kernel_and_run(async |locked, current_task| {
700 let test_clock = UtcClock::create(zx::ClockOpts::AUTO_START, None).unwrap();
701 let _test_clock_guard = UtcClockOverrideGuard::new(
702 test_clock.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
703 );
704
705 let slow_clock_update = UtcClockUpdate::builder().rate_adjust(-1000).build();
707 test_clock.update(slow_clock_update).unwrap();
708
709 let before = test_clock.read().unwrap();
710
711 let tv = timespec { tv_sec: 1, tv_nsec: 0 };
712
713 let remaining = UserRef::new(UserAddress::default());
714
715 super::clock_nanosleep_relative_to_utc(
716 locked,
717 current_task,
718 tv,
719 false,
720 remaining.into(),
721 )
722 .unwrap();
723 let elapsed = test_clock.read().unwrap() - before;
724 assert!(elapsed >= UtcDuration::from_seconds(1));
725 })
726 .await;
727 }
728
729 #[::fuchsia::test]
730 async fn test_clock_nanosleep_interrupted_relative_to_fast_utc_clock() {
731 spawn_kernel_and_run(async |locked, current_task| {
732 let test_clock = UtcClock::create(zx::ClockOpts::AUTO_START, None).unwrap();
733 let _test_clock_guard = UtcClockOverrideGuard::new(
734 test_clock.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
735 );
736
737 let slow_clock_update = UtcClockUpdate::builder().rate_adjust(1000).build();
739 test_clock.update(slow_clock_update).unwrap();
740
741 let before = test_clock.read().unwrap();
742
743 let tv = timespec { tv_sec: 2, tv_nsec: 0 };
744
745 let remaining = {
746 let addr = map_memory(locked, ¤t_task, UserAddress::default(), *PAGE_SIZE);
747 UserRef::new(addr)
748 };
749
750 let interruption_target =
753 zx::MonotonicInstant::get() + zx::MonotonicDuration::from_seconds(1);
754
755 let thread_group = Arc::downgrade(current_task.thread_group());
756 let thread_join_handle = std::thread::Builder::new()
757 .name("clock_nanosleep_interruptor".to_string())
758 .spawn(move || {
759 std::thread::sleep(std::time::Duration::from_nanos(
760 (interruption_target - zx::MonotonicInstant::get()).into_nanos() as u64,
761 ));
762 if let Some(thread_group) = thread_group.upgrade() {
763 let signal = signals::SIGALRM;
764 thread_group
765 .write()
766 .send_signal(crate::signals::SignalInfo::default(signal));
767 }
768 })
769 .unwrap();
770
771 let result = super::clock_nanosleep_relative_to_utc(
772 locked,
773 current_task,
774 tv,
775 false,
776 remaining.into(),
777 );
778
779 let mut remaining_written = Default::default();
783 if result.is_err() {
784 assert_eq!(result, error!(ERESTART_RESTARTBLOCK));
785 remaining_written = current_task.read_object(remaining).unwrap();
786 }
787 assert_leq!(
788 duration_from_timespec::<zx::MonotonicTimeline>(remaining_written).unwrap(),
789 zx::MonotonicDuration::from_seconds(2)
790 );
791 let elapsed = test_clock.read().unwrap() - before;
792 thread_join_handle.join().unwrap();
793
794 assert_geq!(
795 elapsed + duration_from_timespec(remaining_written).unwrap(),
796 UtcDuration::from_seconds(2)
797 );
798 })
799 .await;
800 }
801}