diff --git a/kernel/include/assert.hpp b/kernel/include/assert.hpp index 9887a165..32801563 100644 --- a/kernel/include/assert.hpp +++ b/kernel/include/assert.hpp @@ -10,6 +10,7 @@ void __thor_assert(bool condition); void __thor_assert(bool condition, const char* message); +void __thor_unreachable(const char* message); #ifdef NASSERT inline void thor_assert(bool){} @@ -24,4 +25,9 @@ inline void thor_assert(bool condition, const char* message){ } #endif +inline void thor_unreachable(const char* message){ + __thor_unreachable(message); + __builtin_unreachable(); +} + #endif diff --git a/kernel/include/process.hpp b/kernel/include/process.hpp index b690bbfe..6ba6a106 100644 --- a/kernel/include/process.hpp +++ b/kernel/include/process.hpp @@ -16,9 +16,10 @@ namespace scheduler { -constexpr const size_t MAX_PRIORITY = 2; +constexpr const size_t MAX_PRIORITY = 3; constexpr const size_t MIN_PRIORITY = 0; constexpr const size_t PRIORITY_LEVELS = MAX_PRIORITY - MIN_PRIORITY + 1; +constexpr const size_t DEFAULT_PRIORITY = 2; typedef size_t pid_t; @@ -37,6 +38,7 @@ struct segment_t { struct process_t { pid_t pid; + size_t priority; bool system; diff --git a/kernel/include/stl/array.hpp b/kernel/include/stl/array.hpp index ece2e10f..5eaacc37 100644 --- a/kernel/include/stl/array.hpp +++ b/kernel/include/stl/array.hpp @@ -8,9 +8,11 @@ #ifndef ARRAY_H #define ARRAY_H +#include "stl/types.hpp" + namespace std { -template +template class array { private: T data[N]; @@ -19,7 +21,7 @@ public: typedef T value_type; typedef value_type* iterator; typedef const value_type* const_iterator; - typedef uint64_t size_type; + typedef size_t size_type; T& operator[](size_type pos){ return data[pos]; @@ -57,11 +59,11 @@ public: typedef value_type* pointer_type; typedef value_type* iterator; typedef const value_type* const_iterator; - typedef uint64_t size_type; + typedef size_t size_type; private: T* array; - uint64_t _size; + size_t _size; public: unique_heap_array() : array(nullptr), _size(0) {} diff --git a/kernel/src/assert.cpp b/kernel/src/assert.cpp index 02def0ab..f1ad6f3d 100644 --- a/kernel/src/assert.cpp +++ b/kernel/src/assert.cpp @@ -19,3 +19,8 @@ void __thor_assert(bool condition, const char* message){ suspend_kernel(); } } + +void __thor_unreachable(const char* message){ + k_print_line(message); + suspend_kernel(); +} diff --git a/kernel/src/scheduler.cpp b/kernel/src/scheduler.cpp index 94c69f1a..44d09811 100644 --- a/kernel/src/scheduler.cpp +++ b/kernel/src/scheduler.cpp @@ -5,6 +5,9 @@ // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= +#include "stl/array.hpp" +#include "stl/vector.hpp" + #include "scheduler.hpp" #include "paging.hpp" #include "assert.hpp" @@ -12,8 +15,6 @@ #include "console.hpp" -#include "stl/array.hpp" - namespace { struct process_control_t { @@ -22,8 +23,12 @@ struct process_control_t { size_t rounds; }; +//The Process Control Block std::array pcb; +//Define one run queue for each priority level +std::array, scheduler::PRIORITY_LEVELS> run_queues; + bool started = false; constexpr const size_t TURNOVER = 10; @@ -44,6 +49,8 @@ char idle_kernel_stack[scheduler::kernel_stack_size]; void create_idle_task(){ auto& idle_process = scheduler::new_process(); + idle_process.priority = scheduler::MIN_PRIORITY; + idle_process.system = true; idle_process.physical_cr3 = paging::get_physical_pml4t(); idle_process.paging_size = 0; @@ -95,28 +102,54 @@ void switch_to_process(const interrupt::syscall_regs& regs, size_t pid){ *(stack_pointer - 14) = process.process.regs.ds; asm volatile("mov cr3, %0" : : "r" (process.process.physical_cr3) : "memory"); - - /*asm volatile("mov rax, %0; mov ds, ax; mov es, ax; mov fs, ax; mov gs, ax;" - : //No outputs - : "r" (process.data_selector) - : "rax"); - - asm volatile("mov cr3, %0" : : "r" (process.physical_cr3) : "memory"); - - asm volatile("push %0; push %1; pushfq; pop rax; or rax, 0x200; push rax; push %2; push %3; iretq" - : //No outputs - : "r" (process.data_selector), "r" (process.user_rsp), "r" (process.code_selector), "r" (process.rip) - : "rax", "memory");*/ } size_t select_next_process(){ - auto next = (current_pid+ 1) % pcb.size(); + auto current_priority = pcb[current_pid].process.priority; - while(pcb[next].state != scheduler::process_state::READY){ - next = (next + 1) % pcb.size(); + //1. Run a process of higher priority, if any + for(size_t p = scheduler::MAX_PRIORITY; p > current_priority; --p){ + for(auto pid : run_queues[p]){ + if(pcb[pid].state == scheduler::process_state::READY){ + return pid; + } + } } - return next; + //2. Run the next process of the same priority + + auto& current_run_queue = run_queues[current_priority]; + + size_t next_index = 0; + for(size_t i = 0; i < current_run_queue.size(); ++i){ + if(current_run_queue[i] == current_pid){ + next_index = (i + 1) % current_run_queue.size(); + break; + } + } + + for(size_t i = 0; i < current_run_queue.size(); ++i){ + auto index = (next_index + i) % current_run_queue.size(); + auto pid = current_run_queue[index]; + + if(pcb[pid].state == scheduler::process_state::READY){ + return pid; + } + } + + thor_assert(current_priority > 0, "The idle task should always be ready"); + + //3. Run a process of lower priority + + for(size_t p = current_priority - 1; p >= scheduler::MIN_PRIORITY; --p){ + for(auto pid : run_queues[p]){ + if(pcb[pid].state == scheduler::process_state::READY){ + return pid; + } + } + } + + thor_unreachable("No process is READY"); } void save_context(const interrupt::syscall_regs& regs){ @@ -206,19 +239,30 @@ void scheduler::reschedule(const interrupt::syscall_regs& regs){ } scheduler::process_t& scheduler::new_process(){ + //TODO use get_free_pid() that searchs through the PCB auto pid = next_pid++; auto& process = pcb[pid]; process.process.system = false; process.process.pid = pid; + process.process.priority = scheduler::DEFAULT_PRIORITY; process.state = process_state::NEW; return process.process; } -void scheduler::queue_process(scheduler::pid_t p){ - pcb[p].state = process_state::READY; +void scheduler::queue_process(scheduler::pid_t pid){ + thor_assert(pid < scheduler::MAX_PROCESS, "pid out of bounds"); + + auto& process = pcb[pid]; + + thor_assert(process.process.priority <= scheduler::MAX_PRIORITY, "Invalid priority"); + thor_assert(process.process.priority >= scheduler::MIN_PRIORITY, "Invalid priority"); + + process.state = process_state::READY; + + run_queues[process.process.priority].push_back(pid); } scheduler::pid_t scheduler::get_pid(){