summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJon Santmyer <jon@jonsantmyer.com>2026-10-17 16:21:55 -0400
committerJon Santmyer <jon@jonsantmyer.com>2026-10-17 16:21:55 -0400
commitb2920331b103d43793ac8be927a80a593ce0be5a (patch)
treea91934ff588ffe02697b530899c8c0227521e04a
parentd8aca3ff2501f9a77e22e5afb7a30380aed205af (diff)
downloadjove-kernel-b2920331b103d43793ac8be927a80a593ce0be5a.tar.gz
jove-kernel-b2920331b103d43793ac8be927a80a593ce0be5a.tar.bz2
jove-kernel-b2920331b103d43793ac8be927a80a593ce0be5a.zip
add pcb stop syscall and scheduler dequeueingHEADmain
-rw-r--r--api/process.h4
-rw-r--r--api/syscall.h6
-rw-r--r--arch/x86_64/hal/obj.c7
-rw-r--r--doc/syscall.md37
-rw-r--r--hal/obj.h6
-rw-r--r--proc/scheduler.c116
-rw-r--r--proc/scheduler.h3
-rw-r--r--sys/objdir.h7
-rw-r--r--sys/syscall_objdir.c2
-rw-r--r--sys/syscall_pcb.c45
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 |
diff --git a/hal/obj.h b/hal/obj.h
index befbc24..180b830 100644
--- a/hal/obj.h
+++ b/hal/obj.h
@@ -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;
}