mirror of
https://github.com/wichtounet/thor-os.git
synced 2025-09-09 20:43:34 -04:00
Implement some kind of Round Robin Priority Scheduling
This commit is contained in:
parent
01ca17a9f8
commit
2ebc0e22ac
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
void __thor_assert(bool condition);
|
void __thor_assert(bool condition);
|
||||||
void __thor_assert(bool condition, const char* message);
|
void __thor_assert(bool condition, const char* message);
|
||||||
|
void __thor_unreachable(const char* message);
|
||||||
|
|
||||||
#ifdef NASSERT
|
#ifdef NASSERT
|
||||||
inline void thor_assert(bool){}
|
inline void thor_assert(bool){}
|
||||||
@ -24,4 +25,9 @@ inline void thor_assert(bool condition, const char* message){
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
inline void thor_unreachable(const char* message){
|
||||||
|
__thor_unreachable(message);
|
||||||
|
__builtin_unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -16,9 +16,10 @@
|
|||||||
|
|
||||||
namespace scheduler {
|
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 MIN_PRIORITY = 0;
|
||||||
constexpr const size_t PRIORITY_LEVELS = MAX_PRIORITY - MIN_PRIORITY + 1;
|
constexpr const size_t PRIORITY_LEVELS = MAX_PRIORITY - MIN_PRIORITY + 1;
|
||||||
|
constexpr const size_t DEFAULT_PRIORITY = 2;
|
||||||
|
|
||||||
typedef size_t pid_t;
|
typedef size_t pid_t;
|
||||||
|
|
||||||
@ -37,6 +38,7 @@ struct segment_t {
|
|||||||
|
|
||||||
struct process_t {
|
struct process_t {
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
size_t priority;
|
||||||
|
|
||||||
bool system;
|
bool system;
|
||||||
|
|
||||||
|
@ -8,9 +8,11 @@
|
|||||||
#ifndef ARRAY_H
|
#ifndef ARRAY_H
|
||||||
#define ARRAY_H
|
#define ARRAY_H
|
||||||
|
|
||||||
|
#include "stl/types.hpp"
|
||||||
|
|
||||||
namespace std {
|
namespace std {
|
||||||
|
|
||||||
template<typename T, uint64_t N>
|
template<typename T, size_t N>
|
||||||
class array {
|
class array {
|
||||||
private:
|
private:
|
||||||
T data[N];
|
T data[N];
|
||||||
@ -19,7 +21,7 @@ public:
|
|||||||
typedef T value_type;
|
typedef T value_type;
|
||||||
typedef value_type* iterator;
|
typedef value_type* iterator;
|
||||||
typedef const value_type* const_iterator;
|
typedef const value_type* const_iterator;
|
||||||
typedef uint64_t size_type;
|
typedef size_t size_type;
|
||||||
|
|
||||||
T& operator[](size_type pos){
|
T& operator[](size_type pos){
|
||||||
return data[pos];
|
return data[pos];
|
||||||
@ -57,11 +59,11 @@ public:
|
|||||||
typedef value_type* pointer_type;
|
typedef value_type* pointer_type;
|
||||||
typedef value_type* iterator;
|
typedef value_type* iterator;
|
||||||
typedef const value_type* const_iterator;
|
typedef const value_type* const_iterator;
|
||||||
typedef uint64_t size_type;
|
typedef size_t size_type;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T* array;
|
T* array;
|
||||||
uint64_t _size;
|
size_t _size;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
unique_heap_array() : array(nullptr), _size(0) {}
|
unique_heap_array() : array(nullptr), _size(0) {}
|
||||||
|
@ -19,3 +19,8 @@ void __thor_assert(bool condition, const char* message){
|
|||||||
suspend_kernel();
|
suspend_kernel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void __thor_unreachable(const char* message){
|
||||||
|
k_print_line(message);
|
||||||
|
suspend_kernel();
|
||||||
|
}
|
||||||
|
@ -5,6 +5,9 @@
|
|||||||
// http://www.boost.org/LICENSE_1_0.txt)
|
// http://www.boost.org/LICENSE_1_0.txt)
|
||||||
//=======================================================================
|
//=======================================================================
|
||||||
|
|
||||||
|
#include "stl/array.hpp"
|
||||||
|
#include "stl/vector.hpp"
|
||||||
|
|
||||||
#include "scheduler.hpp"
|
#include "scheduler.hpp"
|
||||||
#include "paging.hpp"
|
#include "paging.hpp"
|
||||||
#include "assert.hpp"
|
#include "assert.hpp"
|
||||||
@ -12,8 +15,6 @@
|
|||||||
|
|
||||||
#include "console.hpp"
|
#include "console.hpp"
|
||||||
|
|
||||||
#include "stl/array.hpp"
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
struct process_control_t {
|
struct process_control_t {
|
||||||
@ -22,8 +23,12 @@ struct process_control_t {
|
|||||||
size_t rounds;
|
size_t rounds;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//The Process Control Block
|
||||||
std::array<process_control_t, scheduler::MAX_PROCESS> pcb;
|
std::array<process_control_t, scheduler::MAX_PROCESS> pcb;
|
||||||
|
|
||||||
|
//Define one run queue for each priority level
|
||||||
|
std::array<std::vector<scheduler::pid_t>, scheduler::PRIORITY_LEVELS> run_queues;
|
||||||
|
|
||||||
bool started = false;
|
bool started = false;
|
||||||
|
|
||||||
constexpr const size_t TURNOVER = 10;
|
constexpr const size_t TURNOVER = 10;
|
||||||
@ -44,6 +49,8 @@ char idle_kernel_stack[scheduler::kernel_stack_size];
|
|||||||
void create_idle_task(){
|
void create_idle_task(){
|
||||||
auto& idle_process = scheduler::new_process();
|
auto& idle_process = scheduler::new_process();
|
||||||
|
|
||||||
|
idle_process.priority = scheduler::MIN_PRIORITY;
|
||||||
|
|
||||||
idle_process.system = true;
|
idle_process.system = true;
|
||||||
idle_process.physical_cr3 = paging::get_physical_pml4t();
|
idle_process.physical_cr3 = paging::get_physical_pml4t();
|
||||||
idle_process.paging_size = 0;
|
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;
|
*(stack_pointer - 14) = process.process.regs.ds;
|
||||||
|
|
||||||
asm volatile("mov cr3, %0" : : "r" (process.process.physical_cr3) : "memory");
|
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(){
|
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){
|
//1. Run a process of higher priority, if any
|
||||||
next = (next + 1) % pcb.size();
|
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){
|
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(){
|
scheduler::process_t& scheduler::new_process(){
|
||||||
|
//TODO use get_free_pid() that searchs through the PCB
|
||||||
auto pid = next_pid++;
|
auto pid = next_pid++;
|
||||||
|
|
||||||
auto& process = pcb[pid];
|
auto& process = pcb[pid];
|
||||||
|
|
||||||
process.process.system = false;
|
process.process.system = false;
|
||||||
process.process.pid = pid;
|
process.process.pid = pid;
|
||||||
|
process.process.priority = scheduler::DEFAULT_PRIORITY;
|
||||||
process.state = process_state::NEW;
|
process.state = process_state::NEW;
|
||||||
|
|
||||||
return process.process;
|
return process.process;
|
||||||
}
|
}
|
||||||
|
|
||||||
void scheduler::queue_process(scheduler::pid_t p){
|
void scheduler::queue_process(scheduler::pid_t pid){
|
||||||
pcb[p].state = process_state::READY;
|
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(){
|
scheduler::pid_t scheduler::get_pid(){
|
||||||
|
Loading…
x
Reference in New Issue
Block a user