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::{
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            // Error if no dynamic clock can be found.
53            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        // Return early if the user passes an obviously invalid pointer. This check is not a guarantee.
117        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        // Setting time is allowed.
134        let boot_now = zx::BootInstant::get();
135        let tv = current_task.read_multi_arch_object(tv)?;
136
137        // Any errors here result in EINVAL, there should be no overflow in "normal" situations.
138        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                // Maybe a weird choice of the error code, but the only choice
159                // between the documented error codes for `settimeofday` that
160                // seems relevant for when FIDL breaks.
161                errno!(ENOSYS)
162            })?
163            .map_err(|e| {
164                log_error!("remote error: {:?}", e);
165                // Remote should normally report an error only as a result of
166                // invalid user input. Hence, EINVAL.
167                errno!(EINVAL)
168            })
169    } else {
170        // We expect most systems not to be allowed to set time.
171        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    // TODO(https://fxrev.dev/117507): For now, Starnix pretends that the monotonic and realtime
190    // clocks advance at close to uniform rates and so we can treat relative realtime offsets the
191    // same way that we treat relative monotonic clock offsets with a linear adjustment and retries
192    // if we sleep for too little time.
193    // At some point we'll need to monitor changes to the realtime clock proactively and adjust
194    // timers accordingly.
195    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    // TODO(https://fxbug.dev/361583830): Support futex wait on different timeline deadlines.
230    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
246/// Sleep until we've satisfied |request| relative to the UTC clock which may advance at
247/// a different rate from the boot clock by repeatdly computing a boot target and sleeping.
248fn 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        // Compute boot deadline that corresponds to the UTC clocks's current transformation to
262        // boot. This may have changed while we were sleeping so check again on every
263        // iteration.
264        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        // Look at |clock| again and decide if we're done.
275        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
354/// Returns the cpu time for the task with the given `pid`.
355///
356/// Returns EINVAL if no such task can be found.
357fn 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
363/// Returns the cpu time for the process associated with the given `pid`. `pid`
364/// can be the `pid` for any task in the thread_group (so the caller can get the
365/// process cpu time for any `task` by simply using `task.get_pid()`).
366///
367/// Returns EINVAL if no such process can be found.
368fn 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
374/// Returns the type of cpu clock that `clock` encodes.
375fn which_cpu_clock(clock: i32) -> i32 {
376    const CPU_CLOCK_MASK: i32 = 3;
377    clock & CPU_CLOCK_MASK
378}
379
380/// Returns whether or not `clock` encodes a valid clock type.
381fn 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
393/// Returns the pid encoded in `clock`.
394fn pid_of_clock_id(clock: i32) -> pid_t {
395    // The pid is stored in the most significant 29 bits.
396    !(clock >> 3) as pid_t
397}
398
399/// Returns true if the clock references a thread specific clock.
400fn is_thread_clock(clock: i32) -> bool {
401    const PER_THREAD_MASK: i32 = 4;
402    clock & PER_THREAD_MASK != 0
403}
404
405/// Returns the cpu time for the clock specified in `which_clock`.
406///
407/// This is to support "dynamic clocks."
408/// https://man7.org/linux/man-pages/man2/clock_gettime.2.html
409///
410/// `which_clock` is decoded as follows:
411///   - Bit 0 and 1 are used to determine the type of clock.
412///   - Bit 3 is used to determine whether the clock is for a thread or process.
413///   - The remaining bits encode the pid of the thread/process.
414fn 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 = &current_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    // Return early if the user passes an obviously invalid pointer. This avoids changing the timer
530    // settings for common pointer errors.
531    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// Syscalls for arch32 usage
595#[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    // TODO(https://fxbug.dev/356911500): Use types below from fuchsia_runtime
658    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                    // Wait until the task is in nanosleep, and interrupt it.
669                    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                &current_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            // nanosleep will be interrupted by the current thread and should not fail with EFAULT
687            // because the remainder pointer is null.
688            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            // Slow |test_clock| down and verify that we sleep long enough.
707            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            // Speed |test_clock| up.
739            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, &current_task, UserAddress::default(), *PAGE_SIZE);
748                UserRef::new(addr)
749            };
750
751            // Interrupt the sleep roughly halfway through. The actual interruption might be before the
752            // sleep starts, during the sleep, or after.
753            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            // We can't know deterministically if our interrupter thread will be able to interrupt our sleep.
781            // If it did, result should be ERESTART_RESTARTBLOCK and |remaining| will be populated.
782            // If it didn't, the result will be OK and |remaining| will not be touched.
783            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}