mirror of
https://github.com/wichtounet/thor-os.git
synced 2025-09-09 04:22:04 -04:00
Fix bugs with the scheduler
Selecting the next process and switching to it should be done in a safe fashion. Otherwise, can be preempted between the two and the decision may not be valid anymore
This commit is contained in:
parent
f0661aaf46
commit
aaa1f2a7a2
@ -58,8 +58,6 @@ pcb_t pcb;
|
|||||||
//Define one run queue for each priority level
|
//Define one run queue for each priority level
|
||||||
std::array<std::vector<scheduler::pid_t>, scheduler::PRIORITY_LEVELS> run_queues;
|
std::array<std::vector<scheduler::pid_t>, scheduler::PRIORITY_LEVELS> run_queues;
|
||||||
|
|
||||||
int_lock queue_lock;
|
|
||||||
|
|
||||||
volatile bool started = false;
|
volatile bool started = false;
|
||||||
|
|
||||||
volatile size_t rr_quantum = 0;
|
volatile size_t rr_quantum = 0;
|
||||||
@ -153,7 +151,8 @@ void gc_task(){
|
|||||||
// 5. Remove process from run queue
|
// 5. Remove process from run queue
|
||||||
|
|
||||||
{
|
{
|
||||||
std::lock_guard<int_lock> l(queue_lock);
|
// Move only write to the list with a lock
|
||||||
|
direct_int_lock queue_lock;
|
||||||
|
|
||||||
for(size_t index = 0; index < run_queue(desc.priority).size(); ++index){
|
for(size_t index = 0; index < run_queue(desc.priority).size(); ++index){
|
||||||
if(run_queue(desc.priority)[index] == desc.pid){
|
if(run_queue(desc.priority)[index] == desc.pid){
|
||||||
@ -291,7 +290,8 @@ void queue_process(scheduler::pid_t pid){
|
|||||||
|
|
||||||
process.state = scheduler::process_state::READY;
|
process.state = scheduler::process_state::READY;
|
||||||
|
|
||||||
std::lock_guard<int_lock> l(queue_lock);
|
// Move only write to the list with a lock
|
||||||
|
direct_int_lock queue_lock;
|
||||||
run_queue(process.process.priority).push_back(pid);
|
run_queue(process.process.priority).push_back(pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -361,20 +361,26 @@ void create_post_init_task(){
|
|||||||
logging::logf(logging::log_level::DEBUG, "scheduler: post_init_task %u \n", post_init_pid);
|
logging::logf(logging::log_level::DEBUG, "scheduler: post_init_task %u \n", post_init_pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
void switch_to_process(size_t pid){
|
void switch_to_process_with_lock(size_t new_pid){
|
||||||
if(pcb[current_pid].process.system){
|
if (pcb[current_pid].process.system) {
|
||||||
verbose_logf(logging::log_level::DEBUG, "scheduler: Switch from %u (s:%u) to %u (rip:%u)\n", current_pid, static_cast<size_t>(pcb[current_pid].state), pid, pcb[current_pid].process.context->rip);
|
verbose_logf(logging::log_level::DEBUG, "scheduler: Switch from %u (s:%u) to %u (rip:%u)\n",
|
||||||
|
current_pid, static_cast<size_t>(pcb[current_pid].state), new_pid, pcb[current_pid].process.context->rip);
|
||||||
} else {
|
} else {
|
||||||
verbose_logf(logging::log_level::DEBUG, "scheduler: Switch from %u (s:%u) to %u\n", current_pid, static_cast<size_t>(pcb[current_pid].state), pid);
|
verbose_logf(logging::log_level::DEBUG, "scheduler: Switch from %u (s:%u) to %u\n",
|
||||||
|
current_pid, static_cast<size_t>(pcb[current_pid].state), new_pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This should never be interrupted
|
|
||||||
direct_int_lock l;
|
|
||||||
|
|
||||||
auto old_pid = current_pid;
|
auto old_pid = current_pid;
|
||||||
current_pid = pid;
|
|
||||||
|
|
||||||
auto& process = pcb[pid];
|
// It is possible that preemption occured and that the process is already
|
||||||
|
// running, in which case, there is no need to do anything
|
||||||
|
if(old_pid == new_pid){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
current_pid = new_pid;
|
||||||
|
|
||||||
|
auto& process = pcb[new_pid];
|
||||||
process.state = scheduler::process_state::RUNNING;
|
process.state = scheduler::process_state::RUNNING;
|
||||||
|
|
||||||
gdt::tss().rsp0_low = process.process.kernel_rsp & 0xFFFFFFFF;
|
gdt::tss().rsp0_low = process.process.kernel_rsp & 0xFFFFFFFF;
|
||||||
@ -383,10 +389,20 @@ void switch_to_process(size_t pid){
|
|||||||
task_switch(old_pid, current_pid);
|
task_switch(old_pid, current_pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t select_next_process(){
|
void switch_to_process(size_t new_pid){
|
||||||
auto current_priority = pcb[current_pid].process.priority;
|
// This should never be interrupted
|
||||||
|
direct_int_lock l;
|
||||||
|
|
||||||
std::lock_guard<int_lock> l(queue_lock);
|
switch_to_process_with_lock(new_pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Select the next process to run.
|
||||||
|
*
|
||||||
|
* This function assume that an int_lock is already owned.
|
||||||
|
*/
|
||||||
|
size_t select_next_process_with_lock(){
|
||||||
|
auto current_priority = pcb[current_pid].process.priority;
|
||||||
|
|
||||||
//1. Run a process of higher priority, if any
|
//1. Run a process of higher priority, if any
|
||||||
for(size_t p = scheduler::MAX_PRIORITY; p > current_priority; --p){
|
for(size_t p = scheduler::MAX_PRIORITY; p > current_priority; --p){
|
||||||
@ -435,6 +451,14 @@ size_t select_next_process(){
|
|||||||
thor_unreachable("No process is READY");
|
thor_unreachable("No process is READY");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t select_next_process(){
|
||||||
|
auto current_priority = pcb[current_pid].process.priority;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return select_next_process_with_lock();
|
||||||
|
}
|
||||||
|
|
||||||
bool allocate_user_memory(scheduler::process_t& process, size_t address, size_t size, size_t& ref){
|
bool allocate_user_memory(scheduler::process_t& process, size_t address, size_t size, size_t& ref){
|
||||||
//1. Calculate some stuff
|
//1. Calculate some stuff
|
||||||
auto first_page = paging::page_align(address);
|
auto first_page = paging::page_align(address);
|
||||||
@ -858,17 +882,24 @@ void scheduler::tick(){
|
|||||||
if(process.rounds == rr_quantum){
|
if(process.rounds == rr_quantum){
|
||||||
process.rounds = 0;
|
process.rounds = 0;
|
||||||
|
|
||||||
process.state = process_state::READY;
|
auto previous_state = process.state;
|
||||||
|
|
||||||
|
// Change to Ready if it was not blocked
|
||||||
|
// If it was blocked, we still prempt and it will end up in reschedule
|
||||||
|
// later but with a full time quanta
|
||||||
|
if(previous_state != process_state::BLOCKED && previous_state != process_state::BLOCKED_TIMEOUT){
|
||||||
|
process.state = process_state::READY;
|
||||||
|
}
|
||||||
|
|
||||||
auto pid = select_next_process();
|
auto pid = select_next_process();
|
||||||
|
|
||||||
//If it is the same, no need to go to the switching process
|
//If it is the same, no need to go to the switching process
|
||||||
if(pid == current_pid){
|
if(pid == current_pid){
|
||||||
process.state = process_state::RUNNING;
|
process.state = previous_state;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
verbose_logf(logging::log_level::DEBUG, "scheduler: Preempt %u to %u\n", current_pid, pid);
|
verbose_logf(logging::log_level::DEBUG, "scheduler: Preempt %u (%d->%d) to %u\n", current_pid, previous_state, process.state, pid);
|
||||||
|
|
||||||
switch_to_process(pid);
|
switch_to_process(pid);
|
||||||
} else {
|
} else {
|
||||||
@ -880,14 +911,16 @@ void scheduler::tick(){
|
|||||||
|
|
||||||
void scheduler::yield(){
|
void scheduler::yield(){
|
||||||
thor_assert(started, "No interest in yielding before start");
|
thor_assert(started, "No interest in yielding before start");
|
||||||
|
thor_assert(pcb[current_pid].state == process_state::RUNNING, "Can only yield() running processes");
|
||||||
|
|
||||||
pcb[current_pid].state = process_state::READY;
|
pcb[current_pid].state = process_state::READY;
|
||||||
|
|
||||||
auto pid = select_next_process();
|
direct_int_lock lock;
|
||||||
|
|
||||||
|
auto pid = select_next_process_with_lock();
|
||||||
|
|
||||||
if(pid != current_pid){
|
if(pid != current_pid){
|
||||||
verbose_logf(logging::log_level::DEBUG, "scheduler: Yields %u to %u\n", current_pid, pid);
|
switch_to_process_with_lock(pid);
|
||||||
switch_to_process(pid);
|
|
||||||
} else {
|
} else {
|
||||||
pcb[current_pid].state = process_state::RUNNING;
|
pcb[current_pid].state = process_state::RUNNING;
|
||||||
}
|
}
|
||||||
@ -900,9 +933,11 @@ void scheduler::reschedule(){
|
|||||||
|
|
||||||
//The process just got blocked or put to sleep, choose another one
|
//The process just got blocked or put to sleep, choose another one
|
||||||
if(process.state != process_state::RUNNING){
|
if(process.state != process_state::RUNNING){
|
||||||
auto index = select_next_process();
|
direct_int_lock lock;
|
||||||
|
|
||||||
switch_to_process(index);
|
auto index = select_next_process_with_lock();
|
||||||
|
|
||||||
|
switch_to_process_with_lock(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
//At this point we just have to return to the current process
|
//At this point we just have to return to the current process
|
||||||
|
Loading…
x
Reference in New Issue
Block a user