Implement some kind of Round Robin Priority Scheduling

This commit is contained in:
Baptiste Wicht 2014-01-30 17:07:32 +01:00
parent 01ca17a9f8
commit 2ebc0e22ac
5 changed files with 84 additions and 25 deletions

View File

@ -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

View File

@ -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;

View File

@ -8,9 +8,11 @@
#ifndef ARRAY_H
#define ARRAY_H
#include "stl/types.hpp"
namespace std {
template<typename T, uint64_t N>
template<typename T, size_t N>
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) {}

View File

@ -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();
}

View File

@ -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<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;
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(){