Skip to main content

starnix_core/syscalls/
time.rs

1// Copyright 2022 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use 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            // Error if no dynamic clock can be found.
50            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        // Return early if the user passes an obviously invalid pointer. This check is not a guarantee.
111        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        // Setting time is allowed.
127        let boot_now = zx::BootInstant::get();
128        let tv = current_task.read_multi_arch_object(tv)?;
129
130        // Any errors here result in EINVAL, there should be no overflow in "normal" situations.
131        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                // Maybe a weird choice of the error code, but the only choice
152                // between the documented error codes for `settimeofday` that
153                // seems relevant for when FIDL breaks.
154                errno!(ENOSYS)
155            })?
156            .map_err(|e| {
157                log_error!("remote error: {:?}", e);
158                // Remote should normally report an error only as a result of
159                // invalid user input. Hence, EINVAL.
160                errno!(EINVAL)
161            })
162    } else {
163        // We expect most systems not to be allowed to set time.
164        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    // TODO(https://fxrev.dev/117507): For now, Starnix pretends that the monotonic and realtime
182    // clocks advance at close to uniform rates and so we can treat relative realtime offsets the
183    // same way that we treat relative monotonic clock offsets with a linear adjustment and retries
184    // if we sleep for too little time.
185    // At some point we'll need to monitor changes to the realtime clock proactively and adjust
186    // timers accordingly.
187    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    // TODO(https://fxbug.dev/361583830): Support futex wait on different timeline deadlines.
216    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
231/// Sleep until we've satisfied |request| relative to the UTC clock which may advance at
232/// a different rate from the boot clock by repeatdly computing a boot target and sleeping.
233fn 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        // Compute boot deadline that corresponds to the UTC clocks's current transformation to
246        // boot. This may have changed while we were sleeping so check again on every
247        // iteration.
248        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        // Look at |clock| again and decide if we're done.
258        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
327/// Returns the cpu time for the task with the given `pid`.
328///
329/// Returns EINVAL if no such task can be found.
330fn 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
335/// Returns the cpu time for the process associated with the given `pid`. `pid`
336/// can be the `pid` for any task in the thread_group (so the caller can get the
337/// process cpu time for any `task` by simply using `task.get_pid()`).
338///
339/// Returns EINVAL if no such process can be found.
340fn 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
346/// Returns the type of cpu clock that `clock` encodes.
347fn which_cpu_clock(clock: i32) -> i32 {
348    const CPU_CLOCK_MASK: i32 = 3;
349    clock & CPU_CLOCK_MASK
350}
351
352/// Returns whether or not `clock` encodes a valid clock type.
353fn 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
365/// Returns the pid encoded in `clock`.
366fn pid_of_clock_id(clock: i32) -> pid_t {
367    // The pid is stored in the most significant 29 bits.
368    !(clock >> 3) as pid_t
369}
370
371/// Returns true if the clock references a thread specific clock.
372fn is_thread_clock(clock: i32) -> bool {
373    const PER_THREAD_MASK: i32 = 4;
374    clock & PER_THREAD_MASK != 0
375}
376
377/// Returns the cpu time for the clock specified in `which_clock`.
378///
379/// This is to support "dynamic clocks."
380/// https://man7.org/linux/man-pages/man2/clock_gettime.2.html
381///
382/// `which_clock` is decoded as follows:
383///   - Bit 0 and 1 are used to determine the type of clock.
384///   - Bit 3 is used to determine whether the clock is for a thread or process.
385///   - The remaining bits encode the pid of the thread/process.
386fn 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 = &current_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    // Return early if the user passes an obviously invalid pointer. This avoids changing the timer
491    // settings for common pointer errors.
492    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// Syscalls for arch32 usage
550#[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    // TODO(https://fxbug.dev/356911500): Use types below from fuchsia_runtime
611    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                    // Wait until the task is in nanosleep, and interrupt it.
622                    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                &current_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            // nanosleep will be interrupted by the current thread and should not fail with EFAULT
639            // because the remainder pointer is null.
640            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            // Slow |test_clock| down and verify that we sleep long enough.
659            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            // Speed |test_clock| up.
685            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(&current_task, UserAddress::default(), *PAGE_SIZE);
694                UserRef::new(addr)
695            };
696
697            // Interrupt the sleep roughly halfway through. The actual interruption might be before the
698            // sleep starts, during the sleep, or after.
699            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            // We can't know deterministically if our interrupter thread will be able to interrupt our sleep.
722            // If it did, result should be ERESTART_RESTARTBLOCK and |remaining| will be populated.
723            // If it didn't, the result will be OK and |remaining| will not be touched.
724            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}