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