From 01b829eab611c9a06cae16cef2808837df1ac656 Mon Sep 17 00:00:00 2001 From: jules Date: Fri, 20 Sep 2019 17:16:02 +0200 Subject: [PATCH 1/3] Implemented kernel level timers. Also extended SinglyLinkedList to be able to do sorted inserts. --- AK/SinglyLinkedList.h | 55 +++++++++++++++++++++++++++++ Kernel/Scheduler.cpp | 82 +++++++++++++++++++++++++++++++++++++++++-- Kernel/Scheduler.h | 2 ++ 3 files changed, 136 insertions(+), 3 deletions(-) diff --git a/AK/SinglyLinkedList.h b/AK/SinglyLinkedList.h index 3fff790bc48019..115ff1bc95c54b 100644 --- a/AK/SinglyLinkedList.h +++ b/AK/SinglyLinkedList.h @@ -128,6 +128,60 @@ class SinglyLinkedList { m_tail->next = node; m_tail = node; } + + void sorted_insert_slow(const T& value) + { + auto* new_node = new Node(move(value)); + new_node->value = value; + + if (!m_head) { + m_head = new_node; + m_tail = new_node; + return; + } + + if (!m_head->next && new_node->value < m_head->value) { + new_node->next = m_head; + m_head = new_node; + return; + } + + Node* curr = m_head; + while (curr->next && curr->next->value < new_node->value) + { + curr = curr->next; + } + + new_node->next = curr->next; + curr->next = new_node; + if(m_tail == curr) + m_tail = new_node; + + } + + void sorted_insert_slow(T&& value) + { + auto* new_node = new Node(move(value)); + new_node->value = value; + + if (!m_head) { + m_head = new_node; + m_tail = new_node; + return; + } + + Node* curr = m_head; + while (curr->next && curr->next->value < new_node->value) + { + curr = curr->next; + } + + new_node->next = curr->next; + curr->next = new_node; + if(m_tail == curr) + m_tail = new_node; + + } bool contains_slow(const T& value) const { @@ -138,6 +192,7 @@ class SinglyLinkedList { return false; } + using Iterator = SinglyLinkedListIterator; friend Iterator; Iterator begin() { return Iterator(m_head); } diff --git a/Kernel/Scheduler.cpp b/Kernel/Scheduler.cpp index 310f9c2d148f44..85c3109f1bd497 100644 --- a/Kernel/Scheduler.cpp +++ b/Kernel/Scheduler.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -7,6 +8,7 @@ #include SchedulerData* g_scheduler_data; +SinglyLinkedList* g_timer_queue; void Scheduler::init_thread(Thread& thread) { @@ -48,12 +50,26 @@ Thread* g_last_fpu_thread; Thread* g_finalizer; static Process* s_colonel_process; u64 g_uptime; -static u64 s_beep_timeout; +static u64 s_next_timer_due; struct TaskRedirectionData { u16 selector; TSS32 tss; }; + +struct Timer { + u64 expires; + void (*callback)(); + inline bool operator<(const Timer& rhs) + { + return expires < rhs.expires; + } + inline bool operator>( const Timer& rhs) + { + return expires > rhs.expires; + } +}; + static TaskRedirectionData s_redirection; static bool s_active; @@ -65,7 +81,14 @@ bool Scheduler::is_active() void Scheduler::beep() { PCSpeaker::tone_on(440); - s_beep_timeout = g_uptime + 100; + + auto timer = Timer(); + timer.expires = g_uptime + 100; + timer.callback = []() { + PCSpeaker::tone_off(); + dbgprintf("tone off"); + }; + add_timer(timer); } Thread::FileDescriptionBlocker::FileDescriptionBlocker(const FileDescription& description) @@ -523,6 +546,38 @@ void Scheduler::initialize() // Make sure the colonel uses a smallish time slice. s_colonel_process->set_priority(Process::IdlePriority); load_task_register(s_redirection.selector); + + g_timer_queue = new SinglyLinkedList(); + + auto timer = Timer(); + timer.expires = g_uptime + 10000; + timer.callback = []() { + dbgprintf("10 secs\n"); + }; + add_timer(timer); + + + timer = Timer(); + timer.expires = g_uptime + 12000; + timer.callback = []() { + dbgprintf("12 secs\n"); + }; + add_timer(timer); + + timer = Timer(); + timer.expires = g_uptime + 11000; + timer.callback = []() { + dbgprintf("11 secs\n"); + }; + add_timer(timer); + + timer = Timer(); + timer.expires = g_uptime + 5000; + timer.callback = []() { + dbgprintf("5 secs\n"); + }; + add_timer(timer); + } void Scheduler::timer_tick(RegisterDump& regs) @@ -531,11 +586,25 @@ void Scheduler::timer_tick(RegisterDump& regs) return; ++g_uptime; - +/* if (s_beep_timeout && g_uptime > s_beep_timeout) { PCSpeaker::tone_off(); s_beep_timeout = 0; } +*/ + if ( s_next_timer_due && g_uptime > s_next_timer_due) { + + ASSERT(s_next_timer_due == g_timer_queue->first().expires); + while (! g_timer_queue->is_empty() && g_uptime > g_timer_queue->first().expires) + { + auto timer = g_timer_queue->take_first(); + timer.callback(); + } + if (! g_timer_queue->is_empty()) + s_next_timer_due = g_timer_queue->first().expires; + else + s_next_timer_due = 0; + } if (current->tick()) return; @@ -576,6 +645,13 @@ void Scheduler::timer_tick(RegisterDump& regs) "popf\n"); } +void Scheduler::add_timer(Timer& timer) +{ + ASSERT(timer.expires > g_uptime); + g_timer_queue->sorted_insert_slow(timer); + s_next_timer_due = g_timer_queue->first().expires; +} + static bool s_should_stop_idling = false; void Scheduler::stop_idling() diff --git a/Kernel/Scheduler.h b/Kernel/Scheduler.h index f69a2060208303..a765255fe60e61 100644 --- a/Kernel/Scheduler.h +++ b/Kernel/Scheduler.h @@ -7,6 +7,7 @@ class Process; class Thread; +struct Timer; struct RegisterDump; struct SchedulerData; @@ -32,6 +33,7 @@ class Scheduler { static void beep(); static void idle_loop(); static void stop_idling(); + static void add_timer(Timer& timer); template static inline IterationDecision for_each_runnable(Callback); From 63e21fc421161bd314d7838ee09297bc58cc10ff Mon Sep 17 00:00:00 2001 From: Julius Flohr Date: Mon, 23 Sep 2019 10:15:07 +0200 Subject: [PATCH 2/3] Fixed sorted_insert error when newly added element is the smallest. Fixed indentation. --- AK/SinglyLinkedList.h | 41 +++++++++++++++----------------- Kernel/Scheduler.cpp | 55 ++++++++----------------------------------- 2 files changed, 29 insertions(+), 67 deletions(-) diff --git a/AK/SinglyLinkedList.h b/AK/SinglyLinkedList.h index 115ff1bc95c54b..780fb9b0bdaf1d 100644 --- a/AK/SinglyLinkedList.h +++ b/AK/SinglyLinkedList.h @@ -134,27 +134,23 @@ class SinglyLinkedList { auto* new_node = new Node(move(value)); new_node->value = value; - if (!m_head) { - m_head = new_node; - m_tail = new_node; + if (!m_head || m_head->value > new_node->value) { + new_node->next = m_head; + if (!m_head) + m_tail = new_node; + m_head = new_node; return; } - if (!m_head->next && new_node->value < m_head->value) { - new_node->next = m_head; - m_head = new_node; - return; - } - Node* curr = m_head; - while (curr->next && curr->next->value < new_node->value) - { - curr = curr->next; + while (curr->next && curr->next->value < new_node->value) + { + curr = curr->next; } new_node->next = curr->next; - curr->next = new_node; - if(m_tail == curr) + curr->next = new_node; + if(m_tail == curr) m_tail = new_node; } @@ -164,23 +160,24 @@ class SinglyLinkedList { auto* new_node = new Node(move(value)); new_node->value = value; - if (!m_head) { + if (!m_head || m_head->value > new_node->value) { + new_node->next = m_head; + if (!m_head) + m_tail = new_node; m_head = new_node; - m_tail = new_node; return; } - + Node* curr = m_head; - while (curr->next && curr->next->value < new_node->value) + while (curr->next && curr->next->value < new_node->value) { - curr = curr->next; + curr = curr->next; } new_node->next = curr->next; - curr->next = new_node; - if(m_tail == curr) + curr->next = new_node; + if(m_tail == curr) m_tail = new_node; - } bool contains_slow(const T& value) const diff --git a/Kernel/Scheduler.cpp b/Kernel/Scheduler.cpp index 85c3109f1bd497..af9e1410d9fdd0 100644 --- a/Kernel/Scheduler.cpp +++ b/Kernel/Scheduler.cpp @@ -62,11 +62,11 @@ struct Timer { void (*callback)(); inline bool operator<(const Timer& rhs) { - return expires < rhs.expires; + return expires < rhs.expires; } inline bool operator>( const Timer& rhs) { - return expires > rhs.expires; + return expires > rhs.expires; } }; @@ -86,7 +86,7 @@ void Scheduler::beep() timer.expires = g_uptime + 100; timer.callback = []() { PCSpeaker::tone_off(); - dbgprintf("tone off"); + dbgprintf("tone off"); }; add_timer(timer); } @@ -548,36 +548,6 @@ void Scheduler::initialize() load_task_register(s_redirection.selector); g_timer_queue = new SinglyLinkedList(); - - auto timer = Timer(); - timer.expires = g_uptime + 10000; - timer.callback = []() { - dbgprintf("10 secs\n"); - }; - add_timer(timer); - - - timer = Timer(); - timer.expires = g_uptime + 12000; - timer.callback = []() { - dbgprintf("12 secs\n"); - }; - add_timer(timer); - - timer = Timer(); - timer.expires = g_uptime + 11000; - timer.callback = []() { - dbgprintf("11 secs\n"); - }; - add_timer(timer); - - timer = Timer(); - timer.expires = g_uptime + 5000; - timer.callback = []() { - dbgprintf("5 secs\n"); - }; - add_timer(timer); - } void Scheduler::timer_tick(RegisterDump& regs) @@ -586,23 +556,18 @@ void Scheduler::timer_tick(RegisterDump& regs) return; ++g_uptime; -/* - if (s_beep_timeout && g_uptime > s_beep_timeout) { - PCSpeaker::tone_off(); - s_beep_timeout = 0; - } -*/ + if ( s_next_timer_due && g_uptime > s_next_timer_due) { - ASSERT(s_next_timer_due == g_timer_queue->first().expires); - while (! g_timer_queue->is_empty() && g_uptime > g_timer_queue->first().expires) - { + ASSERT(s_next_timer_due == g_timer_queue->first().expires); + while (! g_timer_queue->is_empty() && g_uptime > g_timer_queue->first().expires) + { auto timer = g_timer_queue->take_first(); timer.callback(); - } - if (! g_timer_queue->is_empty()) + } + if (! g_timer_queue->is_empty()) s_next_timer_due = g_timer_queue->first().expires; - else + else s_next_timer_due = 0; } From ae6c7b571bcd636e7205c8e3b105d6a29fb026ce Mon Sep 17 00:00:00 2001 From: Julius Flohr Date: Tue, 24 Sep 2019 17:09:08 +0200 Subject: [PATCH 3/3] feedback from klingt --- AK/SinglyLinkedList.h | 51 ------------------------------- Kernel/Scheduler.cpp | 35 ++------------------- Kernel/Scheduler.h | 1 - Kernel/TimerQueue.cpp | 71 +++++++++++++++++++++++++++++++++++++++++++ Kernel/TimerQueue.h | 43 ++++++++++++++++++++++++++ 5 files changed, 116 insertions(+), 85 deletions(-) create mode 100644 Kernel/TimerQueue.cpp create mode 100644 Kernel/TimerQueue.h diff --git a/AK/SinglyLinkedList.h b/AK/SinglyLinkedList.h index 780fb9b0bdaf1d..a617b21de2e7d7 100644 --- a/AK/SinglyLinkedList.h +++ b/AK/SinglyLinkedList.h @@ -129,57 +129,6 @@ class SinglyLinkedList { m_tail = node; } - void sorted_insert_slow(const T& value) - { - auto* new_node = new Node(move(value)); - new_node->value = value; - - if (!m_head || m_head->value > new_node->value) { - new_node->next = m_head; - if (!m_head) - m_tail = new_node; - m_head = new_node; - return; - } - - Node* curr = m_head; - while (curr->next && curr->next->value < new_node->value) - { - curr = curr->next; - } - - new_node->next = curr->next; - curr->next = new_node; - if(m_tail == curr) - m_tail = new_node; - - } - - void sorted_insert_slow(T&& value) - { - auto* new_node = new Node(move(value)); - new_node->value = value; - - if (!m_head || m_head->value > new_node->value) { - new_node->next = m_head; - if (!m_head) - m_tail = new_node; - m_head = new_node; - return; - } - - Node* curr = m_head; - while (curr->next && curr->next->value < new_node->value) - { - curr = curr->next; - } - - new_node->next = curr->next; - curr->next = new_node; - if(m_tail == curr) - m_tail = new_node; - } - bool contains_slow(const T& value) const { for (auto* node = m_head; node; node = node->next) { diff --git a/Kernel/Scheduler.cpp b/Kernel/Scheduler.cpp index af9e1410d9fdd0..59cd984cf7c375 100644 --- a/Kernel/Scheduler.cpp +++ b/Kernel/Scheduler.cpp @@ -8,7 +8,6 @@ #include SchedulerData* g_scheduler_data; -SinglyLinkedList* g_timer_queue; void Scheduler::init_thread(Thread& thread) { @@ -57,19 +56,6 @@ struct TaskRedirectionData { TSS32 tss; }; -struct Timer { - u64 expires; - void (*callback)(); - inline bool operator<(const Timer& rhs) - { - return expires < rhs.expires; - } - inline bool operator>( const Timer& rhs) - { - return expires > rhs.expires; - } -}; - static TaskRedirectionData s_redirection; static bool s_active; @@ -557,18 +543,8 @@ void Scheduler::timer_tick(RegisterDump& regs) ++g_uptime; - if ( s_next_timer_due && g_uptime > s_next_timer_due) { - - ASSERT(s_next_timer_due == g_timer_queue->first().expires); - while (! g_timer_queue->is_empty() && g_uptime > g_timer_queue->first().expires) - { - auto timer = g_timer_queue->take_first(); - timer.callback(); - } - if (! g_timer_queue->is_empty()) - s_next_timer_due = g_timer_queue->first().expires; - else - s_next_timer_due = 0; + if ( TimerQueue::s_next_timer_due && g_uptime > TimerQueue::s_next_timer_due) { + TimerQueue::fire_timer(); } if (current->tick()) @@ -610,13 +586,6 @@ void Scheduler::timer_tick(RegisterDump& regs) "popf\n"); } -void Scheduler::add_timer(Timer& timer) -{ - ASSERT(timer.expires > g_uptime); - g_timer_queue->sorted_insert_slow(timer); - s_next_timer_due = g_timer_queue->first().expires; -} - static bool s_should_stop_idling = false; void Scheduler::stop_idling() diff --git a/Kernel/Scheduler.h b/Kernel/Scheduler.h index a765255fe60e61..8b1f64dcb7fba6 100644 --- a/Kernel/Scheduler.h +++ b/Kernel/Scheduler.h @@ -33,7 +33,6 @@ class Scheduler { static void beep(); static void idle_loop(); static void stop_idling(); - static void add_timer(Timer& timer); template static inline IterationDecision for_each_runnable(Callback); diff --git a/Kernel/TimerQueue.cpp b/Kernel/TimerQueue.cpp new file mode 100644 index 00000000000000..ba3dd45abea87e --- /dev/null +++ b/Kernel/TimerQueue.cpp @@ -0,0 +1,71 @@ +#include +#include +#include + + +SinglyLinkedList* g_timer_queue; + +static u64 s_next_timer_due; +static u64 s_timer_id_count; +void TimerQueue::initialize() +{ + + g_timer_queue = new SinglyLinkedList(); +} + + +u64 TimerQueue::add_timer(Timer& timer) +{ + ASSERT(timer.expires > Scheduler::g_uptime); + timer.id = ++s_timer_id_count; + g_timer_queue->sorted_insert_slow(timer); + s_next_timer_due = g_timer_queue->first().expires; + return s_timer_id_count; +} + +u64 add_timer(u64 duration, TimeUnit unit, void (callback)()) +{ + atuo timer = Timer(); + timer.expires = g_uptime + duration * unit; + timer.callback = callback; + return add_timer(timer); +} + +void TimerQueue::sorted_insert_slow(T&& value) +{ + auto* new_node = new Node(move(value)); + new_node->value = value; + + if (!g_timer_queue->m_head || g_timer_queue->m_head->value > new_node->value) { + new_node->next = g_timer_queue->m_head; + if (!m_head) + m_tail = new_node; + m_head = new_node; + return; + } + + Node* curr = m_head; + while (curr->next && curr->next->value < new_node->value) + { + curr = curr->next; + } + + new_node->next = curr->next; + curr->next = new_node; + if(g_timer_queue->m_tail == curr) + g_timer_queue->m_tail = new_node; +} + +void TimerQueue::fire_timer() +{ + ASSERT(s_next_timer_due == g_timer_queue->first().expires); + while (! g_timer_queue->is_empty() && Scheduler::g_uptime > g_timer_queue->first().expires) + { + auto timer = g_timer_queue->take_first(); + timer.callback(); + } + if (! g_timer_queue->is_empty()) + s_next_timer_due = g_timer_queue->first().expires; + else + s_next_timer_due = 0; +} \ No newline at end of file diff --git a/Kernel/TimerQueue.h b/Kernel/TimerQueue.h new file mode 100644 index 00000000000000..465c369173431a --- /dev/null +++ b/Kernel/TimerQueue.h @@ -0,0 +1,43 @@ +#pragma once + +#include + +struct Timer { + u64 id; + u64 expires; + 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 X& rhs) const + { + return id == rhs.id; + } +}; + +enum TimeUnit { + MS = TICKS_PER_SECOND / 1000, + S = TICKS_PER_SECOND, + M = TICKS_PER_SECOND * 60 +}; + + +class TimerQueue { +friend class SinglyLinkedList; +public: + static void initialize(); + static u64 add_timer(Timer&); + static u64 add_timer(u64 duration, TimeUnit, void (callback)()); + static Timer& get_timer(u64 id); + static bool update_timer(Timer&) + static bool cancel_timer(u64 id); +private: + static void fire_timer(); + static void sorted_list_insert_slow() +}; \ No newline at end of file