mirror of
https://github.com/wichtounet/thor-os.git
synced 2025-09-08 20:10: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
|
||||
std::array<std::vector<scheduler::pid_t>, scheduler::PRIORITY_LEVELS> run_queues;
|
||||
|
||||
int_lock queue_lock;
|
||||
|
||||
volatile bool started = false;
|
||||
|
||||
volatile size_t rr_quantum = 0;
|
||||
@ -153,7 +151,8 @@ void gc_task(){
|
||||
// 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){
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -361,20 +361,26 @@ void create_post_init_task(){
|
||||
logging::logf(logging::log_level::DEBUG, "scheduler: post_init_task %u \n", post_init_pid);
|
||||
}
|
||||
|
||||
void switch_to_process(size_t pid){
|
||||
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);
|
||||
void switch_to_process_with_lock(size_t new_pid){
|
||||
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), new_pid, pcb[current_pid].process.context->rip);
|
||||
} 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;
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
size_t select_next_process(){
|
||||
auto current_priority = pcb[current_pid].process.priority;
|
||||
void switch_to_process(size_t new_pid){
|
||||
// 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
|
||||
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");
|
||||
}
|
||||
|
||||
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){
|
||||
//1. Calculate some stuff
|
||||
auto first_page = paging::page_align(address);
|
||||
@ -858,17 +882,24 @@ void scheduler::tick(){
|
||||
if(process.rounds == rr_quantum){
|
||||
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();
|
||||
|
||||
//If it is the same, no need to go to the switching process
|
||||
if(pid == current_pid){
|
||||
process.state = process_state::RUNNING;
|
||||
process.state = previous_state;
|
||||
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);
|
||||
} else {
|
||||
@ -880,14 +911,16 @@ void scheduler::tick(){
|
||||
|
||||
void scheduler::yield(){
|
||||
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;
|
||||
|
||||
auto pid = select_next_process();
|
||||
direct_int_lock lock;
|
||||
|
||||
auto pid = select_next_process_with_lock();
|
||||
|
||||
if(pid != current_pid){
|
||||
verbose_logf(logging::log_level::DEBUG, "scheduler: Yields %u to %u\n", current_pid, pid);
|
||||
switch_to_process(pid);
|
||||
switch_to_process_with_lock(pid);
|
||||
} else {
|
||||
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
|
||||
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
|
||||
|
Loading…
x
Reference in New Issue
Block a user