Serenity Operating System
1/*
2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#pragma once
8
9#include <AK/AtomicRefCounted.h>
10#include <AK/Function.h>
11#include <AK/IntrusiveList.h>
12#include <AK/OwnPtr.h>
13#include <AK/Time.h>
14#include <Kernel/Library/NonnullLockRefPtr.h>
15#include <Kernel/Time/TimeManagement.h>
16
17namespace Kernel {
18
19AK_TYPEDEF_DISTINCT_ORDERED_ID(u64, TimerId);
20
21class Timer final : public AtomicRefCounted<Timer> {
22 friend class TimerQueue;
23
24public:
25 void setup(clockid_t clock_id, Time expires, Function<void()>&& callback)
26 {
27 VERIFY(!is_queued());
28 m_clock_id = clock_id;
29 m_expires = expires;
30 m_callback = move(callback);
31 }
32
33 ~Timer()
34 {
35 VERIFY(!is_queued());
36 }
37
38 Time remaining() const;
39
40private:
41 TimerId m_id;
42 clockid_t m_clock_id;
43 Time m_expires;
44 Time m_remaining {};
45 Function<void()> m_callback;
46 Atomic<bool> m_cancelled { false };
47 Atomic<bool> m_callback_finished { false };
48 Atomic<bool> m_in_use { false };
49
50 bool operator<(Timer const& rhs) const
51 {
52 return m_expires < rhs.m_expires;
53 }
54 bool operator>(Timer const& rhs) const
55 {
56 return m_expires > rhs.m_expires;
57 }
58 bool operator==(Timer const& rhs) const
59 {
60 return m_id == rhs.m_id;
61 }
62
63 void clear_cancelled() { return m_cancelled.store(false, AK::memory_order_release); }
64 bool set_cancelled() { return m_cancelled.exchange(true, AK::memory_order_acq_rel); }
65
66 bool is_in_use() { return m_in_use.load(AK::memory_order_acquire); };
67 void set_in_use() { m_in_use.store(true, AK::memory_order_release); }
68 void clear_in_use() { return m_in_use.store(false, AK::memory_order_release); }
69
70 bool is_callback_finished() const { return m_callback_finished.load(AK::memory_order_acquire); }
71 void clear_callback_finished() { m_callback_finished.store(false, AK::memory_order_release); }
72 void set_callback_finished() { m_callback_finished.store(true, AK::memory_order_release); }
73
74 Time now(bool) const;
75
76 bool is_queued() const { return m_list_node.is_in_list(); }
77
78public:
79 IntrusiveListNode<Timer> m_list_node;
80 using List = IntrusiveList<&Timer::m_list_node>;
81};
82
83class TimerQueue {
84 friend class Timer;
85
86public:
87 TimerQueue();
88 static TimerQueue& the();
89
90 TimerId add_timer(NonnullLockRefPtr<Timer>&&);
91 bool add_timer_without_id(NonnullLockRefPtr<Timer>, clockid_t, Time const&, Function<void()>&&);
92 bool cancel_timer(Timer& timer, bool* was_in_use = nullptr);
93 void fire();
94
95private:
96 struct Queue {
97 Timer::List list;
98 Time next_timer_due {};
99 };
100 void remove_timer_locked(Queue&, Timer&);
101 void update_next_timer_due(Queue&);
102 void add_timer_locked(NonnullLockRefPtr<Timer>);
103
104 Queue& queue_for_timer(Timer& timer)
105 {
106 switch (timer.m_clock_id) {
107 case CLOCK_MONOTONIC:
108 case CLOCK_MONOTONIC_COARSE:
109 case CLOCK_MONOTONIC_RAW:
110 return m_timer_queue_monotonic;
111 case CLOCK_REALTIME:
112 case CLOCK_REALTIME_COARSE:
113 return m_timer_queue_realtime;
114 default:
115 VERIFY_NOT_REACHED();
116 }
117 }
118
119 u64 m_timer_id_count { 0 };
120 u64 m_ticks_per_second { 0 };
121 Queue m_timer_queue_monotonic;
122 Queue m_timer_queue_realtime;
123 Timer::List m_timers_executing;
124};
125
126}