summaryrefslogtreecommitdiff
path: root/AK
diff options
context:
space:
mode:
authorkleines Filmröllchen <filmroellchen@serenityos.org>2023-03-13 22:42:09 +0100
committerJelle Raaijmakers <jelle@gmta.nl>2023-05-24 23:18:07 +0200
commitb2e7b8cdffa2297b335698677f5c0434dbf92e75 (patch)
treebb0a0d752d385c7ee0d2f1ce0c16a0ea2af1f0ab /AK
parent69e27169c40eda66795db8b3dfbc8a797ef9989d (diff)
downloadserenity-b2e7b8cdffa2297b335698677f5c0434dbf92e75.zip
AK: Introduce MonotonicTime
This class takes on the duties of CLOCK_MONOTONIC, a time without a defined reference point that always increases. This informs some important design decisions about the class API: MonotonicTime cannot be constructed from external time data, except as a computation based on other monotonic time, or the current monotonic time. Importantly, there is no default constructor, since the reference point of monotonic time is unspecified and therefore without meaning as a default. The current use of monotonic time (via Duration) includes some potential problems that may be caught when we move most to all code to MonotonicTime in the next commit. The API restrictions have one important relaxation: Kernel::TimeManagement is allowed to exchange raw time data within MonotonicTime freely. This is required for the clock-agnostic time accessors for timeouts and syscalls, as well as creating monotonic time data from hardware in the first place.
Diffstat (limited to 'AK')
-rw-r--r--AK/Time.cpp10
-rw-r--r--AK/Time.h69
2 files changed, 79 insertions, 0 deletions
diff --git a/AK/Time.cpp b/AK/Time.cpp
index 700cc02b97..5fb62691b6 100644
--- a/AK/Time.cpp
+++ b/AK/Time.cpp
@@ -227,6 +227,16 @@ Duration Duration::now_monotonic_coarse()
return now_time_from_clock(CLOCK_MONOTONIC_COARSE);
}
+MonotonicTime MonotonicTime::now()
+{
+ return MonotonicTime { now_time_from_clock(CLOCK_MONOTONIC) };
+}
+
+MonotonicTime MonotonicTime::now_coarse()
+{
+ return MonotonicTime { now_time_from_clock(CLOCK_MONOTONIC_COARSE) };
+}
+
UnixDateTime UnixDateTime::now()
{
return UnixDateTime { now_time_from_clock(CLOCK_REALTIME) };
diff --git a/AK/Time.h b/AK/Time.h
index 29c5c0570f..87709fe052 100644
--- a/AK/Time.h
+++ b/AK/Time.h
@@ -8,6 +8,7 @@
#include <AK/Array.h>
#include <AK/Assertions.h>
+#include <AK/Badge.h>
#include <AK/Checked.h>
#include <AK/Platform.h>
#include <AK/Types.h>
@@ -15,6 +16,12 @@
#if defined(AK_OS_SERENITY) && defined(KERNEL)
# include <Kernel/API/POSIX/sys/time.h>
# include <Kernel/API/POSIX/time.h>
+
+// We need a Badge<TimeManagement> for some MonotonicTime operations.
+namespace Kernel {
+class TimeManagement;
+}
+
#else
# include <sys/time.h>
# include <time.h>
@@ -456,6 +463,67 @@ private:
}
};
+// Monotonic time represents time returned from the CLOCK_MONOTONIC clock, which has an arbitrary fixed reference point.
+class MonotonicTime : private Detail::UnawareTime {
+public:
+ // Monotonic time does not have a defined reference point.
+ // A MonotonicTime at the reference point is therefore meaningless.
+ MonotonicTime() = delete;
+ constexpr MonotonicTime(MonotonicTime const&) = default;
+ constexpr MonotonicTime(MonotonicTime&&) = default;
+ constexpr MonotonicTime& operator=(MonotonicTime const&) = default;
+ constexpr MonotonicTime& operator=(MonotonicTime&&) = default;
+
+#ifndef KERNEL
+ [[nodiscard]] static MonotonicTime now();
+ [[nodiscard]] static MonotonicTime now_coarse();
+#endif
+
+ // clang-format off
+ // Clang-format likes to expand this function for some reason.
+ [[nodiscard]] i64 seconds() const { return m_offset.to_seconds(); }
+ // clang-format on
+ [[nodiscard]] i64 milliseconds() const { return m_offset.to_milliseconds(); }
+ [[nodiscard]] i64 nanoseconds() const { return m_offset.to_nanoseconds(); }
+ // Never returns a point in the future, since fractional seconds are cut off.
+ [[nodiscard]] i64 truncated_seconds() const { return m_offset.to_truncated_seconds(); }
+ [[nodiscard]] i64 nanoseconds_within_second() const { return to_timespec().tv_nsec; }
+
+ // clang-format off
+ constexpr bool operator==(MonotonicTime const& other) const { return this->m_offset == other.m_offset; }
+ // clang-format on
+ constexpr int operator<=>(MonotonicTime const& other) const { return this->m_offset <=> other.m_offset; }
+
+ constexpr MonotonicTime operator+(Duration const& other) const { return MonotonicTime { m_offset + other }; }
+ constexpr MonotonicTime& operator+=(Duration const& other)
+ {
+ this->m_offset = this->m_offset + other;
+ return *this;
+ }
+ constexpr MonotonicTime operator-(Duration const& other) const { return MonotonicTime { m_offset - other }; }
+ constexpr Duration operator-(MonotonicTime const& other) const { return m_offset - other.m_offset; }
+
+#ifdef KERNEL
+ // Required in the Kernel in order to create monotonic time information from hardware timers.
+ [[nodiscard]] static MonotonicTime from_hardware_time(Badge<Kernel::TimeManagement>, time_t seconds, long nanoseconds)
+ {
+ return MonotonicTime { Duration::from_timespec({ seconds, nanoseconds }) };
+ }
+
+ // "Start" is whenever the hardware timers started counting (e.g. for HPET it's most certainly boot).
+ [[nodiscard]] Duration time_since_start(Badge<Kernel::TimeManagement>)
+ {
+ return m_offset;
+ }
+#endif
+
+private:
+ constexpr explicit MonotonicTime(Duration offset)
+ : Detail::UnawareTime(offset)
+ {
+ }
+};
+
template<typename TimevalType>
inline void timeval_sub(TimevalType const& a, TimevalType const& b, TimevalType& result)
{
@@ -545,6 +613,7 @@ using AK::days_in_year;
using AK::days_since_epoch;
using AK::Duration;
using AK::is_leap_year;
+using AK::MonotonicTime;
using AK::seconds_since_epoch_to_year;
using AK::timespec_add;
using AK::timespec_add_timeval;