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::{
9    CurrentTask, EventHandler, SignalHandler, SignalHandlerInner, Task, ThreadGroup, Waiter,
10};
11use crate::time::utc::utc_now;
12use crate::time::{ClockId, GenericDuration, Timeline, TimerId, TimerWakeup};
13use fuchsia_runtime::UtcInstant;
14use starnix_logging::{log_debug, log_error, log_trace, track_stub};
15use starnix_types::time::{
16    NANOS_PER_SECOND, duration_from_timespec, duration_to_scheduler_clock, time_from_timespec,
17    timespec_from_duration, timespec_is_zero, timeval_from_time,
18};
19use starnix_uapi::auth::CAP_WAKE_ALARM;
20use starnix_uapi::errors::{EINTR, Errno};
21use starnix_uapi::user_address::{MultiArchUserRef, UserRef};
22use starnix_uapi::{
23    CLOCK_BOOTTIME, CLOCK_BOOTTIME_ALARM, CLOCK_MONOTONIC, CLOCK_MONOTONIC_COARSE,
24    CLOCK_MONOTONIC_RAW, CLOCK_PROCESS_CPUTIME_ID, CLOCK_REALTIME, CLOCK_REALTIME_ALARM,
25    CLOCK_REALTIME_COARSE, CLOCK_TAI, CLOCK_THREAD_CPUTIME_ID, MAX_CLOCKS, TIMER_ABSTIME, errno,
26    error, from_status_like_fdio, pid_t, timespec, timezone, tms, uapi,
27};
28use zx::{
29    Task as _, {self as zx},
30};
31
32pub type TimeSpecPtr = MultiArchUserRef<uapi::timespec, uapi::arch32::timespec>;
33pub type ITimerSpecPtr = MultiArchUserRef<uapi::itimerspec, uapi::arch32::itimerspec>;
34pub type ITimerValPtr = MultiArchUserRef<uapi::itimerval, uapi::arch32::itimerval>;
35pub type TimeValPtr = MultiArchUserRef<uapi::timeval, uapi::arch32::timeval>;
36type TimeZonePtr = MultiArchUserRef<uapi::timezone, uapi::arch32::timezone>;
37
38fn get_clock_res(current_task: &CurrentTask, which_clock: i32) -> Result<timespec, Errno> {
39    match which_clock as u32 {
40        CLOCK_REALTIME
41        | CLOCK_REALTIME_ALARM
42        | CLOCK_REALTIME_COARSE
43        | CLOCK_MONOTONIC
44        | CLOCK_MONOTONIC_COARSE
45        | CLOCK_MONOTONIC_RAW
46        | CLOCK_BOOTTIME
47        | CLOCK_BOOTTIME_ALARM
48        | CLOCK_THREAD_CPUTIME_ID
49        | CLOCK_PROCESS_CPUTIME_ID => Ok(timespec { tv_sec: 0, tv_nsec: 1 }),
50        _ => {
51            // Error if no dynamic clock can be found.
52            let _ = get_dynamic_clock(current_task, which_clock)?;
53            Ok(timespec { tv_sec: 0, tv_nsec: 1 })
54        }
55    }
56}
57
58pub fn sys_clock_getres(
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)?,
85            CLOCK_PROCESS_CPUTIME_ID => get_process_cpu_time(current_task.thread_group())?,
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    current_task: &CurrentTask,
94    which_clock: i32,
95    tp_addr: TimeSpecPtr,
96) -> Result<(), Errno> {
97    let tv = get_clock_gettime(current_task, which_clock)?;
98    current_task.write_multi_arch_object(tp_addr, tv)?;
99    Ok(())
100}
101
102pub fn sys_gettimeofday(
103    current_task: &CurrentTask,
104    user_tv: TimeValPtr,
105    user_tz: TimeZonePtr,
106) -> Result<(), Errno> {
107    if !user_tv.is_null() {
108        let tv = timeval_from_time(utc_now());
109        current_task.write_multi_arch_object(user_tv, tv)?;
110    }
111    if !user_tz.is_null() {
112        // Return early if the user passes an obviously invalid pointer. This check is not a guarantee.
113        current_task.mm()?.check_plausible(user_tz.addr(), std::mem::size_of::<timezone>())?;
114        track_stub!(TODO("https://fxbug.dev/322874502"), "gettimeofday tz argument");
115    }
116    Ok(())
117}
118
119pub fn sys_settimeofday(
120    current_task: &CurrentTask,
121    tv: TimeValPtr,
122    _tz: TimeZonePtr,
123) -> Result<(), Errno> {
124    const SEC_IN_NANOS: i64 = 1_000_000_000;
125    const USEC_IN_NANOS: i64 = 1000;
126    let kernel = current_task.kernel();
127    if let Some(ref proxy) = kernel.time_adjustment_proxy {
128        // Setting time is allowed.
129        let boot_now = zx::BootInstant::get();
130        let tv = current_task.read_multi_arch_object(tv)?;
131
132        // Any errors here result in EINVAL, there should be no overflow in "normal" situations.
133        let utc_now_sec_as_nanos =
134            tv.tv_sec.checked_mul(SEC_IN_NANOS).ok_or_else(|| errno!(EINVAL))?;
135        let utc_now_usec_as_nanos =
136            tv.tv_usec.checked_mul(USEC_IN_NANOS).ok_or_else(|| errno!(EINVAL))?;
137        let utc_now_nanos = utc_now_sec_as_nanos
138            .checked_add(utc_now_usec_as_nanos)
139            .ok_or_else(|| errno!(EINVAL))?;
140        log_debug!(
141            "settimeofday: reporting reference: boot_now={:?}, utc_now_nanos={:?}",
142            boot_now,
143            utc_now_nanos
144        );
145        proxy
146            .report_boot_to_utc_mapping(
147                boot_now.into(),
148                utc_now_nanos,
149                zx::MonotonicInstant::INFINITE,
150            )
151            .map_err(|e| {
152                log_error!("FIDL error: {:?}", e);
153                // Maybe a weird choice of the error code, but the only choice
154                // between the documented error codes for `settimeofday` that
155                // seems relevant for when FIDL breaks.
156                errno!(ENOSYS)
157            })?
158            .map_err(|e| {
159                log_error!("remote error: {:?}", e);
160                // Remote should normally report an error only as a result of
161                // invalid user input. Hence, EINVAL.
162                errno!(EINVAL)
163            })
164    } else {
165        // We expect most systems not to be allowed to set time.
166        log_debug!("settimeofday: No functionality");
167        error!(ENOSYS)
168    }
169}
170
171pub fn sys_clock_nanosleep(
172    current_task: &mut CurrentTask,
173    which_clock: ClockId,
174    flags: u32,
175    user_request: TimeSpecPtr,
176    user_remaining: TimeSpecPtr,
177) -> Result<(), Errno> {
178    if which_clock < 0 {
179        return error!(EINVAL);
180    }
181    let which_clock = which_clock as u32;
182    let is_absolute = flags == TIMER_ABSTIME;
183    // TODO(https://fxrev.dev/117507): For now, Starnix pretends that the monotonic and realtime
184    // clocks advance at close to uniform rates and so we can treat relative realtime offsets the
185    // same way that we treat relative monotonic clock offsets with a linear adjustment and retries
186    // if we sleep for too little time.
187    // At some point we'll need to monitor changes to the realtime clock proactively and adjust
188    // timers accordingly.
189    match which_clock {
190        CLOCK_REALTIME | CLOCK_MONOTONIC | CLOCK_BOOTTIME => {}
191        CLOCK_TAI => {
192            track_stub!(TODO("https://fxbug.dev/322875165"), "clock_nanosleep, CLOCK_TAI", flags);
193            return error!(EINVAL);
194        }
195        CLOCK_PROCESS_CPUTIME_ID => {
196            track_stub!(
197                TODO("https://fxbug.dev/322874886"),
198                "clock_nanosleep, CLOCK_PROCESS_CPUTIME_ID",
199                flags
200            );
201            return error!(EINVAL);
202        }
203        _ => return error!(ENOTSUP),
204    }
205
206    let request = current_task.read_multi_arch_object(user_request)?;
207    log_trace!("clock_nanosleep({}, {}, {:?})", which_clock, flags, request);
208
209    if timespec_is_zero(request) {
210        return Ok(());
211    }
212
213    if which_clock == CLOCK_REALTIME {
214        return clock_nanosleep_relative_to_utc(current_task, request, is_absolute, user_remaining);
215    }
216
217    // TODO(https://fxbug.dev/361583830): Support futex wait on different timeline deadlines.
218    let boot_deadline = if is_absolute {
219        time_from_timespec(request)?
220    } else {
221        zx::BootInstant::after(duration_from_timespec(request)?)
222    };
223
224    clock_nanosleep_boot_with_deadline(
225        current_task,
226        is_absolute,
227        boot_deadline,
228        None,
229        user_remaining,
230    )
231}
232
233/// Sleep until we've satisfied |request| relative to the UTC clock which may advance at
234/// a different rate from the boot clock by repeatdly computing a boot target and sleeping.
235fn clock_nanosleep_relative_to_utc(
236    current_task: &mut CurrentTask,
237    request: timespec,
238    is_absolute: bool,
239    user_remaining: TimeSpecPtr,
240) -> Result<(), Errno> {
241    let clock_deadline_absolute = if is_absolute {
242        time_from_timespec(request)?
243    } else {
244        utc_now() + duration_from_timespec(request)?
245    };
246    loop {
247        // Compute boot deadline that corresponds to the UTC clocks's current transformation to
248        // boot. This may have changed while we were sleeping so check again on every
249        // iteration.
250        let (boot_deadline, _) =
251            crate::time::utc::estimate_boot_deadline_from_utc(clock_deadline_absolute);
252        clock_nanosleep_boot_with_deadline(
253            current_task,
254            is_absolute,
255            boot_deadline,
256            Some(clock_deadline_absolute),
257            user_remaining,
258        )?;
259        // Look at |clock| again and decide if we're done.
260        let clock_now = utc_now();
261        if clock_now >= clock_deadline_absolute {
262            return Ok(());
263        }
264        log_trace!(
265            "clock_nanosleep_relative_to_clock short by {:?}, sleeping again",
266            clock_deadline_absolute - clock_now
267        );
268    }
269}
270
271fn clock_nanosleep_boot_with_deadline(
272    current_task: &mut CurrentTask,
273    is_absolute: bool,
274    deadline: zx::BootInstant,
275    original_utc_deadline: Option<UtcInstant>,
276    user_remaining: TimeSpecPtr,
277) -> Result<(), Errno> {
278    let waiter = Waiter::new();
279    let timer = zx::BootTimer::create();
280    let signal_handler = SignalHandler {
281        inner: SignalHandlerInner::None,
282        event_handler: EventHandler::None,
283        err_code: None,
284    };
285    waiter
286        .wake_on_zircon_signals(&timer, zx::Signals::TIMER_SIGNALED, signal_handler)
287        .expect("wait can only fail in OOM conditions");
288    let timer_slack = current_task.read().get_timerslack();
289    timer.set(deadline, timer_slack).expect("timer set cannot fail with valid handles and slack");
290    match waiter.wait(current_task) {
291        Err(err) if err == EINTR && is_absolute => error!(ERESTARTNOHAND),
292        Err(err) if err == EINTR => {
293            if !user_remaining.is_null() {
294                let remaining = match original_utc_deadline {
295                    Some(original_utc_deadline) => {
296                        GenericDuration::from(original_utc_deadline - utc_now())
297                    }
298                    None => GenericDuration::from(deadline - zx::BootInstant::get()),
299                };
300                let remaining = timespec_from_duration(*std::cmp::max(
301                    GenericDuration::from_nanos(0),
302                    remaining,
303                ));
304                current_task.write_multi_arch_object(user_remaining, remaining)?;
305            }
306            current_task.set_syscall_restart_func(move |current_task| {
307                clock_nanosleep_boot_with_deadline(
308                    current_task,
309                    is_absolute,
310                    deadline,
311                    original_utc_deadline,
312                    user_remaining,
313                )
314            });
315            error!(ERESTART_RESTARTBLOCK)
316        }
317        non_eintr => non_eintr,
318    }
319}
320
321pub fn sys_nanosleep(
322    current_task: &mut CurrentTask,
323    user_request: TimeSpecPtr,
324    user_remaining: TimeSpecPtr,
325) -> Result<(), Errno> {
326    sys_clock_nanosleep(current_task, CLOCK_REALTIME as ClockId, 0, user_request, user_remaining)
327}
328
329/// Returns the cpu time for `task`.
330fn get_thread_cpu_time(task: &Task) -> Result<i64, Errno> {
331    Ok(task.thread_runtime_info()?.cpu_time)
332}
333
334/// Returns the cpu time for the thread group `tg`.
335fn get_process_cpu_time(tg: &ThreadGroup) -> Result<i64, Errno> {
336    Ok(tg.process.get_runtime_info().map_err(|status| from_status_like_fdio!(status))?.cpu_time)
337}
338
339/// Returns the type of cpu clock that `clock` encodes.
340fn which_cpu_clock(clock: i32) -> i32 {
341    const CPU_CLOCK_MASK: i32 = 3;
342    clock & CPU_CLOCK_MASK
343}
344
345/// Returns whether or not `clock` encodes a valid clock type.
346fn is_valid_cpu_clock(clock: i32) -> bool {
347    const MAX_CPU_CLOCK: i32 = 3;
348    if clock & 7 == 7 {
349        return false;
350    }
351    if which_cpu_clock(clock) >= MAX_CPU_CLOCK {
352        return false;
353    }
354
355    true
356}
357
358/// Returns the pid encoded in `clock`.
359fn pid_of_clock_id(clock: i32) -> pid_t {
360    // The pid is stored in the most significant 29 bits.
361    !(clock >> 3) as pid_t
362}
363
364/// Returns true if the clock references a thread specific clock.
365fn is_thread_clock(clock: i32) -> bool {
366    const PER_THREAD_MASK: i32 = 4;
367    clock & PER_THREAD_MASK != 0
368}
369
370/// Returns the cpu time for the clock specified in `which_clock`.
371///
372/// This is to support "dynamic clocks."
373/// https://man7.org/linux/man-pages/man2/clock_gettime.2.html
374///
375/// `which_clock` is decoded as follows:
376///   - Bit 0 and 1 are used to determine the type of clock.
377///   - Bit 3 is used to determine whether the clock is for a thread or process.
378///   - The remaining bits encode the pid of the thread/process.
379fn get_dynamic_clock(current_task: &CurrentTask, which_clock: i32) -> Result<i64, Errno> {
380    if !is_valid_cpu_clock(which_clock) {
381        return error!(EINVAL);
382    }
383
384    let pid = pid_of_clock_id(which_clock);
385    let target_pid = current_task.kernel().pids.get(pid).map_err(|_| errno!(EINVAL))?;
386
387    if is_thread_clock(which_clock) {
388        let task = target_pid.get_task().map_err(|_| errno!(EINVAL))?;
389        get_thread_cpu_time(&task)
390    } else {
391        let tg = target_pid.get_thread_group().map_err(|_| errno!(EINVAL))?;
392        get_process_cpu_time(&tg)
393    }
394}
395
396pub fn sys_timer_create(
397    current_task: &CurrentTask,
398    clock_id: ClockId,
399    event: MultiArchUserRef<uapi::sigevent, uapi::arch32::sigevent>,
400    timerid: UserRef<TimerId>,
401) -> Result<(), Errno> {
402    if clock_id >= MAX_CLOCKS as TimerId {
403        return error!(EINVAL);
404    }
405    let user_event = if event.addr().is_null() {
406        None
407    } else {
408        Some(current_task.read_multi_arch_object(event)?)
409    };
410
411    let mut checked_signal_event: Option<SignalEvent> = None;
412    let thread_group = current_task.thread_group();
413    if let Some(user_event) = user_event {
414        let signal_event: SignalEvent = user_event.try_into()?;
415        if !signal_event.is_valid(&thread_group.read()) {
416            return error!(EINVAL);
417        }
418        checked_signal_event = Some(signal_event);
419    }
420    let timeline = match clock_id as u32 {
421        CLOCK_REALTIME => Timeline::RealTime,
422        CLOCK_MONOTONIC => Timeline::Monotonic,
423        CLOCK_BOOTTIME => Timeline::BootInstant,
424        CLOCK_REALTIME_ALARM => Timeline::RealTime,
425        CLOCK_BOOTTIME_ALARM => Timeline::BootInstant,
426        CLOCK_TAI => {
427            track_stub!(TODO("https://fxbug.dev/349191834"), "timers w/ TAI");
428            return error!(ENOTSUP);
429        }
430        CLOCK_PROCESS_CPUTIME_ID => {
431            track_stub!(TODO("https://fxbug.dev/349188105"), "timers w/ calling process cpu time");
432            return error!(ENOTSUP);
433        }
434        CLOCK_THREAD_CPUTIME_ID => {
435            track_stub!(TODO("https://fxbug.dev/349188105"), "timers w/ calling thread cpu time");
436            return error!(ENOTSUP);
437        }
438        _ => {
439            track_stub!(TODO("https://fxbug.dev/349188105"), "timers w/ dynamic process clocks");
440            return error!(ENOTSUP);
441        }
442    };
443    let timer_wakeup = match clock_id as u32 {
444        CLOCK_BOOTTIME_ALARM | CLOCK_REALTIME_ALARM => {
445            security::check_task_capable(current_task, CAP_WAKE_ALARM)?;
446            TimerWakeup::Alarm
447        }
448        _ => TimerWakeup::Regular,
449    };
450
451    let id = &thread_group.timers.create(timeline, timer_wakeup, checked_signal_event)?;
452    current_task.write_object(timerid, &id)?;
453    Ok(())
454}
455
456pub fn sys_timer_delete(current_task: &CurrentTask, id: TimerId) -> Result<(), Errno> {
457    current_task.thread_group().timers.delete(current_task, id)
458}
459
460pub fn sys_timer_gettime(
461    current_task: &CurrentTask,
462    id: TimerId,
463    curr_value: ITimerSpecPtr,
464) -> Result<(), Errno> {
465    let timers = &current_task.thread_group().timers;
466    current_task.write_multi_arch_object(curr_value, timers.get_time(id)?)?;
467    Ok(())
468}
469
470pub fn sys_timer_getoverrun(current_task: &CurrentTask, id: TimerId) -> Result<i32, Errno> {
471    current_task.thread_group().timers.get_overrun(id)
472}
473
474pub fn sys_timer_settime(
475    current_task: &CurrentTask,
476    id: TimerId,
477    flags: i32,
478    user_new_value: ITimerSpecPtr,
479    user_old_value: ITimerSpecPtr,
480) -> Result<(), Errno> {
481    if user_new_value.is_null() {
482        return error!(EINVAL);
483    }
484    let new_value = current_task.read_multi_arch_object(user_new_value)?;
485
486    // Return early if the user passes an obviously invalid pointer. This avoids changing the timer
487    // settings for common pointer errors.
488    if !user_old_value.is_null() {
489        current_task.write_multi_arch_object(user_old_value, Default::default())?;
490    }
491
492    let old_value =
493        current_task.thread_group().timers.set_time(current_task, id, flags, new_value)?;
494
495    if !user_old_value.is_null() {
496        current_task.write_multi_arch_object(user_old_value, old_value)?;
497    }
498    Ok(())
499}
500
501pub fn sys_getitimer(
502    current_task: &CurrentTask,
503    which: u32,
504    user_curr_value: ITimerValPtr,
505) -> Result<(), Errno> {
506    let remaining = current_task.thread_group().get_itimer(which)?;
507    current_task.write_multi_arch_object(user_curr_value, remaining)?;
508    Ok(())
509}
510
511pub fn sys_setitimer(
512    current_task: &CurrentTask,
513    which: u32,
514    user_new_value: ITimerValPtr,
515    user_old_value: ITimerValPtr,
516) -> Result<(), Errno> {
517    let new_value = current_task.read_multi_arch_object(user_new_value)?;
518
519    let old_value = current_task.thread_group().set_itimer(current_task, which, new_value)?;
520
521    if !user_old_value.is_null() {
522        current_task.write_multi_arch_object(user_old_value, old_value)?;
523    }
524
525    Ok(())
526}
527
528pub fn sys_times(current_task: &CurrentTask, buf: UserRef<tms>) -> Result<i64, Errno> {
529    if !buf.is_null() {
530        let thread_group = current_task.thread_group();
531        let process_time_stats = thread_group.time_stats();
532        let children_time_stats = thread_group.read().children_time_stats;
533        let tms_result = tms {
534            tms_utime: duration_to_scheduler_clock(process_time_stats.user_time),
535            tms_stime: duration_to_scheduler_clock(process_time_stats.system_time),
536            tms_cutime: duration_to_scheduler_clock(children_time_stats.user_time),
537            tms_cstime: duration_to_scheduler_clock(children_time_stats.system_time),
538        };
539        current_task.write_object(buf, &tms_result)?;
540    }
541
542    Ok(duration_to_scheduler_clock(zx::MonotonicInstant::get() - zx::MonotonicInstant::ZERO))
543}
544
545// Syscalls for arch32 usage
546#[cfg(target_arch = "aarch64")]
547mod arch32 {
548    use crate::task::CurrentTask;
549    use crate::time::TimerId;
550    use starnix_uapi::errors::Errno;
551    use starnix_uapi::uapi;
552    use starnix_uapi::user_address::UserRef;
553    use static_assertions::const_assert;
554
555    pub fn sys_arch32_clock_gettime64(
556        current_task: &CurrentTask,
557        which_clock: i32,
558        tp_addr: UserRef<uapi::timespec>,
559    ) -> Result<(), Errno> {
560        const_assert!(
561            std::mem::size_of::<uapi::timespec>()
562                == std::mem::size_of::<uapi::arch32::__kernel_timespec>()
563        );
564        super::sys_clock_gettime(current_task, which_clock, tp_addr.into())
565    }
566
567    pub fn sys_arch32_timer_gettime64(
568        current_task: &CurrentTask,
569        id: TimerId,
570        curr_value: UserRef<uapi::itimerspec>,
571    ) -> Result<(), Errno> {
572        const_assert!(
573            std::mem::size_of::<uapi::itimerspec>()
574                == std::mem::size_of::<uapi::arch32::__kernel_itimerspec>()
575        );
576        super::sys_timer_gettime(current_task, id, curr_value.into())
577    }
578
579    pub use super::{
580        sys_clock_getres as sys_arch32_clock_getres, sys_clock_gettime as sys_arch32_clock_gettime,
581        sys_getitimer as sys_arch32_getitimer, sys_gettimeofday as sys_arch32_gettimeofday,
582        sys_nanosleep as sys_arch32_nanosleep, sys_setitimer as sys_arch32_setitimer,
583        sys_settimeofday as sys_arch32_settimeofday, sys_timer_create as sys_arch32_timer_create,
584        sys_timer_delete as sys_arch32_timer_delete,
585        sys_timer_getoverrun as sys_arch32_timer_getoverrun,
586        sys_timer_gettime as sys_arch32_timer_gettime,
587        sys_timer_settime as sys_arch32_timer_settime,
588    };
589}
590
591#[cfg(target_arch = "aarch64")]
592pub use arch32::*;
593
594#[cfg(test)]
595mod test {
596    use super::*;
597    use crate::mm::PAGE_SIZE;
598    use crate::testing::{map_memory, spawn_kernel_and_run};
599    use crate::time::utc::UtcClockOverrideGuard;
600    use fuchsia_runtime::{UtcDuration, UtcTimeline};
601    use starnix_uapi::signals;
602    use starnix_uapi::user_address::UserAddress;
603    use std::sync::Arc;
604    use test_util::{assert_geq, assert_leq};
605    use zx::{BootTimeline, Clock, ClockUpdate};
606
607    // TODO(https://fxbug.dev/356911500): Use types below from fuchsia_runtime
608    type UtcClock = Clock<BootTimeline, UtcTimeline>;
609    type UtcClockUpdate = ClockUpdate<BootTimeline, UtcTimeline>;
610
611    #[::fuchsia::test]
612    async fn test_nanosleep_without_remainder() {
613        spawn_kernel_and_run(async |current_task| {
614            let thread = std::thread::spawn({
615                let task = current_task.weak_task();
616                move || {
617                    let task = task.upgrade().expect("task must be alive");
618                    // Wait until the task is in nanosleep, and interrupt it.
619                    while !task.read().is_blocked() {
620                        std::thread::sleep(std::time::Duration::from_millis(10));
621                    }
622                    task.interrupt();
623                }
624            });
625
626            let duration = timespec_from_duration(zx::MonotonicDuration::from_seconds(60));
627            let address = map_memory(
628                &current_task,
629                UserAddress::default(),
630                std::mem::size_of::<timespec>() as u64,
631            );
632            let address_ptr = UserRef::<timespec>::from(address);
633            current_task.write_object(address_ptr, &duration).expect("write_object");
634
635            // nanosleep will be interrupted by the current thread and should not fail with EFAULT
636            // because the remainder pointer is null.
637            assert_eq!(
638                sys_nanosleep(current_task, address_ptr.into(), UserRef::default().into()),
639                error!(ERESTART_RESTARTBLOCK)
640            );
641
642            thread.join().expect("join");
643        })
644        .await;
645    }
646
647    #[::fuchsia::test]
648    async fn test_clock_nanosleep_relative_to_slow_clock() {
649        spawn_kernel_and_run(async |current_task| {
650            let test_clock = UtcClock::create(zx::ClockOpts::AUTO_START, None).unwrap();
651            let _test_clock_guard = UtcClockOverrideGuard::new(
652                test_clock.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
653            );
654
655            // Slow |test_clock| down and verify that we sleep long enough.
656            let slow_clock_update = UtcClockUpdate::builder().rate_adjust(-1000).build();
657            test_clock.update(slow_clock_update).unwrap();
658
659            let before = test_clock.read().unwrap();
660
661            let tv = timespec { tv_sec: 1, tv_nsec: 0 };
662
663            let remaining = UserRef::new(UserAddress::default());
664
665            super::clock_nanosleep_relative_to_utc(current_task, tv, false, remaining.into())
666                .unwrap();
667            let elapsed = test_clock.read().unwrap() - before;
668            assert!(elapsed >= UtcDuration::from_seconds(1));
669        })
670        .await;
671    }
672
673    #[::fuchsia::test]
674    async fn test_clock_nanosleep_interrupted_relative_to_fast_utc_clock() {
675        spawn_kernel_and_run(async |current_task| {
676            let test_clock = UtcClock::create(zx::ClockOpts::AUTO_START, None).unwrap();
677            let _test_clock_guard = UtcClockOverrideGuard::new(
678                test_clock.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
679            );
680
681            // Speed |test_clock| up.
682            let slow_clock_update = UtcClockUpdate::builder().rate_adjust(1000).build();
683            test_clock.update(slow_clock_update).unwrap();
684
685            let before = test_clock.read().unwrap();
686
687            let tv = timespec { tv_sec: 2, tv_nsec: 0 };
688
689            let remaining = {
690                let addr = map_memory(&current_task, UserAddress::default(), *PAGE_SIZE);
691                UserRef::new(addr)
692            };
693
694            // Interrupt the sleep roughly halfway through. The actual interruption might be before the
695            // sleep starts, during the sleep, or after.
696            let interruption_target =
697                zx::MonotonicInstant::get() + zx::MonotonicDuration::from_seconds(1);
698
699            let thread_group = Arc::downgrade(current_task.thread_group());
700            let thread_join_handle = std::thread::Builder::new()
701                .name("clock_nanosleep_interruptor".to_string())
702                .spawn(move || {
703                    std::thread::sleep(std::time::Duration::from_nanos(
704                        (interruption_target - zx::MonotonicInstant::get()).into_nanos() as u64,
705                    ));
706                    if let Some(thread_group) = thread_group.upgrade() {
707                        let signal = signals::SIGALRM;
708                        thread_group
709                            .write()
710                            .send_signal(crate::signals::SignalInfo::kernel(signal));
711                    }
712                })
713                .unwrap();
714
715            let result =
716                super::clock_nanosleep_relative_to_utc(current_task, tv, false, remaining.into());
717
718            // We can't know deterministically if our interrupter thread will be able to interrupt our sleep.
719            // If it did, result should be ERESTART_RESTARTBLOCK and |remaining| will be populated.
720            // If it didn't, the result will be OK and |remaining| will not be touched.
721            let mut remaining_written = Default::default();
722            if result.is_err() {
723                assert_eq!(result, error!(ERESTART_RESTARTBLOCK));
724                remaining_written = current_task.read_object(remaining).unwrap();
725            }
726            assert_leq!(
727                duration_from_timespec::<zx::MonotonicTimeline>(remaining_written).unwrap(),
728                zx::MonotonicDuration::from_seconds(2)
729            );
730            let elapsed = test_clock.read().unwrap() - before;
731            thread_join_handle.join().unwrap();
732
733            assert_geq!(
734                elapsed + duration_from_timespec(remaining_written).unwrap(),
735                UtcDuration::from_seconds(2)
736            );
737        })
738        .await;
739    }
740}