Compare commits

..

2 Commits

Author SHA1 Message Date
fea0999726 Fix scheduler starvation, use lists for scheduling
All checks were successful
Build documentation / build-and-deploy (push) Successful in 33s
2026-01-22 11:54:52 +01:00
7eceecf6e3 Add mutex syscalls 2026-01-20 22:18:43 +01:00
15 changed files with 203 additions and 74 deletions

View File

@@ -9,5 +9,9 @@
#define SYS_SCHED 6
#define SYS_CREATE_MEM 7
#define SYS_UNLINK_MEM 8
#define SYS_CREATE_MUTEX 9
#define SYS_UNLINK_MUTEX 10
#define SYS_LOCK_MUTEX 11
#define SYS_UNLOCK_MUTEX 12
#endif // _M_SYSCALL_DEFS_H

View File

@@ -6,20 +6,66 @@
#include <stdint.h>
#include <string/string.h>
#define EXAMPLE 1
#define EXAMPLE 2
#if EXAMPLE == 1
void app_thread1 (void) {
test ('b');
quit ();
}
int spawn (void (*fn) (void)) {
size_t stack_size = 256 * PAGE_SIZE;
void* stack = malloc (stack_size);
if (stack == NULL)
return -ST_OOM_ERROR;
uintptr_t stack_top = (uintptr_t)stack + stack_size;
return clone (stack_top, stack_size, fn);
}
void app_main (void) { spawn (&app_thread1); }
#elif EXAMPLE == 2
#define MUTEX 2000
void app_thread1 (void);
int spawn (void (*fn) (void)) {
size_t stack_size = 256 * PAGE_SIZE;
void* stack = malloc (stack_size);
if (stack == NULL)
return -ST_OOM_ERROR;
uintptr_t stack_top = (uintptr_t)stack + stack_size;
return clone (stack_top, stack_size, fn);
}
void app_main (void) {
test ('a');
test ('a');
test ('a');
create_mutex (MUTEX, RV_PRIVATE);
int* xs = malloc (1024 * sizeof (*xs));
memset (xs, 123, 1024 * sizeof (*xs));
free (xs);
spawn (&app_thread1);
test ('a');
test ('a');
test ('a');
for (;;) {
/* lock_mutex (MUTEX, RV_PRIVATE); */
for (int i = 0; i < 3; i++)
test ('a');
/* unlock_mutex (MUTEX, RV_PRIVATE); */
}
}
void app_thread1 (void) {
for (int i = 0; i < 3; i++)
test ('b');
for (;;) {
/* lock_mutex (MUTEX, RV_PRIVATE); */
/* unlock_mutex (MUTEX, RV_PRIVATE); */
}
quit ();
}
#endif

View File

@@ -27,7 +27,7 @@ struct cpu {
spin_lock_t lock;
struct rb_node_link* proc_run_q;
struct list_node_link* proc_run_q;
struct proc* proc_current;
};

View File

@@ -25,12 +25,8 @@ int amd64_syscall_dispatch (void* stack_ptr) {
struct proc* caller = thiscpu->proc_current;
__asm__ volatile ("sti");
int result = func (caller, regs, regs->rdi, regs->rsi, regs->rdx, regs->r10, regs->r8, regs->r9);
__asm__ volatile ("cli");
return result;
}

View File

