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