Переглянути джерело

Kernel: Add CLOCK_REALTIME support to the TimerQueue

This allows us to use blocking timeouts with either monotonic or
real time for all blockers. Which means that clock_nanosleep()
now also supports CLOCK_REALTIME.

Also, switch alarm() to use CLOCK_REALTIME as per specification.
Tom 4 роки тому
батько
коміт
12cf6f8650

+ 2 - 2
Kernel/Syscalls/alarm.cpp

@@ -46,9 +46,9 @@ unsigned Process::sys$alarm(unsigned seconds)
     }
 
     if (seconds > 0) {
-        auto deadline = TimeManagement::the().monotonic_time(); // TODO: should be using CLOCK_REALTIME
+        auto deadline = TimeManagement::the().current_time(CLOCK_REALTIME).value();
         timespec_add(deadline, { seconds, 0 }, deadline);
-        m_alarm_timer = TimerQueue::the().add_timer_without_id(deadline, [this]() {
+        m_alarm_timer = TimerQueue::the().add_timer_without_id(CLOCK_REALTIME, deadline, [this]() {
             (void)send_signal(SIGALRM, nullptr);
         });
     }

+ 8 - 16
Kernel/Syscalls/clock.cpp

@@ -34,20 +34,11 @@ int Process::sys$clock_gettime(clockid_t clock_id, Userspace<timespec*> user_ts)
 {
     REQUIRE_PROMISE(stdio);
 
-    timespec ts = {};
+    auto ts = TimeManagement::the().current_time(clock_id);
+    if (ts.is_error())
+        return ts.error();
 
-    switch (clock_id) {
-    case CLOCK_MONOTONIC:
-        ts = TimeManagement::the().monotonic_time();
-        break;
-    case CLOCK_REALTIME:
-        ts = TimeManagement::the().epoch_time();
-        break;
-    default:
-        return -EINVAL;
-    }
-
-    if (!copy_to_user(user_ts, &ts))
+    if (!copy_to_user(user_ts, &ts.value()))
         return -EFAULT;
     return 0;
 }
@@ -88,13 +79,14 @@ int Process::sys$clock_nanosleep(Userspace<const Syscall::SC_clock_nanosleep_par
     bool is_absolute = params.flags & TIMER_ABSTIME;
 
     switch (params.clock_id) {
-    case CLOCK_MONOTONIC: {
+    case CLOCK_MONOTONIC:
+    case CLOCK_REALTIME: {
         bool was_interrupted;
         if (is_absolute) {
-            was_interrupted = Thread::current()->sleep_until(requested_sleep).was_interrupted();
+            was_interrupted = Thread::current()->sleep_until(params.clock_id, requested_sleep).was_interrupted();
         } else {
             timespec remaining_sleep;
-            was_interrupted = Thread::current()->sleep(requested_sleep, &remaining_sleep).was_interrupted();
+            was_interrupted = Thread::current()->sleep(params.clock_id, requested_sleep, &remaining_sleep).was_interrupted();
             if (was_interrupted && params.remaining_sleep && !copy_to_user(params.remaining_sleep, &remaining_sleep))
                 return -EFAULT;
         }

+ 5 - 5
Kernel/Thread.cpp

@@ -271,16 +271,16 @@ void Thread::relock_process(bool did_unlock)
     Processor::current().restore_critical(prev_crit, prev_flags);
 }
 
-auto Thread::sleep(const timespec& duration, timespec* remaining_time) -> BlockResult
+auto Thread::sleep(clockid_t clock_id, const timespec& duration, timespec* remaining_time) -> BlockResult
 {
     ASSERT(state() == Thread::Running);
-    return Thread::current()->block<Thread::SleepBlocker>(nullptr, Thread::BlockTimeout(false, &duration), remaining_time);
+    return Thread::current()->block<Thread::SleepBlocker>(nullptr, Thread::BlockTimeout(false, &duration, nullptr, clock_id), remaining_time);
 }
 
-auto Thread::sleep_until(const timespec& deadline) -> BlockResult
+auto Thread::sleep_until(clockid_t clock_id, const timespec& deadline) -> BlockResult
 {
     ASSERT(state() == Thread::Running);
-    return Thread::current()->block<Thread::SleepBlocker>(nullptr, Thread::BlockTimeout(true, &deadline));
+    return Thread::current()->block<Thread::SleepBlocker>(nullptr, Thread::BlockTimeout(true, &deadline, nullptr, clock_id));
 }
 
 const char* Thread::state_string() const
@@ -1081,7 +1081,7 @@ Thread::BlockResult Thread::wait_on(WaitQueue& queue, const char* reason, const
         {
             ScopedSpinLock sched_lock(g_scheduler_lock);
             if (!timeout.is_infinite()) {
-                timer = TimerQueue::the().add_timer_without_id(timeout.absolute_time(), [&]() {
+                timer = TimerQueue::the().add_timer_without_id(timeout.clock_id(), timeout.absolute_time(), [&]() {
                     // NOTE: this may execute on the same or any other processor!
                     ScopedSpinLock lock(g_scheduler_lock);
                     if (!block_finished) {

+ 21 - 9
Kernel/Thread.h

@@ -211,28 +211,30 @@ public:
             : m_infinite(true)
         {
         }
-        explicit BlockTimeout(bool is_absolute, const timeval* time, const timespec* start_time = nullptr)
-            : m_infinite(!time)
+        explicit BlockTimeout(bool is_absolute, const timeval* time, const timespec* start_time = nullptr, clockid_t clock_id = CLOCK_MONOTONIC)
+            : m_clock_id(clock_id)
+            , m_infinite(!time)
         {
             if (!m_infinite) {
                 if (time->tv_sec > 0 || time->tv_usec > 0) {
                     timeval_to_timespec(*time, m_time);
                     m_should_block = true;
                 }
-                m_start_time = start_time ? *start_time : TimeManagement::the().monotonic_time();
+                m_start_time = start_time ? *start_time : TimeManagement::the().current_time(clock_id).value();
                 if (!is_absolute)
                     timespec_add(m_time, m_start_time, m_time);
             }
         }
-        explicit BlockTimeout(bool is_absolute, const timespec* time, const timespec* start_time = nullptr)
-            : m_infinite(!time)
+        explicit BlockTimeout(bool is_absolute, const timespec* time, const timespec* start_time = nullptr, clockid_t clock_id = CLOCK_MONOTONIC)
+            : m_clock_id(clock_id)
+            , m_infinite(!time)
         {
             if (!m_infinite) {
                 if (time->tv_sec > 0 || time->tv_nsec > 0) {
                     m_time = *time;
                     m_should_block = true;
                 }
-                m_start_time = start_time ? *start_time : TimeManagement::the().monotonic_time();
+                m_start_time = start_time ? *start_time : TimeManagement::the().current_time(clock_id).value();
                 if (!is_absolute)
                     timespec_add(m_time, m_start_time, m_time);
             }
@@ -240,12 +242,14 @@ public:
 
         const timespec& absolute_time() const { return m_time; }
         const timespec* start_time() const { return !m_infinite ? &m_start_time : nullptr; }
+        clockid_t clock_id() const { return m_clock_id; }
         bool is_infinite() const { return m_infinite; }
         bool should_block() const { return m_infinite || m_should_block; };
 
     private:
         timespec m_time { 0, 0 };
         timespec m_start_time { 0, 0 };
+        clockid_t m_clock_id { CLOCK_MONOTONIC };
         bool m_infinite { false };
         bool m_should_block { false };
     };
@@ -733,7 +737,7 @@ public:
 
             auto& block_timeout = t.override_timeout(timeout);
             if (!block_timeout.is_infinite()) {
-                m_blocker_timeout = timer = TimerQueue::the().add_timer_without_id(block_timeout.absolute_time(), [&]() {
+                m_blocker_timeout = timer = TimerQueue::the().add_timer_without_id(block_timeout.clock_id(), block_timeout.absolute_time(), [&]() {
                     // NOTE: this may execute on the same or any other processor!
                     ScopedSpinLock scheduler_lock(g_scheduler_lock);
                     ScopedSpinLock lock(m_lock);
@@ -816,8 +820,16 @@ public:
     void unblock_from_blocker(Blocker&);
     void unblock(u8 signal = 0);
 
-    BlockResult sleep(const timespec&, timespec* = nullptr);
-    BlockResult sleep_until(const timespec&);
+    BlockResult sleep(clockid_t, const timespec&, timespec* = nullptr);
+    BlockResult sleep(const timespec& duration, timespec* remaining_time = nullptr)
+    {
+        return sleep(CLOCK_MONOTONIC, duration, remaining_time);
+    }
+    BlockResult sleep_until(clockid_t, const timespec&);
+    BlockResult sleep_until(const timespec& duration)
+    {
+        return sleep_until(CLOCK_MONOTONIC, duration);
+    }
 
     // Tell this thread to unblock if needed,
     // gracefully unwind the stack and die.

+ 3 - 3
Kernel/ThreadBlockers.cpp

@@ -197,7 +197,7 @@ auto Thread::WriteBlocker::override_timeout(const BlockTimeout& timeout) -> cons
     if (description.is_socket()) {
         auto& socket = *description.socket();
         if (socket.has_send_timeout()) {
-            m_timeout = BlockTimeout(false, &socket.send_timeout(), timeout.start_time());
+            m_timeout = BlockTimeout(false, &socket.send_timeout(), timeout.start_time(), timeout.clock_id());
             if (timeout.is_infinite() || (!m_timeout.is_infinite() && m_timeout.absolute_time() < timeout.absolute_time()))
                 return m_timeout;
         }
@@ -216,7 +216,7 @@ auto Thread::ReadBlocker::override_timeout(const BlockTimeout& timeout) -> const
     if (description.is_socket()) {
         auto& socket = *description.socket();
         if (socket.has_receive_timeout()) {
-            m_timeout = BlockTimeout(false, &socket.receive_timeout(), timeout.start_time());
+            m_timeout = BlockTimeout(false, &socket.receive_timeout(), timeout.start_time(), timeout.clock_id());
             if (timeout.is_infinite() || (!m_timeout.is_infinite() && m_timeout.absolute_time() < timeout.absolute_time()))
                 return m_timeout;
         }
@@ -256,7 +256,7 @@ void Thread::SleepBlocker::calculate_remaining()
 {
     if (!m_remaining)
         return;
-    auto time_now = TimeManagement::the().monotonic_time();
+    auto time_now = TimeManagement::the().current_time(m_deadline.clock_id()).value();
     if (time_now < m_deadline.absolute_time())
         timespec_sub(m_deadline.absolute_time(), time_now, *m_remaining);
     else

+ 12 - 0
Kernel/Time/TimeManagement.cpp

@@ -52,6 +52,18 @@ TimeManagement& TimeManagement::the()
     return *s_the;
 }
 
+KResultOr<timespec> TimeManagement::current_time(clockid_t clock_id) const
+{
+    switch (clock_id) {
+    case CLOCK_MONOTONIC:
+        return monotonic_time();
+    case CLOCK_REALTIME:
+        return epoch_time();
+    default:
+        return KResult(EINVAL);
+    }
+}
+
 bool TimeManagement::is_system_timer(const HardwareTimerBase& timer) const
 {
     return &timer == m_system_timer.ptr();

+ 2 - 0
Kernel/Time/TimeManagement.h

@@ -29,6 +29,7 @@
 #include <AK/NonnullRefPtrVector.h>
 #include <AK/RefPtr.h>
 #include <AK/Types.h>
+#include <Kernel/KResult.h>
 #include <Kernel/UnixTypes.h>
 
 namespace Kernel {
@@ -49,6 +50,7 @@ public:
     static timespec ticks_to_time(u64 ticks, time_t ticks_per_second);
     static u64 time_to_ticks(const timespec& tspec, time_t ticks_per_second);
 
+    KResultOr<timespec> current_time(clockid_t clock_id) const;
     timespec monotonic_time() const;
     timespec epoch_time() const;
     void set_epoch_time(timespec);

+ 100 - 52
Kernel/TimerQueue.cpp

@@ -42,7 +42,12 @@ timespec Timer::remaining() const
 {
     if (m_remaining == 0)
         return {};
-    return TimerQueue::the().ticks_to_time(m_remaining);
+    return TimerQueue::the().ticks_to_time(m_clock_id, m_remaining);
+}
+
+u64 Timer::now() const
+{
+    return TimerQueue::the().time_to_ticks(m_clock_id, TimeManagement::the().current_time(m_clock_id).value());
 }
 
 TimerQueue& TimerQueue::the()
@@ -55,9 +60,9 @@ TimerQueue::TimerQueue()
     m_ticks_per_second = TimeManagement::the().ticks_per_second();
 }
 
-RefPtr<Timer> TimerQueue::add_timer_without_id(const timespec& deadline, Function<void()>&& callback)
+RefPtr<Timer> TimerQueue::add_timer_without_id(clockid_t clock_id, const timespec& deadline, Function<void()>&& callback)
 {
-    if (deadline <= TimeManagement::the().monotonic_time())
+    if (deadline <= TimeManagement::the().current_time(clock_id).value())
         return {};
 
     // Because timer handlers can execute on any processor and there is
@@ -65,7 +70,7 @@ RefPtr<Timer> TimerQueue::add_timer_without_id(const timespec& deadline, Functio
     // *must* be a RefPtr<Timer>. Otherwise calling cancel_timer() could
     // inadvertently cancel another timer that has been created between
     // returning from the timer handler and a call to cancel_timer().
-    auto timer = adopt(*new Timer(time_to_ticks(deadline), move(callback)));
+    auto timer = adopt(*new Timer(clock_id, time_to_ticks(clock_id, deadline), move(callback)));
 
     ScopedSpinLock lock(g_timerqueue_lock);
     timer->m_id = 0; // Don't generate a timer id
@@ -86,16 +91,17 @@ TimerId TimerQueue::add_timer(NonnullRefPtr<Timer>&& timer)
 void TimerQueue::add_timer_locked(NonnullRefPtr<Timer> timer)
 {
     u64 timer_expiration = timer->m_expires;
-    ASSERT(timer_expiration >= time_to_ticks(TimeManagement::the().monotonic_time()));
+    ASSERT(timer_expiration >= time_to_ticks(timer->m_clock_id, TimeManagement::the().current_time(timer->m_clock_id).value()));
 
     ASSERT(!timer->is_queued());
 
-    if (m_timer_queue.is_empty()) {
-        m_timer_queue.append(&timer.leak_ref());
-        m_next_timer_due = timer_expiration;
+    auto& queue = queue_for_timer(*timer);
+    if (queue.list.is_empty()) {
+        queue.list.append(&timer.leak_ref());
+        queue.next_timer_due = timer_expiration;
     } else {
         Timer* following_timer = nullptr;
-        m_timer_queue.for_each([&](Timer& t) {
+        queue.list.for_each([&](Timer& t) {
             if (t.m_expires > timer_expiration) {
                 following_timer = &t;
                 return IterationDecision::Break;
@@ -103,51 +109,85 @@ void TimerQueue::add_timer_locked(NonnullRefPtr<Timer> timer)
             return IterationDecision::Continue;
         });
         if (following_timer) {
-            bool next_timer_needs_update = m_timer_queue.head() == following_timer;
-            m_timer_queue.insert_before(following_timer, &timer.leak_ref());
+            bool next_timer_needs_update = queue.list.head() == following_timer;
+            queue.list.insert_before(following_timer, &timer.leak_ref());
             if (next_timer_needs_update)
-                m_next_timer_due = timer_expiration;
+                queue.next_timer_due = timer_expiration;
         } else {
-            m_timer_queue.append(&timer.leak_ref());
+            queue.list.append(&timer.leak_ref());
         }
     }
 }
 
-TimerId TimerQueue::add_timer(timeval& deadline, Function<void()>&& callback)
+TimerId TimerQueue::add_timer(clockid_t clock_id, timeval& deadline, Function<void()>&& callback)
 {
-    auto expires = TimeManagement::the().monotonic_time();
+    auto expires = TimeManagement::the().current_time(clock_id).value();
     timespec_add_timeval(expires, deadline, expires);
-    return add_timer(adopt(*new Timer(time_to_ticks(expires), move(callback))));
+    return add_timer(adopt(*new Timer(clock_id, time_to_ticks(clock_id, expires), move(callback))));
 }
 
-timespec TimerQueue::ticks_to_time(u64 ticks) const
+timespec TimerQueue::ticks_to_time(clockid_t clock_id, u64 ticks) const
 {
     timespec tspec;
-    tspec.tv_sec = ticks / m_ticks_per_second;
-    tspec.tv_nsec = (ticks % m_ticks_per_second) * (1'000'000'000 / m_ticks_per_second);
+    switch (clock_id) {
+    case CLOCK_MONOTONIC:
+        tspec.tv_sec = ticks / m_ticks_per_second;
+        tspec.tv_nsec = (ticks % m_ticks_per_second) * (1'000'000'000 / m_ticks_per_second);
+        break;
+    case CLOCK_REALTIME:
+        tspec.tv_sec = ticks / 1'000'000'000;
+        tspec.tv_nsec = ticks % 1'000'000'000;
+        break;
+    default:
+        ASSERT_NOT_REACHED();
+    }
     ASSERT(tspec.tv_nsec <= 1'000'000'000);
     return tspec;
 }
 
-u64 TimerQueue::time_to_ticks(const timespec& tspec) const
+u64 TimerQueue::time_to_ticks(clockid_t clock_id, const timespec& tspec) const
 {
-    u64 ticks = (u64)tspec.tv_sec * m_ticks_per_second;
-    ticks += ((u64)tspec.tv_nsec * m_ticks_per_second) / 1'000'000'000;
+    u64 ticks;
+    switch (clock_id) {
+    case CLOCK_MONOTONIC:
+        ticks = (u64)tspec.tv_sec * m_ticks_per_second;
+        ticks += ((u64)tspec.tv_nsec * m_ticks_per_second) / 1'000'000'000;
+        break;
+    case CLOCK_REALTIME:
+        ticks = (u64)tspec.tv_sec * 1'000'000'000 + tspec.tv_nsec;
+        break;
+    default:
+        ASSERT_NOT_REACHED();
+    }
     return ticks;
 }
 
 bool TimerQueue::cancel_timer(TimerId id)
 {
-    ScopedSpinLock lock(g_timerqueue_lock);
     Timer* found_timer = nullptr;
-    if (m_timer_queue.for_each([&](Timer& timer) {
+    Queue* timer_queue = nullptr;
+
+    ScopedSpinLock lock(g_timerqueue_lock);
+    if (m_timer_queue_monotonic.list.for_each([&](Timer& timer) {
             if (timer.m_id == id) {
                 found_timer = &timer;
+                timer_queue = &m_timer_queue_monotonic;
                 return IterationDecision::Break;
             }
             return IterationDecision::Continue;
         })
         != IterationDecision::Break) {
+        m_timer_queue_realtime.list.for_each([&](Timer& timer) {
+            if (timer.m_id == id) {
+                found_timer = &timer;
+                timer_queue = &m_timer_queue_realtime;
+                return IterationDecision::Break;
+            }
+            return IterationDecision::Continue;
+        });
+    }
+
+    if (!found_timer) {
         // The timer may be executing right now, if it is then it should
         // be in m_timers_executing. If it is then release the lock
         // briefly to allow it to finish by removing itself
@@ -171,7 +211,8 @@ bool TimerQueue::cancel_timer(TimerId id)
     }
 
     ASSERT(found_timer);
-    remove_timer_locked(*found_timer);
+    ASSERT(timer_queue);
+    remove_timer_locked(*timer_queue, *found_timer);
     lock.unlock();
     found_timer->unref();
     return true;
@@ -179,8 +220,9 @@ bool TimerQueue::cancel_timer(TimerId id)
 
 bool TimerQueue::cancel_timer(Timer& timer)
 {
+    auto& timer_queue = queue_for_timer(timer);
     ScopedSpinLock lock(g_timerqueue_lock);
-    if (!m_timer_queue.contains_slow(&timer)) {
+    if (!timer_queue.list.contains_slow(&timer)) {
         // The timer may be executing right now, if it is then it should
         // be in m_timers_executing. If it is then release the lock
         // briefly to allow it to finish by removing itself
@@ -199,58 +241,64 @@ bool TimerQueue::cancel_timer(Timer& timer)
         return false;
     }
 
-    remove_timer_locked(timer);
+    remove_timer_locked(timer_queue, timer);
     return true;
 }
 
-void TimerQueue::remove_timer_locked(Timer& timer)
+void TimerQueue::remove_timer_locked(Queue& queue, Timer& timer)
 {
-    bool was_next_timer = (m_timer_queue.head() == &timer);
-    m_timer_queue.remove(&timer);
+    bool was_next_timer = (queue.list.head() == &timer);
+    queue.list.remove(&timer);
     timer.set_queued(false);
-    auto now = TimeManagement::the().monotonic_ticks();
+    auto now = timer.now();
     if (timer.m_expires > now)
         timer.m_remaining = timer.m_expires - now;
 
     if (was_next_timer)
-        update_next_timer_due();
+        update_next_timer_due(queue);
 }
 
 void TimerQueue::fire()
 {
     ScopedSpinLock lock(g_timerqueue_lock);
-    auto* timer = m_timer_queue.head();
-    if (!timer)
-        return;
 
-    ASSERT(m_next_timer_due == timer->m_expires);
+    auto fire_timers = [&](Queue& queue) {
+        auto* timer = queue.list.head();
+        ASSERT(timer);
+        ASSERT(queue.next_timer_due == timer->m_expires);
 
-    while (timer && TimeManagement::the().monotonic_ticks() > timer->m_expires) {
-        m_timer_queue.remove(timer);
-        m_timers_executing.append(timer);
+        while (timer && timer->now() > timer->m_expires) {
+            queue.list.remove(timer);
+            m_timers_executing.append(timer);
 
-        update_next_timer_due();
+            update_next_timer_due(queue);
 
-        lock.unlock();
-        timer->m_callback();
-        lock.lock();
+            lock.unlock();
+            timer->m_callback();
+            lock.lock();
 
-        m_timers_executing.remove(timer);
-        timer->set_queued(false);
-        timer->unref();
+            m_timers_executing.remove(timer);
+            timer->set_queued(false);
+            timer->unref();
 
-        timer = m_timer_queue.head();
-    }
+            timer = queue.list.head();
+        }
+    };
+
+    if (!m_timer_queue_monotonic.list.is_empty())
+        fire_timers(m_timer_queue_monotonic);
+    if (!m_timer_queue_realtime.list.is_empty())
+        fire_timers(m_timer_queue_realtime);
 }
 
-void TimerQueue::update_next_timer_due()
+void TimerQueue::update_next_timer_due(Queue& queue)
 {
     ASSERT(g_timerqueue_lock.is_locked());
 
-    if (auto* next_timer = m_timer_queue.head())
-        m_next_timer_due = next_timer->m_expires;
+    if (auto* next_timer = queue.list.head())
+        queue.next_timer_due = next_timer->m_expires;
     else
-        m_next_timer_due = 0;
+        queue.next_timer_due = 0;
 }
 
 }

+ 29 - 10
Kernel/TimerQueue.h

@@ -43,8 +43,9 @@ class Timer : public RefCounted<Timer>
     friend class InlineLinkedListNode<Timer>;
 
 public:
-    Timer(u64 expires, Function<void()>&& callback)
-        : m_expires(expires)
+    Timer(clockid_t clock_id, u64 expires, Function<void()>&& callback)
+        : m_clock_id(clock_id)
+        , m_expires(expires)
         , m_callback(move(callback))
     {
     }
@@ -57,6 +58,7 @@ public:
 
 private:
     TimerId m_id;
+    clockid_t m_clock_id;
     u64 m_expires;
     u64 m_remaining { 0 };
     Function<void()> m_callback;
@@ -78,6 +80,7 @@ private:
     }
     bool is_queued() const { return m_queued.load(AK::MemoryOrder::memory_order_relaxed); }
     void set_queued(bool queued) { m_queued.store(queued, AK::MemoryOrder::memory_order_relaxed); }
+    u64 now() const;
 };
 
 class TimerQueue {
@@ -88,8 +91,8 @@ public:
     static TimerQueue& the();
 
     TimerId add_timer(NonnullRefPtr<Timer>&&);
-    RefPtr<Timer> add_timer_without_id(const timespec& timeout, Function<void()>&& callback);
-    TimerId add_timer(timeval& timeout, Function<void()>&& callback);
+    RefPtr<Timer> add_timer_without_id(clockid_t, const timespec&, Function<void()>&&);
+    TimerId add_timer(clockid_t, timeval& timeout, Function<void()>&& callback);
     bool cancel_timer(TimerId id);
     bool cancel_timer(Timer&);
     bool cancel_timer(NonnullRefPtr<Timer>&& timer)
@@ -99,17 +102,33 @@ public:
     void fire();
 
 private:
-    void remove_timer_locked(Timer&);
-    void update_next_timer_due();
+    struct Queue {
+        InlineLinkedList<Timer> list;
+        u64 next_timer_due { 0 };
+    };
+    void remove_timer_locked(Queue&, Timer&);
+    void update_next_timer_due(Queue&);
     void add_timer_locked(NonnullRefPtr<Timer>);
 
-    timespec ticks_to_time(u64 ticks) const;
-    u64 time_to_ticks(const timespec&) const;
+    Queue& queue_for_timer(Timer& timer)
+    {
+        switch (timer.m_clock_id) {
+        case CLOCK_MONOTONIC:
+            return m_timer_queue_monotonic;
+        case CLOCK_REALTIME:
+            return m_timer_queue_realtime;
+        default:
+            ASSERT_NOT_REACHED();
+        }
+    }
+
+    timespec ticks_to_time(clockid_t, u64 ticks) const;
+    u64 time_to_ticks(clockid_t, const timespec&) const;
 
-    u64 m_next_timer_due { 0 };
     u64 m_timer_id_count { 0 };
     u64 m_ticks_per_second { 0 };
-    InlineLinkedList<Timer> m_timer_queue;
+    Queue m_timer_queue_monotonic;
+    Queue m_timer_queue_realtime;
     InlineLinkedList<Timer> m_timers_executing;
 };