-
-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Kernel: Add kernel-level timer queue (heavily based on @juliusf's work)
PR #591 defines the rationale for kernel-level timers. They're most immediately useful for TCP retransmission, but will most likely see use in many other areas as well.
- Loading branch information
1 parent
13cf7e7
commit 115b315
Showing
4 changed files
with
124 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
#include <AK/Function.h> | ||
#include <AK/NonnullOwnPtr.h> | ||
#include <AK/OwnPtr.h> | ||
#include <Kernel/Scheduler.h> | ||
#include <Kernel/TimerQueue.h> | ||
|
||
static TimerQueue* s_the; | ||
|
||
TimerQueue& TimerQueue::the() | ||
{ | ||
if (!s_the) | ||
s_the = new TimerQueue; | ||
return *s_the; | ||
} | ||
|
||
u64 TimerQueue::add_timer(NonnullOwnPtr<Timer>&& timer) | ||
{ | ||
ASSERT(timer->expires > g_uptime); | ||
|
||
timer->id = ++m_timer_id_count; | ||
|
||
auto following_timer = m_timer_queue.find([&timer](auto& other) { return other->expires > timer->expires; }); | ||
if (following_timer.is_end()) | ||
m_timer_queue.append(move(timer)); | ||
else | ||
m_timer_queue.insert_before(following_timer, move(timer)); | ||
|
||
update_next_timer_due(); | ||
|
||
return m_timer_id_count; | ||
} | ||
|
||
u64 TimerQueue::add_timer(u64 duration, TimeUnit unit, Function<void()>&& callback) | ||
{ | ||
NonnullOwnPtr timer = make<Timer>(); | ||
timer->expires = g_uptime + duration * unit; | ||
timer->callback = move(callback); | ||
return add_timer(move(timer)); | ||
} | ||
|
||
bool TimerQueue::cancel_timer(u64 id) | ||
{ | ||
auto it = m_timer_queue.find([id](auto& timer) { return timer->id == id; }); | ||
if (it.is_end()) | ||
return false; | ||
m_timer_queue.remove(it); | ||
update_next_timer_due(); | ||
return true; | ||
} | ||
|
||
void TimerQueue::fire() | ||
{ | ||
if (m_timer_queue.is_empty()) | ||
return; | ||
|
||
ASSERT(m_next_timer_due == m_timer_queue.first()->expires); | ||
|
||
while (!m_timer_queue.is_empty() && g_uptime > m_timer_queue.first()->expires) { | ||
auto timer = m_timer_queue.take_first(); | ||
timer->callback(); | ||
} | ||
|
||
update_next_timer_due(); | ||
} | ||
|
||
void TimerQueue::update_next_timer_due() | ||
{ | ||
if (m_timer_queue.is_empty()) | ||
m_next_timer_due = 0; | ||
else | ||
m_next_timer_due = m_timer_queue.first()->expires; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
#pragma once | ||
|
||
#include <AK/Function.h> | ||
#include <AK/NonnullOwnPtr.h> | ||
#include <AK/OwnPtr.h> | ||
#include <AK/SinglyLinkedList.h> | ||
#include <Kernel/Arch/i386/PIT.h> | ||
|
||
struct Timer { | ||
u64 id; | ||
u64 expires; | ||
Function<void()> callback; | ||
bool operator<(const Timer& rhs) const | ||
{ | ||
return expires < rhs.expires; | ||
} | ||
bool operator>(const Timer& rhs) const | ||
{ | ||
return expires > rhs.expires; | ||
} | ||
bool operator==(const Timer& rhs) const | ||
{ | ||
return id == rhs.id; | ||
} | ||
}; | ||
|
||
enum TimeUnit { | ||
MS = TICKS_PER_SECOND / 1000, | ||
S = TICKS_PER_SECOND, | ||
M = TICKS_PER_SECOND * 60 | ||
}; | ||
|
||
class TimerQueue { | ||
public: | ||
static TimerQueue& the(); | ||
|
||
u64 add_timer(NonnullOwnPtr<Timer>&&); | ||
u64 add_timer(u64 duration, TimeUnit, Function<void()>&& callback); | ||
bool cancel_timer(u64 id); | ||
void fire(); | ||
|
||
private: | ||
void update_next_timer_due(); | ||
|
||
u64 m_next_timer_due { 0 }; | ||
u64 m_timer_id_count { 0 }; | ||
SinglyLinkedList<NonnullOwnPtr<Timer>> m_timer_queue; | ||
}; |