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_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            // Error if no dynamic clock can be found.
51            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        // Return early if the user passes an obviously invalid pointer. This check is not a guarantee.
115        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        // Setting time is allowed.
132        let boot_now = zx::BootInstant::get();
133        let tv = current_task.read_multi_arch_object(tv)?;
134
135        // Any errors here result in EINVAL, there should be no overflow in "normal" situations.
136        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                // Maybe a weird choice of the error code, but the only choice
157                // between the documented error codes for `settimeofday` that
158                // seems relevant for when FIDL breaks.
159                errno!(ENOSYS)
160            })?
161            .map_err(|e| {
162                log_error!("remote error: {:?}", e);
163                // Remote should normally report an error only as a result of
164                // invalid user input. Hence, EINVAL.
165                errno!(EINVAL)
166            })
167    } else {
168        // We expect most systems not to be allowed to set time.
169        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    // TODO(https://fxrev.dev/117507): For now, Starnix pretends that the monotonic and realtime
188    // clocks advance at close to uniform rates and so we can treat relative realtime offsets the
189    // same way that we treat relative monotonic clock offsets with a linear adjustment and retries
190    // if we sleep for too little time.
191    // At some point we'll need to monitor changes to the realtime clock proactively and adjust
192    // timers accordingly.
193    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    // TODO(https://fxbug.dev/361583830): Support futex wait on different timeline deadlines.
228    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
244/// Sleep until we've satisfied |request| relative to the UTC clock which may advance at
245/// a different rate from the boot clock by repeatdly computing a boot target and sleeping.
246fn 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        // Compute boot deadline that corresponds to the UTC clocks's current transformation to
260        // boot. This may have changed while we were sleeping so check again on every
261        // iteration.
262        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        // Look at |clock| again and decide if we're done.
273        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
352/// Returns the cpu time for the task with the given `pid`.
353///
354/// Returns EINVAL if no such task can be found.
355fn get_thread_cpu_time(current_task: &CurrentTask, tid: tid_t) -> Result<i64, Errno> {
356    let task = current_task.get_task(tid).map_err(|_| errno!(EINVAL))?;
357    Ok(task.thread_runtime_info()?.cpu_time)
358}
359
360/// Returns the cpu time for the process associated with the given `pid`. `pid`
361/// can be the `pid` for any task in the thread_group (so the caller can get the
362/// process cpu time for any `task` by simply using `task.get_pid()`).
363///
364/// Returns EINVAL if no such process can be found.
365fn get_process_cpu_time(current_task: &CurrentTask, pid: pid_t) -> Result<i64, Errno> {
366    let pids = current_task.kernel().pids.read();
367    let tg = pids.get_thread_group(pid).ok_or_else(|| errno!(EINVAL))?;
368    Ok(tg.process.get_runtime_info().map_err(|status| from_status_like_fdio!(status))?.cpu_time)
369}
370
371/// Returns the type of cpu clock that `clock` encodes.
372fn which_cpu_clock(clock: i32) -> i32 {
373    const CPU_CLOCK_MASK: i32 = 3;
374    clock & CPU_CLOCK_MASK
375}
376
377/// Returns whether or not `clock` encodes a valid clock type.
378fn is_valid_cpu_clock(clock: i32) -> bool {
379    const MAX_CPU_CLOCK: i32 = 3;
380    if clock & 7 == 7 {
381        return false;
382    }
383    if which_cpu_clock(clock) >= MAX_CPU_CLOCK {
384        return false;
385    }
386
387    true
388}
389
390/// Returns the pid encoded in `clock`.
391fn pid_of_clock_id(clock: i32) -> pid_t {
392    // The pid is stored in the most significant 29 bits.
393    !(clock >> 3) as pid_t
394}
395
396/// Returns true if the clock references a thread specific clock.
397fn is_thread_clock(clock: i32) -> bool {
398    const PER_THREAD_MASK: i32 = 4;
399    clock & PER_THREAD_MASK != 0
400}
401
402/// Returns the cpu time for the clock specified in `which_clock`.
403///
404/// This is to support "dynamic clocks."
405/// https://man7.org/linux/man-pages/man2/clock_gettime.2.html
406///
407/// `which_clock` is decoded as follows:
408///   - Bit 0 and 1 are used to determine the type of clock.
409///   - Bit 3 is used to determine whether the clock is for a thread or process.
410///   - The remaining bits encode the pid of the thread/process.
411fn get_dynamic_clock(current_task: &CurrentTask, which_clock: i32) -> Result<i64, Errno> {
412    if !is_valid_cpu_clock(which_clock) {
413        return error!(EINVAL);
414    }
415
416    let pid = pid_of_clock_id(which_clock);
417
418    if is_thread_clock(which_clock) {
419        get_thread_cpu_time(current_task, pid)
420    } else {
421        get_process_cpu_time(current_task, pid)
422    }
423}
424
425pub fn sys_timer_create(
426    _locked: &mut Locked<Unlocked>,
427    current_task: &CurrentTask,
428    clock_id: ClockId,
429    event: MultiArchUserRef<uapi::sigevent, uapi::arch32::sigevent>,
430    timerid: UserRef<TimerId>,
431) -> Result<(), Errno> {
432    if clock_id >= MAX_CLOCKS as TimerId {
433        return error!(EINVAL);
434    }
435    let user_event = if event.addr().is_null() {
436        None
437    } else {
438        Some(current_task.read_multi_arch_object(event)?)
439    };
440
441    let mut checked_signal_event: Option<SignalEvent> = None;
442    let thread_group = current_task.thread_group();
443    if let Some(user_event) = user_event {
444        let signal_event: SignalEvent = user_event.try_into()?;
445        if !signal_event.is_valid(&thread_group.read()) {
446            return error!(EINVAL);
447        }
448        checked_signal_event = Some(signal_event);
449    }
450    let timeline = match clock_id as u32 {
451        CLOCK_REALTIME => Timeline::RealTime,
452        CLOCK_MONOTONIC => Timeline::Monotonic,
453        CLOCK_BOOTTIME => Timeline::BootInstant,
454        CLOCK_REALTIME_ALARM => Timeline::RealTime,
455        CLOCK_BOOTTIME_ALARM => Timeline::BootInstant,
456        CLOCK_TAI => {
457            track_stub!(TODO("https://fxbug.dev/349191834"), "timers w/ TAI");
458            return error!(ENOTSUP);
459        }
460        CLOCK_PROCESS_CPUTIME_ID => {
461            track_stub!(TODO("https://fxbug.dev/349188105"), "timers w/ calling process cpu time");
462            return error!(ENOTSUP);
463        }
464        CLOCK_THREAD_CPUTIME_ID => {
465            track_stub!(TODO("https://fxbug.dev/349188105"), "timers w/ calling thread cpu time");
466            return error!(ENOTSUP);
467        }
468        _ => {
469            track_stub!(TODO("https://fxbug.dev/349188105"), "timers w/ dynamic process clocks");
470            return error!(ENOTSUP);
471        }
472    };
473    let timer_wakeup = match clock_id as u32 {
474        CLOCK_BOOTTIME_ALARM | CLOCK_REALTIME_ALARM => {
475            security::check_task_capable(current_task, CAP_WAKE_ALARM)?;
476            TimerWakeup::Alarm
477        }
478        _ => TimerWakeup::Regular,
479    };
480
481    let id = &thread_group.timers.create(timeline, timer_wakeup, checked_signal_event)?;
482    current_task.write_object(timerid, &id)?;
483    Ok(())
484}
485
486pub fn sys_timer_delete(
487    _locked: &mut Locked<Unlocked>,
488    current_task: &CurrentTask,
489    id: TimerId,
490) -> Result<(), Errno> {
491    current_task.thread_group().timers.delete(current_task, id)
492}
493
494pub fn sys_timer_gettime(
495    _locked: &mut Locked<Unlocked>,
496    current_task: &CurrentTask,
497    id: TimerId,
498    curr_value: ITimerSpecPtr,
499) -> Result<(), Errno> {
500    let timers = &current_task.thread_group().timers;
501    current_task.write_multi_arch_object(curr_value, timers.get_time(id)?)?;
502    Ok(())
503}
504
505pub fn sys_timer_getoverrun(
506    _locked: &mut Locked<Unlocked>,
507    current_task: &CurrentTask,
508    id: TimerId,
509) -> Result<i32, Errno> {
510    current_task.thread_group().timers.get_overrun(id)
511}
512
513pub fn sys_timer_settime(
514    _locked: &mut Locked<Unlocked>,
515    current_task: &CurrentTask,
516    id: TimerId,
517    flags: i32,
518    user_new_value: ITimerSpecPtr,
519    user_old_value: ITimerSpecPtr,
520) -> Result<(), Errno> {
521    if user_new_value.is_null() {
522        return error!(EINVAL);
523    }
524    let new_value = current_task.read_multi_arch_object(user_new_value)?;
525
526    // Return early if the user passes an obviously invalid pointer. This avoids changing the timer
527    // settings for common pointer errors.
528    if !user_old_value.is_null() {
529        current_task.write_multi_arch_object(user_old_value, Default::default())?;
530    }
531
532    let old_value =
533        current_task.thread_group().timers.set_time(current_task, id, flags, new_value)?;
534
535    if !user_old_value.is_null() {
536        current_task.write_multi_arch_object(user_old_value, old_value)?;
537    }
538    Ok(())
539}
540
541pub fn sys_getitimer(
542    _locked: &mut Locked<Unlocked>,
543    current_task: &CurrentTask,
544    which: u32,
545    user_curr_value: ITimerValPtr,
546) -> Result<(), Errno> {
547    let remaining = current_task.thread_group().get_itimer(which)?;
548    current_task.write_multi_arch_object(user_curr_value, remaining)?;
549    Ok(())
550}
551
552pub fn sys_setitimer(
553    _locked: &mut Locked<Unlocked>,
554    current_task: &CurrentTask,
555    which: u32,
556    user_new_value: ITimerValPtr,
557    user_old_value: ITimerValPtr,
558) -> Result<(), Errno> {
559    let new_value = current_task.read_multi_arch_object(user_new_value)?;
560
561    let old_value = current_task.thread_group().set_itimer(current_task, which, new_value)?;
562
563    if !user_old_value.is_null() {
564        current_task.write_multi_arch_object(user_old_value, old_value)?;
565    }
566
567    Ok(())
568}
569
570pub fn sys_times(
571    _locked: &mut Locked<Unlocked>,
572    current_task: &CurrentTask,
573    buf: UserRef<tms>,
574) -> Result<i64, Errno> {
575    if !buf.is_null() {
576        let thread_group = current_task.thread_group();
577        let process_time_stats = thread_group.time_stats();
578        let children_time_stats = thread_group.read().children_time_stats;
579        let tms_result = tms {
580            tms_utime: duration_to_scheduler_clock(process_time_stats.user_time),
581            tms_stime: duration_to_scheduler_clock(process_time_stats.system_time),
582            tms_cutime: duration_to_scheduler_clock(children_time_stats.user_time),
583            tms_cstime: duration_to_scheduler_clock(children_time_stats.system_time),
584        };
585        current_task.write_object(buf, &tms_result)?;
586    }
587
588    Ok(duration_to_scheduler_clock(zx::MonotonicInstant::get() - zx::MonotonicInstant::ZERO))
589}
590
591// Syscalls for arch32 usage
592#[cfg(target_arch = "aarch64")]
593mod arch32 {
594    use crate::task::CurrentTask;
595    use crate::time::TimerId;
596    use starnix_sync::{Locked, Unlocked};
597    use starnix_uapi::errors::Errno;
598    use starnix_uapi::uapi;
599    use starnix_uapi::user_address::UserRef;
600    use static_assertions::const_assert;
601
602    pub fn sys_arch32_clock_gettime64(
603        locked: &mut Locked<Unlocked>,
604        current_task: &CurrentTask,
605        which_clock: i32,
606        tp_addr: UserRef<uapi::timespec>,
607    ) -> Result<(), Errno> {
608        const_assert!(
609            std::mem::size_of::<uapi::timespec>()
610                == std::mem::size_of::<uapi::arch32::__kernel_timespec>()
611        );
612        super::sys_clock_gettime(locked, current_task, which_clock, tp_addr.into())
613    }
614
615    pub fn sys_arch32_timer_gettime64(
616        locked: &mut Locked<Unlocked>,
617        current_task: &CurrentTask,
618        id: TimerId,
619        curr_value: UserRef<uapi::itimerspec>,
620    ) -> Result<(), Errno> {
621        const_assert!(
622            std::mem::size_of::<uapi::itimerspec>()
623                == std::mem::size_of::<uapi::arch32::__kernel_itimerspec>()
624        );
625        super::sys_timer_gettime(locked, current_task, id, curr_value.into())
626    }
627
628    pub use super::{
629        sys_clock_getres as sys_arch32_clock_getres, sys_clock_gettime as sys_arch32_clock_gettime,
630        sys_gettimeofday as sys_arch32_gettimeofday, sys_nanosleep as sys_arch32_nanosleep,
631        sys_setitimer as sys_arch32_setitimer, sys_settimeofday as sys_arch32_settimeofday,
632        sys_timer_create as sys_arch32_timer_create, sys_timer_delete as sys_arch32_timer_delete,
633        sys_timer_getoverrun as sys_arch32_timer_getoverrun,
634        sys_timer_gettime as sys_arch32_timer_gettime,
635        sys_timer_settime as sys_arch32_timer_settime,
636    };
637}
638
639#[cfg(target_arch = "aarch64")]
640pub use arch32::*;
641
642#[cfg(test)]
643mod test {
644    use super::*;
645    use crate::mm::PAGE_SIZE;
646    use crate::testing::{map_memory, spawn_kernel_and_run};
647    use crate::time::utc::UtcClockOverrideGuard;
648    use fuchsia_runtime::{UtcDuration, UtcTimeline};
649    use starnix_uapi::signals;
650    use starnix_uapi::user_address::UserAddress;
651    use std::sync::Arc;
652    use test_util::{assert_geq, assert_leq};
653    use zx::{BootTimeline, Clock, ClockUpdate};
654
655    // TODO(https://fxbug.dev/356911500): Use types below from fuchsia_runtime
656    type UtcClock = Clock<BootTimeline, UtcTimeline>;
657    type UtcClockUpdate = ClockUpdate<BootTimeline, UtcTimeline>;
658
659    #[::fuchsia::test]
660    async fn test_nanosleep_without_remainder() {
661        spawn_kernel_and_run(async |locked, current_task| {
662            let thread = std::thread::spawn({
663                let task = current_task.weak_task();
664                move || {
665                    let task = task.upgrade().expect("task must be alive");
666                    // Wait until the task is in nanosleep, and interrupt it.
667                    while !task.read().is_blocked() {
668                        std::thread::sleep(std::time::Duration::from_millis(10));
669                    }
670                    task.interrupt();
671                }
672            });
673
674            let duration = timespec_from_duration(zx::MonotonicDuration::from_seconds(60));
675            let address = map_memory(
676                locked,
677                &current_task,
678                UserAddress::default(),
679                std::mem::size_of::<timespec>() as u64,
680            );
681            let address_ptr = UserRef::<timespec>::from(address);
682            current_task.write_object(address_ptr, &duration).expect("write_object");
683
684            // nanosleep will be interrupted by the current thread and should not fail with EFAULT
685            // because the remainder pointer is null.
686            assert_eq!(
687                sys_nanosleep(locked, current_task, address_ptr.into(), UserRef::default().into()),
688                error!(ERESTART_RESTARTBLOCK)
689            );
690
691            thread.join().expect("join");
692        })
693        .await;
694    }
695
696    #[::fuchsia::test]
697    async fn test_clock_nanosleep_relative_to_slow_clock() {
698        spawn_kernel_and_run(async |locked, current_task| {
699            let test_clock = UtcClock::create(zx::ClockOpts::AUTO_START, None).unwrap();
700            let _test_clock_guard = UtcClockOverrideGuard::new(
701                test_clock.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
702            );
703
704            // Slow |test_clock| down and verify that we sleep long enough.
705            let slow_clock_update = UtcClockUpdate::builder().rate_adjust(-1000).build();
706            test_clock.update(slow_clock_update).unwrap();
707
708            let before = test_clock.read().unwrap();
709
710            let tv = timespec { tv_sec: 1, tv_nsec: 0 };
711
712            let remaining = UserRef::new(UserAddress::default());
713
714            super::clock_nanosleep_relative_to_utc(
715                locked,
716                current_task,
717                tv,
718                false,
719                remaining.into(),
720            )
721            .unwrap();
722            let elapsed = test_clock.read().unwrap() - before;
723            assert!(elapsed >= UtcDuration::from_seconds(1));
724        })
725        .await;
726    }
727
728    #[::fuchsia::test]
729    async fn test_clock_nanosleep_interrupted_relative_to_fast_utc_clock() {
730        spawn_kernel_and_run(async |locked, current_task| {
731            let test_clock = UtcClock::create(zx::ClockOpts::AUTO_START, None).unwrap();
732            let _test_clock_guard = UtcClockOverrideGuard::new(
733                test_clock.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
734            );
735
736            // Speed |test_clock| up.
737            let slow_clock_update = UtcClockUpdate::builder().rate_adjust(1000).build();
738            test_clock.update(slow_clock_update).unwrap();
739
740            let before = test_clock.read().unwrap();
741
742            let tv = timespec { tv_sec: 2, tv_nsec: 0 };
743
744            let remaining = {
745                let addr = map_memory(locked, &current_task, UserAddress::default(), *PAGE_SIZE);
746                UserRef::new(addr)
747            };
748
749            // Interrupt the sleep roughly halfway through. The actual interruption might be before the
750            // sleep starts, during the sleep, or after.
751            let interruption_target =
752                zx::MonotonicInstant::get() + zx::MonotonicDuration::from_seconds(1);
753
754            let thread_group = Arc::downgrade(current_task.thread_group());
755            let thread_join_handle = std::thread::Builder::new()
756                .name("clock_nanosleep_interruptor".to_string())
757                .spawn(move || {
758                    std::thread::sleep(std::time::Duration::from_nanos(
759                        (interruption_target - zx::MonotonicInstant::get()).into_nanos() as u64,
760                    ));
761                    if let Some(thread_group) = thread_group.upgrade() {
762                        let signal = signals::SIGALRM;
763                        thread_group
764                            .write()
765                            .send_signal(crate::signals::SignalInfo::kernel(signal));
766                    }
767                })
768                .unwrap();
769
770            let result = super::clock_nanosleep_relative_to_utc(
771                locked,
772                current_task,
773                tv,
774                false,
775                remaining.into(),
776            );
777
778            // We can't know deterministically if our interrupter thread will be able to interrupt our sleep.
779            // If it did, result should be ERESTART_RESTARTBLOCK and |remaining| will be populated.
780            // If it didn't, the result will be OK and |remaining| will not be touched.
781            let mut remaining_written = Default::default();
782            if result.is_err() {
783                assert_eq!(result, error!(ERESTART_RESTARTBLOCK));
784                remaining_written = current_task.read_object(remaining).unwrap();
785            }
786            assert_leq!(
787                duration_from_timespec::<zx::MonotonicTimeline>(remaining_written).unwrap(),
788                zx::MonotonicDuration::from_seconds(2)
789            );
790            let elapsed = test_clock.read().unwrap() - before;
791            thread_join_handle.join().unwrap();
792
793            assert_geq!(
794                elapsed + duration_from_timespec(remaining_written).unwrap(),
795                UtcDuration::from_seconds(2)
796            );
797        })
798        .await;
799    }
800}