From b2920331b103d43793ac8be927a80a593ce0be5a Mon Sep 17 00:00:00 2001 From: Jon Santmyer Date: Sat, 17 Oct 2026 16:21:55 -0400 Subject: add pcb stop syscall and scheduler dequeueing --- proc/scheduler.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++--------- proc/scheduler.h | 3 ++ 2 files changed, 101 insertions(+), 18 deletions(-) (limited to 'proc') diff --git a/proc/scheduler.c b/proc/scheduler.c index a3c3071..43cb7fc 100644 --- a/proc/scheduler.c +++ b/proc/scheduler.c @@ -2,20 +2,41 @@ #include "api/error.h" #include "hal/smp.h" #include "lib/printf.h" +#include "panic/panic.h" +#include "sys/lock.h" #include "sys/objdir.h" #include "proc/init.h" #include "proc/process.h" #include "proc/ipc.h" +#include //TODO: Better scheduling algorithm than round robin. +atomic_flag s_running_list_lock; static struct pcb_header *s_running_list; +atomic_flag s_ready_queue_lock; static struct pcb_header *s_ready_queue; + +atomic_flag s_mail_queue_lock; static struct pcb_header *s_mail_queue; static uintmax_t s_this_tick; -static inline void +static void +s_enqueue_pcb(struct pcb_header *pcb, struct pcb_header **list, atomic_flag *lock) +{ + take_mutex(lock); + if(pcb->sched_prev) pcb->sched_prev->sched_next = pcb->sched_next; + if(pcb->sched_prev) pcb->sched_next->sched_prev = pcb->sched_prev; + + (*list)->sched_prev = pcb; + pcb->sched_next = *list; + pcb->sched_prev = NULL; + *list = pcb; + release_mutex(lock); +} + +static void s_scheduler_swap_pcb(processor_t *proc, pcb_t *current_pcb, pcb_t *target_pcb) { jove_obj_t *target_rootdir = pcb_getrootdir(target_pcb); @@ -31,6 +52,17 @@ s_scheduler_swap_pcb(processor_t *proc, pcb_t *current_pcb, pcb_t *target_pcb) (void*)obj_getvalue((jove_owned_obj_t*)&target_pagedir)); } +int scheduler_make_ready(jove_owned_obj_t *pcb_obj) +{ + pcb_t *pcb = obj_deref(pcb_obj); + struct pcb_header *pcb_header = (struct pcb_header*)pcb; + + pcb_header->state = PCB_STATE_READY; + s_enqueue_pcb(pcb_header, &s_ready_queue, &s_ready_queue_lock); + + return 0; +} + int scheduler_yield(pid_t target_pid) { processor_t *proc = processor_current(); @@ -41,6 +73,11 @@ int scheduler_yield(pid_t target_pid) pcb_t *target_pcb = pcb_frompid(target_pid); } if(target_pcb == 0) { + if(target_pid == 0) { + //We need to pre-emptively tick the scheduler. + scheduler_tick(); + return 0; + } return -EBADPROC; } @@ -50,15 +87,30 @@ int scheduler_yield(pid_t target_pid) return 0; } -void -s_enqueue_pcb(struct pcb_header *pcb, struct pcb_header *list) +int scheduler_stop(jove_owned_obj_t *pcb_obj, int stop_code) { + struct pcb_header *pcb = obj_deref(pcb_obj); + struct pcb_header *current_pcb = obj_deref(process_current()); + + atomic_flag *state_lock = pcb->state == PCB_STATE_READY ? &s_ready_queue_lock : &s_running_list_lock; + + take_mutex(state_lock); if(pcb->sched_prev) pcb->sched_prev->sched_next = pcb->sched_next; - if(pcb->sched_prev) pcb->sched_next->sched_prev = pcb->sched_prev; + if(pcb->sched_next) pcb->sched_next->sched_prev = pcb->sched_prev; - list->sched_prev = pcb; - pcb->sched_next = list; - pcb->sched_prev = NULL; + if(pcb->state == PCB_STATE_READY) { + if(s_ready_queue == pcb) s_ready_queue = pcb->sched_next; + }else{ + kprintf("SCHEDULER STOP IS NOT READY FOR SMP\n"); + if(s_running_list == pcb) s_running_list = pcb->sched_next; + + if(current_pcb == pcb) { + release_mutex(state_lock); + return scheduler_yield(0); + } + } + release_mutex(state_lock); + return 0; } void @@ -68,8 +120,7 @@ scheduler_block_for_mail(struct pcb_header *pcb, uintmax_t timeout, pid_t yield_ pcb_getpid((pcb_t*)pcb), timeout, yield_target); pcb->state = PCB_STATE_BLOCKED_MAIL; - s_enqueue_pcb(pcb, s_mail_queue); - s_mail_queue = pcb; + s_enqueue_pcb(pcb, &s_mail_queue, &s_mail_queue_lock); pcb->block_until = s_this_tick + timeout; scheduler_yield(yield_target); @@ -78,19 +129,38 @@ scheduler_block_for_mail(struct pcb_header *pcb, uintmax_t timeout, pid_t yield_ void s_schedule_ready_queue(void) { + take_mutex(&s_ready_queue_lock); for(struct pcb_header *pcb = s_ready_queue; pcb; pcb = s_ready_queue) { s_ready_queue = pcb->sched_next; + //Verify that the root directory of the PCB is valid. + jove_owned_obj_t *pcb_rootdir_obj = obj_take(pcb_getrootdir((pcb_t*)pcb)); + jove_objdir_t *pcb_rootdir = obj_deref(pcb_rootdir_obj); + + jove_owned_obj_t *pcb_selfobj = (jove_owned_obj_t*)&pcb_rootdir->entries[PCB_ROOTDIR_SELF_I]; + if(obj_deref(pcb_selfobj) != pcb) { + obj_release(pcb_rootdir_obj); + continue; + } + + jove_owned_obj_t *pcb_pdirobj = (jove_owned_obj_t*)&pcb_rootdir->entries[PCB_ROOTDIR_PAGEDIR_I]; + if(obj_gettype(pcb_pdirobj) != JOVE_OBJ_PAGEDIR) { + obj_release(pcb_rootdir_obj); + continue; + } + //Add this process to the ready list after the last ready process. pcb->state = PCB_STATE_READY; - s_enqueue_pcb(pcb, s_running_list); - s_running_list = pcb; + s_enqueue_pcb(pcb, &s_running_list, &s_running_list_lock); + obj_release(pcb_rootdir_obj); } + release_mutex(&s_ready_queue_lock); } void s_schedule_mail_queue(void) { + take_mutex(&s_mail_queue_lock); struct pcb_header *pcb = s_mail_queue; while(pcb) { struct pcb_header *next_pcb = pcb->sched_next; @@ -108,24 +178,22 @@ s_schedule_mail_queue(void) //This never hits, but if things change in impl we may have to abort here. if(port_recv(recv_port, pcb_port) < 0) continue; - s_enqueue_pcb(pcb, s_running_list); - s_running_list = pcb; + s_enqueue_pcb(pcb, &s_ready_queue, &s_ready_queue_lock); } if(port_poll_recv(pcb_port)) { //Recv buffer is full, so unblock. - s_enqueue_pcb(pcb, s_running_list); - s_running_list = pcb; + s_enqueue_pcb(pcb, &s_ready_queue, &s_ready_queue_lock); } if(s_this_tick >= pcb->block_until) { ipc_klogf("Unblocking %i due to timeout\n", pcb_getpid((pcb_t*)pcb)); - s_enqueue_pcb(pcb, s_running_list); - s_running_list = pcb; + s_enqueue_pcb(pcb, &s_ready_queue, &s_ready_queue_lock); } loop_end: pcb = next_pcb; } + release_mutex(&s_mail_queue_lock); } void @@ -133,12 +201,19 @@ scheduler_tick() { size_t last_tick = s_this_tick++; - s_schedule_ready_queue(); s_schedule_mail_queue(); + s_schedule_ready_queue(); + processor_t *proc = processor_current(); struct pcb_header *current_pcb = obj_deref(processor_getpcb(proc)); + + take_mutex(&s_running_list_lock); struct pcb_header *next_pcb = s_running_list; + if(next_pcb == NULL) { + kpanic("Kernel ran out of running processes!\n"); + } + struct pcb_header *tail = next_pcb; while(tail->sched_next) { @@ -149,12 +224,17 @@ scheduler_tick() tail->sched_next = next_pcb; next_pcb->sched_prev = tail; s_running_list = next_pcb->sched_next; + release_mutex(&s_running_list_lock); s_scheduler_swap_pcb(proc, (pcb_t*)current_pcb, (pcb_t*)next_pcb); } void scheduler_init(jove_owned_obj_t *pcb_obj, void *process_main) { + release_mutex(&s_running_list_lock); + release_mutex(&s_ready_queue_lock); + release_mutex(&s_mail_queue_lock); + struct pcb_header *pcb_header = obj_deref(pcb_obj); pcb_header->state = PCB_STATE_RUNNING; diff --git a/proc/scheduler.h b/proc/scheduler.h index 964f2c0..9b11688 100644 --- a/proc/scheduler.h +++ b/proc/scheduler.h @@ -11,7 +11,10 @@ void scheduler_restorestate(void); void scheduler_switch(void *this_sp, void *other_sp, void *other_cr3); void _scheduler_switch_pcb_arch(pcb_t *target); +int scheduler_make_ready(jove_owned_obj_t *pcb_obj); int scheduler_yield(pid_t target); +int scheduler_stop(jove_owned_obj_t *pcb_obj, int stop_code); + void scheduler_tick(void); void scheduler_block_for_mail(struct pcb_header *pcb, size_t timeout, pid_t yield_target); -- cgit v1.2.3