@@ -34,6 +34,7 @@ try:
spin_unlock (&mutex->resource->lock, &ctxmt);
DEBUG ("proc->pid=%d\n", proc->pid);
proc_suspend (proc, &mutex->suspension_q);
goto try;
@@ -52,11 +53,10 @@ bool proc_mutex_unlock (struct proc* proc, struct proc_mutex* mutex) {
spin_lock (&mutex->suspension_q.lock, &ctxsq);
struct proc* resumed_proc = NULL;
struct rb_node_link* node;
rbtree_first (&mutex->suspension_q.proc_tree, node);
struct list_node_link* node = mutex->suspension_q.proc_list;
if (node) {
resumed_proc = rbtree_entry (node, struct proc, suspension_link);
resumed_proc = list_entry (node, struct proc, suspension_link);
mutex->owner = resumed_proc;
mutex->locked = true;

View File

@@ -28,14 +28,6 @@
#define SCHED_REAP_FREQ 10
/*
* Lock hierachy:
* - proc_tree_lock
* - cpu->lock
* - proc->lock
* - suspension_q->lock
*/
static struct rb_node_link* proc_tree = NULL;
static rw_spin_lock_t proc_tree_lock = RW_SPIN_LOCK_INIT;
@@ -217,49 +209,46 @@ void proc_register (struct proc* proc, struct cpu* cpu) {
proc->cpu = cpu;
rw_spin_write_lock (&proc_tree_lock, &ctxprtr);
rbtree_insert (struct proc, &proc_tree, &proc->proc_tree_link, proc_tree_link, pid);
rw_spin_write_unlock (&proc_tree_lock, &ctxprtr);
spin_lock (&cpu->lock, &ctxcpu);
rbtree_insert (struct proc, &cpu->proc_run_q, &proc->cpu_run_q_link, cpu_run_q_link, pid);
list_append (cpu->proc_run_q, &proc->cpu_run_q_link);
if (cpu->proc_current == NULL)
cpu->proc_current = proc;
spin_unlock (&cpu->lock, &ctxcpu);
rw_spin_write_lock (&proc_tree_lock, &ctxprtr);
rbtree_insert (struct proc, &proc_tree, &proc->proc_tree_link, proc_tree_link, pid);
rw_spin_write_unlock (&proc_tree_lock, &ctxprtr);
}
/* caller holds cpu->lock */
static struct proc* proc_find_sched (struct cpu* cpu) {
struct rb_node_link* node = NULL;
struct proc* current = cpu->proc_current;
struct proc* proc = NULL;
if (current)
rbtree_next (&current->cpu_run_q_link, node);
if (!node)
rbtree_first (&cpu->proc_run_q, node);
if (!node)
if (!cpu->proc_run_q)
return NULL;
struct rb_node_link* first = node;
struct list_node_link *current, *start;
if (cpu->proc_current)
current = cpu->proc_current->cpu_run_q_link.next;
else
current = cpu->proc_run_q;
if (!current)
current = cpu->proc_run_q;
start = current;
do {
proc = rbtree_entry (node, struct proc, cpu_run_q_link);
struct proc* proc = list_entry (current, struct proc, cpu_run_q_link);
if (atomic_load (&proc->state) == PROC_READY)
return proc;
rbtree_next (node, node);
current = current->next ? current->next : cpu->proc_run_q;
} while (current != start);
if (!node)
rbtree_first (&cpu->proc_run_q, node);
} while (node != first);
return ((atomic_load (&current->state) == PROC_READY) ? current : NULL);
return NULL;
}
static void proc_reap (void) {
@@ -281,9 +270,8 @@ static void proc_reap (void) {
if (atomic_load (&proc->state) == PROC_DEAD) {
spin_lock (&proc->lock, &ctxpr);
rbtree_delete (&proc_tree, &proc->proc_tree_link);
spin_unlock (&proc->lock, &ctxpr);
list_append (reap_list, &proc->reap_link);
spin_unlock (&proc->lock, &ctxpr);
}
node = next;
@@ -318,7 +306,7 @@ void proc_sched (void* regs) {
if (prev != NULL) {
spin_lock (&prev->lock, &ctxpr);
prev->pdata.regs = *(struct saved_regs*)regs;
memcpy (&prev->pdata.regs, regs, sizeof (struct saved_regs));
spin_unlock (&prev->lock, &ctxpr);
}
@@ -347,7 +335,7 @@ void proc_kill (struct proc* proc) {
spin_lock (&cpu->lock, &ctxcpu);
rbtree_delete (&cpu->proc_run_q, &proc->cpu_run_q_link);
list_remove (cpu->proc_run_q, &proc->cpu_run_q_link);
if (cpu->proc_current == proc)
cpu->proc_current = NULL;
@@ -370,13 +358,13 @@ void proc_suspend (struct proc* proc, struct proc_suspension_q* sq) {
/* remove from run q */
spin_lock (&cpu->lock, &ctxcpu);
rbtree_delete (&cpu->proc_run_q, &proc->cpu_run_q_link);
list_remove (cpu->proc_run_q, &proc->cpu_run_q_link);
if (cpu->proc_current == proc)
cpu->proc_current = NULL;
spin_unlock (&cpu->lock, &ctxcpu);
spin_lock (&sq->lock, &ctxsq);
rbtree_insert (struct proc, &sq->proc_tree, &proc->suspension_link, suspension_link, pid);
list_append (sq->proc_list, &proc->suspension_link);
spin_unlock (&sq->lock, &ctxsq);
cpu_request_sched (cpu);
@@ -388,7 +376,7 @@ void proc_resume (struct proc* proc) {
struct proc_suspension_q* sq = proc->suspension_q;
spin_lock (&sq->lock, &ctxsq);
rbtree_delete (&sq->proc_tree, &proc->suspension_link);
list_remove (sq->proc_list, &proc->suspension_link);
spin_unlock (&sq->lock, &ctxsq);
spin_lock (&proc->lock, &ctxpr);
@@ -397,7 +385,7 @@ void proc_resume (struct proc* proc) {
spin_unlock (&proc->lock, &ctxpr);
spin_lock (&cpu->lock, &ctxcpu);
rbtree_insert (struct proc, &cpu->proc_run_q, &proc->cpu_run_q_link, cpu_run_q_link, pid);
list_append (cpu->proc_run_q, &proc->cpu_run_q_link);
spin_unlock (&cpu->lock, &ctxcpu);
cpu_request_sched (cpu);

View File

@@ -45,8 +45,8 @@ struct proc_resources {
struct proc {
int pid;
struct rb_node_link proc_tree_link;
struct rb_node_link cpu_run_q_link;
struct rb_node_link suspension_link;
struct list_node_link cpu_run_q_link;
struct list_node_link suspension_link;
struct list_node_link reap_link;
struct list_node_link* mappings; /* pd.lock implicitly protects this field */

View File

@@ -43,11 +43,11 @@ void proc_cleanup_resources (struct proc* proc) {
void proc_drop_resource (struct proc* proc, struct proc_resource* resource, bool lock) {
spin_lock_ctx_t ctxrs;
DEBUG ("resource=%p created_by=%d vis=%d type=%d rid=%d refs=%d\n", resource,
resource->created_by_pid, resource->visibility, resource->type, resource->rid,
atomic_load (&resource->refs));
if (atomic_fetch_sub (&resource->refs, 1) == 1) {
DEBUG ("resource=%p created_by=%d vis=%d type=%d rid=%d refs=%d\n", resource,
resource->created_by_pid, resource->visibility, resource->type, resource->rid,
atomic_load (&resource->refs));
switch (resource->visibility) {
case RV_PRIVATE: {
if (lock)

View File

@@ -1,11 +1,11 @@
#ifndef _KERNEL_PROC_SUSPENTION_Q_H
#define _KERNEL_PROC_SUSPENTION_Q_H
#include <libk/rbtree.h>
#include <libk/list.h>
#include <sync/spin_lock.h>
struct proc_suspension_q {
struct rb_node_link* proc_tree;
struct list_node_link* proc_list;
spin_lock_t lock;
};

View File

@@ -177,12 +177,84 @@ DEFINE_SYSCALL (sys_clone) {
return pid;
}
/* int proc_sched (void) */
/* int sched (void) */
DEFINE_SYSCALL (sys_sched) {
proc_sched (regs);
return ST_OK;
}
/* int create_mutex (int mutex_rid, int vis) */
DEFINE_SYSCALL (sys_create_mutex) {
int mutex_rid = (int)a1;
int vis = (int)a2;
if (mutex_rid < 0)
return -ST_BAD_RESOURCE;
if (!(vis == RV_PUBLIC || vis == RV_PRIVATE))
return -ST_BAD_RESOURCE;
struct proc_resource* mutex_resource =
proc_create_resource (proc, mutex_rid, PR_MUTEX, vis, NULL);
if (mutex_resource == NULL)
return -ST_OOM_ERROR;
return mutex_resource->rid;
}
/* int unlink_mutex (int mutex_rid, int vis) */
DEFINE_SYSCALL (sys_unlink_mutex) {
int mutex_rid = (int)a1;
int vis = (int)a2;
if (!(vis == RV_PUBLIC || vis == RV_PRIVATE))
return -ST_BAD_RESOURCE;
struct proc_resource* mutex_resource = proc_find_resource (proc, mutex_rid, vis);
if (mutex_resource == NULL)
return -ST_NOT_FOUND;
proc_drop_resource (proc, mutex_resource, true);
return ST_OK;
}
/* int lock_mutex (int mutex_rid, int vis) */
DEFINE_SYSCALL (sys_lock_mutex) {
int mutex_rid = (int)a1;
int vis = (int)a2;
if (!(vis == RV_PUBLIC || vis == RV_PRIVATE))
return -ST_BAD_RESOURCE;
struct proc_resource* mutex_resource = proc_find_resource (proc, mutex_rid, vis);
if (mutex_resource == NULL)
return -ST_NOT_FOUND;
proc_mutex_lock (proc, &mutex_resource->u.mutex);
return ST_OK;
}
/* int unlock_mutex (int mutex_rid, int vis) */
DEFINE_SYSCALL (sys_unlock_mutex) {
int mutex_rid = (int)a1;
int vis = (int)a2;
if (!(vis == RV_PUBLIC || vis == RV_PRIVATE))
return -ST_BAD_RESOURCE;
struct proc_resource* mutex_resource = proc_find_resource (proc, mutex_rid, vis);
if (mutex_resource == NULL)
return -ST_NOT_FOUND;
return proc_mutex_unlock (proc, &mutex_resource->u.mutex) ? ST_OK : -ST_PERMISSION_ERROR;
}
static syscall_handler_func_t handler_table[] = {
[SYS_QUIT] = &sys_quit,
[SYS_TEST] = &sys_test,
@@ -192,6 +264,10 @@ static syscall_handler_func_t handler_table[] = {
[SYS_SCHED] = &sys_sched,
[SYS_CREATE_MEM] = &sys_create_mem,
[SYS_UNLINK_MEM] = &sys_unlink_mem,
[SYS_CREATE_MUTEX] = &sys_create_mutex,
[SYS_UNLINK_MUTEX] = &sys_unlink_mutex,
[SYS_LOCK_MUTEX] = &sys_lock_mutex,
[SYS_UNLOCK_MUTEX] = &sys_unlock_mutex,
};
syscall_handler_func_t syscall_find_handler (int syscall_num) {

View File

@@ -4,14 +4,18 @@
#include <alloc/liballoc.h>
#include <m/system.h>
#define LIBALLOC_MUTEX 500
static uintptr_t liballoc_map_base = PROC_MAP_BASE;
static int mem_rid_base = 1000000;
void liballoc_init (void) {}
void liballoc_init (void) { create_mutex (LIBALLOC_MUTEX, RV_PRIVATE); }
int liballoc_lock (void) { return 0; }
void liballoc_deinit (void) { unlink_mutex (LIBALLOC_MUTEX, RV_PRIVATE); }
int liballoc_unlock (void) { return 0; }
int liballoc_lock (void) { return lock_mutex (LIBALLOC_MUTEX, RV_PRIVATE); }
int liballoc_unlock (void) { return unlock_mutex (LIBALLOC_MUTEX, RV_PRIVATE); }
void* liballoc_alloc (int pages, int* mem_rid) {
uintptr_t current_base = liballoc_map_base;

View File

@@ -87,6 +87,7 @@ void* calloc (size_t, size_t); //< The standard function.
void free (void*); //< The standard function.
void liballoc_init (void);
void liballoc_deinit (void);
#ifdef __cplusplus
}

View File

@@ -17,8 +17,7 @@ static void clear_bss (void) {
void __premain (void) {
clear_bss ();
liballoc_init ();
app_main ();
liballoc_deinit ();
quit ();
}

View File

@@ -9,10 +9,12 @@
#define do_syscall(...) do_syscall1 (__VA_ARGS__, 0, 0, 0, 0, 0, 0)
int quit (void) { return do_syscall (SYS_QUIT); }
int quit (void) { return do_syscall (SYS_QUIT, 0); }
int test (char c) { return do_syscall (SYS_TEST, c); }
int sched (void) { return do_syscall (SYS_SCHED, 0); }
int map (int mem_rid, int vis, uintptr_t vaddr, uint32_t flags) {
return do_syscall (SYS_MAP, mem_rid, vis, vaddr, flags);
}
@@ -30,3 +32,11 @@ int unlink_mem (int mem_rid, int vis, size_t pages) {
int clone (uintptr_t vstack_top, size_t stack_size, void (*entry) (void)) {
return do_syscall (SYS_CLONE, vstack_top, stack_size, entry);
}
int create_mutex (int mutex_rid, int vis) { return do_syscall (SYS_CREATE_MUTEX, mutex_rid, vis); }
int unlink_mutex (int mutex_rid, int vis) { return do_syscall (SYS_UNLINK_MUTEX, mutex_rid, vis); }
int lock_mutex (int mutex_rid, int vis) { return do_syscall (SYS_LOCK_MUTEX, mutex_rid, vis); }
int unlock_mutex (int mutex_rid, int vis) { return do_syscall (SYS_UNLOCK_MUTEX, mutex_rid, vis); }

View File

@@ -19,10 +19,15 @@
int quit (void);
int test (char c);
int sched (void);
int map (int mem_rid, int vis, uintptr_t vaddr, uint32_t flags);
int unmap (uintptr_t vaddr, size_t pages);
int create_mem (int mem_rid, int vis, size_t pages);
int unlink_mem (int mem_rid, int vis, size_t pages);
int clone (uintptr_t vstack_top, size_t stack_size, void (*entry) (void));
int create_mutex (int mutex_rid, int vis);
int unlink_mutex (int mutex_rid, int vis);
int lock_mutex (int mutex_rid, int vis);
int unlock_mutex (int mutex_rid, int vis);
#endif // _LIBMSL_M_SYSTEM_H