diff options
| author | Jon Santmyer <jon@jonsantmyer.com> | 2026-10-17 16:21:55 -0400 |
|---|---|---|
| committer | Jon Santmyer <jon@jonsantmyer.com> | 2026-10-17 16:21:55 -0400 |
| commit | b2920331b103d43793ac8be927a80a593ce0be5a (patch) | |
| tree | a91934ff588ffe02697b530899c8c0227521e04a | |
| parent | d8aca3ff2501f9a77e22e5afb7a30380aed205af (diff) | |
| download | jove-kernel-b2920331b103d43793ac8be927a80a593ce0be5a.tar.gz jove-kernel-b2920331b103d43793ac8be927a80a593ce0be5a.tar.bz2 jove-kernel-b2920331b103d43793ac8be927a80a593ce0be5a.zip | |
| -rw-r--r-- | api/process.h | 4 | ||||
| -rw-r--r-- | api/syscall.h | 6 | ||||
| -rw-r--r-- | arch/x86_64/hal/obj.c | 7 | ||||
| -rw-r--r-- | doc/syscall.md | 37 | ||||
| -rw-r--r-- | hal/obj.h | 6 | ||||
| -rw-r--r-- | proc/scheduler.c | 116 | ||||
| -rw-r--r-- | proc/scheduler.h | 3 | ||||
| -rw-r--r-- | sys/objdir.h | 7 | ||||
| -rw-r--r-- | sys/syscall_objdir.c | 2 | ||||
| -rw-r--r-- | sys/syscall_pcb.c | 45 |
10 files changed, 206 insertions, 27 deletions
diff --git a/api/process.h b/api/process.h index 05b7632..52e787e 100644 --- a/api/process.h +++ b/api/process.h @@ -8,11 +8,11 @@ typedef intmax_t pid_t; enum pcb_state { _PCB_STATE_INVALID = 0, - PCB_STATE_DEAD, + PCB_STATE_STOPPED, PCB_STATE_EMBRYO, PCB_STATE_READY, PCB_STATE_RUNNING, - PCB_STATE_WAITING, + PCB_STATE_BLOCKED_KOBJ, PCB_STATE_BLOCKED_MAIL }; diff --git a/api/syscall.h b/api/syscall.h index 62b9917..4a5d3e4 100644 --- a/api/syscall.h +++ b/api/syscall.h @@ -208,6 +208,8 @@ enum SYSCALL_PCB_SWAP, SYSCALL_PCB_STACK, SYSCALL_PCB_READY, + SYSCALL_PCB_STOP, + SYSCALL_PCB_STATE, }; #define SYSCALL_PERM_PCB_PID (JOVE_PERM_READ) @@ -216,7 +218,9 @@ enum #define SYSCALL_PERM_PCB_RECV (JOVE_PERM_READ | JOVE_PERM_WRITE) #define SYSCALL_PERM_PCB_SWAP (SYSCALL_PERM_PCB_SEND | SYSCALL_PERM_PCB_RECV) #define SYSCALL_PERM_PCB_STACK (JOVE_PERM_WRITE | JOVE_PERM_MUTATE) -#define SYSCALL_PERM_PCB_READY (JOVE_PERM_ALL) +#define SYSCALL_PERM_PCB_READY (JOVE_PERM_WRITE | JOVE_PERM_MUTATE) +#define SYSCALL_PERM_PCB_STOP (JOVE_PERM_WRITE | JOVE_PERM_MUTATE) +#define SYSCALL_PERM_PCB_STATE (JOVE_PERM_READ) #define SYSCALL_PERM_PCB_SEND_OBJDIR (JOVE_PERM_WRITE) #define SYSCALL_PERM_PCB_RECV_DST (JOVE_PERM_MUTATE) diff --git a/arch/x86_64/hal/obj.c b/arch/x86_64/hal/obj.c index d6c9a80..e2b6cc8 100644 --- a/arch/x86_64/hal/obj.c +++ b/arch/x86_64/hal/obj.c @@ -5,6 +5,13 @@ #include "hal/obj.h" #include "jove.h" #include "sys/link.h" +#include "sys/objdir.h" + +jove_objdir_t* +obj_getobjdir(jove_obj_t *obj) +{ + return (jove_objdir_t*)((uintptr_t)obj & ~0xFFF); +} jove_owned_obj_t* obj_take(jove_obj_t *obj) diff --git a/doc/syscall.md b/doc/syscall.md index 10f8eb5..6d7583f 100644 --- a/doc/syscall.md +++ b/doc/syscall.md @@ -377,6 +377,7 @@ Successful unmapping returns `0`. | SYSCALL_PCB_RECV | JOVE_PERM_MUTATE | JOVE_PERM_MUTATE | | SYSCALL_PCB_SWAP | JOVE_PERM_MUTATE | JOVE_PERM_MUTATE | | SYSCALL_PCB_STACK | JOVE_PERM_WRITE, JOVE_PERM_MUTATE | JOVE_PERM_WRITE, JOVE_PERM_MUTATE | +| SYSCALL_PCB_STOP | JOVE_PERM_WRITE, JOVE_PERM_MUTATE | | #### SYSCALL_PCB_YIELD @@ -490,6 +491,42 @@ If the PCB already has a stack of the specified type, the kernel will return `-E Successful operation returns `0`. +#### SYSCALL_PCB_READY + +Adds the target PCB to the ready queue, and sets the state to `PCB_STATE_READY`. + +If the target PCB is not in the `PCB_STATE_EMBRYO` state, the kernel will return `-EBADCALL`. + +If the target PCB does not have a system and interrupt stack, the kernel will return `-ENOTREADY`. + +If the target PCB is not in entry `PCB_ROOTDIR_SELF_I`, the kernel will return `-EBADPATH`. + +If the root directory of the target PCB does not have a `JOVE_OBJ_PAGEDIR` object at `PCB_ROOTDIR_PAGEDIR_I`, the kernel will return `-EBADPATH`. + +Successful calls return `0`. + +#### SYSCALL_PCB_STOP + +Removes the targeted PCB from the scheduler queue, sets the state to `PCB_STATE_STOPPED`, and sets the state code to the passed value. + +| Data | State Code | +|--------------|-------------| +| Size (bytes) | sizeof(int) | + +If the target PCB is not in the `PCB_STATE_READY` or `PCB_STATE_RUNNING` state, the kernel will return `-EBADCALL`. + +If the target PCB is not the current PCB, successful call will return `0`. + +Otherwise, the PCB will yield to the next process determined by the scheduler. + + +#### SYSCALL_PCB_STATE + +Gets the state code of the target PCB object. + +If the target PCB is not in the `PCB_STATE_STOPPED` state, the kernel will return `-ENOTDONE`. + + ### JOVE_OBJ_INITRD_FILE | Syscall | Target Permissions | @@ -10,11 +10,6 @@ #include "arch/x86_64/hal/obj.h" #endif -typedef struct jove_objdir -{ - jove_obj_t entries[OBJDIR_ENTRIES]; -} jove_objdir_t; - /*Locks the mutex of the kernel object provided. Returns the locked version. */ jove_owned_obj_t *obj_take(jove_obj_t *obj); jove_owned_obj_t *obj_trytake(jove_obj_t *obj); @@ -36,4 +31,5 @@ void obj_setvalue(jove_owned_obj_t *obj, uintmax_t value); bool obj_compare(jove_obj_t *a, jove_obj_t *b); + #endif 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 <stdatomic.h> //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); diff --git a/sys/objdir.h b/sys/objdir.h index 4ef6d04..8ef602d 100644 --- a/sys/objdir.h +++ b/sys/objdir.h @@ -4,6 +4,13 @@ #include "api/obj.h" #include "hal/obj.h" +typedef struct jove_objdir +{ + jove_obj_t entries[OBJDIR_ENTRIES]; +} jove_objdir_t; + +jove_objdir_t *obj_getobjdir(jove_obj_t *obj); + int objdir_new(jove_owned_obj_t *untyped_obj); /*Returns the n'th entry of the object directory passed. * If the passed object is not an objdir, returns NULL and sets errno to EBADOBJ. diff --git a/sys/syscall_objdir.c b/sys/syscall_objdir.c index 8a17671..28eba68 100644 --- a/sys/syscall_objdir.c +++ b/sys/syscall_objdir.c @@ -18,7 +18,7 @@ s_syscall_objdir_objtype( uint16_t local_idx = *((uint16_t*)payload_data); if(local_idx > OBJDIR_ENTRIES) { - kprintf("%s: Object index is out of bounds (>= 512)\n", __func__); + kprintf("%s: Object index is out of bounds (%i >= 512)\n", __func__, local_idx); return EOOB; } diff --git a/sys/syscall_pcb.c b/sys/syscall_pcb.c index 7a6d4e3..19699ce 100644 --- a/sys/syscall_pcb.c +++ b/sys/syscall_pcb.c @@ -5,6 +5,7 @@ #include "lib/printf.h" #include "proc/process.h" #include "proc/scheduler.h" +#include "sys/objdir.h" #include "syscall.h" int @@ -242,6 +243,40 @@ s_syscall_pcb_stack(jove_owned_obj_t *pcb_obj, return 0; } +int s_syscall_pcb_ready( + jove_owned_obj_t *target_obj, + lockstack_t *lockstack, + jove_obj_t *objdir) +{ + jove_objdir_t *target_objdir = obj_getobjdir(obj_asunowned(target_obj)); + if(!obj_compare(&target_objdir->entries[PCB_ROOTDIR_SELF_I], obj_asunowned(target_obj))) { + klogf("Target PCB is not in entry %i of it's objdir!\n", PCB_ROOTDIR_SELF_I); + return -EBADPATH; + } + + jove_owned_obj_t *pagedir_obj = obj_take(&target_objdir->entries[PCB_ROOTDIR_PAGEDIR_I]); + if(obj_gettype(pagedir_obj) != JOVE_OBJ_PAGEDIR) { + klogf("Target PCB rootdir does not have pagedir in entry %i\n", PCB_ROOTDIR_PAGEDIR_I); + obj_release(pagedir_obj); + return -EBADPATH; + } + + obj_release(pagedir_obj); + return 0; +} + +int +s_syscall_pcb_stop(jove_owned_obj_t *pcb_obj, + size_t bytes_left, + void *payload_data) +{ + size_t bytes_needed = sizeof(int); + CHECK_TOOSMALL(bytes_needed, bytes_left, "Message too small for payload"); + + int stop_code = *((int*)payload_data); + return scheduler_stop(pcb_obj, stop_code); +} + int _syscall_handle_pcb(syscall_context_t *ctx) { @@ -275,6 +310,16 @@ _syscall_handle_pcb(syscall_context_t *ctx) ctx->target.obj, &ctx->lockstack, ctx->objdir, ctx->bytes_left, ctx->payload); return -EPERM; + case SYSCALL_PCB_READY: + if(ctx->target.permissions & SYSCALL_PERM_PCB_READY) + return s_syscall_pcb_ready( + ctx->target.obj, &ctx->lockstack, ctx->objdir); + return -EPERM; + case SYSCALL_PCB_STOP: + if(ctx->target.permissions & SYSCALL_PERM_PCB_STOP) + return s_syscall_pcb_stop( + ctx->target.obj, ctx->bytes_left, ctx->payload); + default: return -EBADCALL; } |
