1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
// SPDX-License-Identifier: GPL-2.0
//! Delay functions for operations like sleeping.
//!
//! C header: [`include/linux/delay.h`](../../../../include/linux/delay.h)
use crate::bindings;
use core::{cmp::min, time::Duration};
const MILLIS_PER_SEC: u64 = 1_000;
fn coarse_sleep_conversion(duration: Duration) -> core::ffi::c_uint {
let milli_as_nanos = Duration::MILLISECOND.subsec_nanos();
// Rounds the nanosecond component of `duration` up to the nearest millisecond.
let nanos_as_millis = duration.subsec_nanos().wrapping_add(milli_as_nanos - 1) / milli_as_nanos;
// Saturates the second component of `duration` to `c_uint::MAX`.
let seconds_as_millis = min(
duration.as_secs().saturating_mul(MILLIS_PER_SEC),
u64::from(core::ffi::c_uint::MAX),
) as core::ffi::c_uint;
seconds_as_millis.saturating_add(nanos_as_millis)
}
/// Sleeps safely even with waitqueue interruptions.
///
/// This function forwards the call to the C side `msleep` function. As a result,
/// `duration` will be rounded up to the nearest millisecond if granularity less
/// than a millisecond is provided. Any [`Duration`] that exceeds
/// [`c_uint::MAX`][core::ffi::c_uint::MAX] in milliseconds is saturated.
///
/// # Examples
///
// Keep these in sync with `test_coarse_sleep_examples`.
/// ```
/// # use core::time::Duration;
/// # use kernel::delay::coarse_sleep;
/// coarse_sleep(Duration::ZERO); // Equivalent to `msleep(0)`.
/// coarse_sleep(Duration::from_nanos(1)); // Equivalent to `msleep(1)`.
///
/// coarse_sleep(Duration::from_nanos(1_000_000)); // Equivalent to `msleep(1)`.
/// coarse_sleep(Duration::from_nanos(1_000_001)); // Equivalent to `msleep(2)`.
/// coarse_sleep(Duration::from_nanos(1_999_999)); // Equivalent to `msleep(2)`.
///
/// coarse_sleep(Duration::from_millis(1)); // Equivalent to `msleep(1)`.
/// coarse_sleep(Duration::from_millis(2)); // Equivalent to `msleep(2)`.
///
/// coarse_sleep(Duration::from_secs(1)); // Equivalent to `msleep(1000)`.
/// coarse_sleep(Duration::new(1, 1)); // Equivalent to `msleep(1001)`.
/// coarse_sleep(Duration::new(1, 2)); // Equivalent to `msleep(1001)`.
/// ```
pub fn coarse_sleep(duration: Duration) {
// SAFETY: `msleep` is safe for all values of its argument.
unsafe { bindings::msleep(coarse_sleep_conversion(duration)) }
}
#[cfg(test)]
mod tests {
use super::{coarse_sleep_conversion, MILLIS_PER_SEC};
use core::time::Duration;
#[test]
fn test_coarse_sleep_examples() {
// Keep these in sync with `coarse_sleep`'s `# Examples` section.
assert_eq!(coarse_sleep_conversion(Duration::ZERO), 0);
assert_eq!(coarse_sleep_conversion(Duration::from_nanos(1)), 1);
assert_eq!(coarse_sleep_conversion(Duration::from_nanos(1_000_000)), 1);
assert_eq!(coarse_sleep_conversion(Duration::from_nanos(1_000_001)), 2);
assert_eq!(coarse_sleep_conversion(Duration::from_nanos(1_999_999)), 2);
assert_eq!(coarse_sleep_conversion(Duration::from_millis(1)), 1);
assert_eq!(coarse_sleep_conversion(Duration::from_millis(2)), 2);
assert_eq!(coarse_sleep_conversion(Duration::from_secs(1)), 1000);
assert_eq!(coarse_sleep_conversion(Duration::new(1, 1)), 1001);
assert_eq!(coarse_sleep_conversion(Duration::new(1, 2)), 1001);
}
#[test]
fn test_coarse_sleep_saturation() {
assert!(
coarse_sleep_conversion(Duration::new(
core::ffi::c_uint::MAX as u64 / MILLIS_PER_SEC,
0
)) < core::ffi::c_uint::MAX
);
assert_eq!(
coarse_sleep_conversion(Duration::new(
core::ffi::c_uint::MAX as u64 / MILLIS_PER_SEC,
999_999_999
)),
core::ffi::c_uint::MAX
);
assert_eq!(
coarse_sleep_conversion(Duration::MAX),
core::ffi::c_uint::MAX
);
}
}