diff --git a/v6/modules/steady_clock.cppm b/v6/modules/steady_clock.cppm index 7b8973d..cd47613 100644 --- a/v6/modules/steady_clock.cppm +++ b/v6/modules/steady_clock.cppm @@ -67,4 +67,25 @@ export hal::u64 future_deadline(hal::steady_clock& p_steady_clock, return future_timestamp; } + +/** + * @ingroup SteadyClock + * @brief Busy-wait for a duration of time using a steady clock + * + * Spins on `p_steady_clock.uptime()` without sleeping, so it works before a + * waiter is installed. Prefer `hal::sleep_for()` once one is, so the CPU can + * idle while it waits. + * + * @param p_steady_clock - steady clock to measure the delay with + * @param p_duration - the amount of time to delay for. A zero or negative + * duration delays for one tick of p_steady_clock. + */ +export void delay(hal::steady_clock& p_steady_clock, + hal::time_duration p_duration) +{ + auto const deadline = future_deadline(p_steady_clock, p_duration); + while (p_steady_clock.uptime() < deadline) { + continue; + } +} } // namespace hal::inline v6 diff --git a/v6/tests/steady_clock.test.cpp b/v6/tests/steady_clock.test.cpp index 6a40623..85a8303 100644 --- a/v6/tests/steady_clock.test.cpp +++ b/v6/tests/steady_clock.test.cpp @@ -62,9 +62,47 @@ void future_deadline_test() }; } +void delay_test() +{ + using namespace boost::ut; + + "hal::delay(hal::steady_clock, duration) waits until the deadline"_test = + []() { + // Setup + using namespace std::chrono_literals; + dummy_steady_clock test_steady_clock; + dummy_steady_clock reference_clock; + // Both clocks start at the same uptime, so this is the deadline delay() + // computes. + auto const deadline = hal::future_deadline(reference_clock, 1us); + + // Exercise + hal::delay(test_steady_clock, 1us); + + // Verify + // The last uptime() read returned the deadline, then incremented. + expect(that % test_steady_clock.m_uptime == deadline + 1); + }; + + "hal::delay(hal::steady_clock, duration) waits one tick for zero"_test = + []() { + // Setup + using namespace std::chrono_literals; + dummy_steady_clock test_steady_clock; + test_steady_clock.m_uptime = 0; + + // Exercise + hal::delay(test_steady_clock, 0ns); + + // Verify + // future_deadline() reads 0 and returns 1; then uptime() reads 1. + expect(that % test_steady_clock.m_uptime == 2); + }; +} } // namespace int main() { future_deadline_test(); + delay_test(); }