From 41a458b9258d97b212989e8ab1245dced646fc37 Mon Sep 17 00:00:00 2001 From: kamkow1 Date: Sat, 10 Jan 2026 00:12:42 +0100 Subject: [PATCH] Implement Mutexes and supporting syscalls, cleanup/optimize scheduler --- include/m/syscall_defs.h | 4 ++ init/init.c | 10 +++ kernel/amd64/mm.c | 4 -- kernel/amd64/proc.c | 2 +- kernel/amd64/smp.c | 4 +- kernel/amd64/smp.h | 4 +- kernel/proc/mutex.c | 42 ++++++++++++ kernel/proc/mutex.h | 19 ++++++ kernel/proc/proc.c | 131 +++++++++++++++++++++++-------------- kernel/proc/proc.h | 8 +-- kernel/proc/resource.c | 26 +++++++- kernel/proc/resource.h | 7 +- kernel/proc/src.mk | 10 +-- kernel/proc/suspension_q.h | 12 ++++ kernel/syscall/syscall.c | 51 +++++++++++++++ libmsl/m/proc.c | 12 ++++ libmsl/m/proc.h | 3 + 17 files changed, 276 insertions(+), 73 deletions(-) create mode 100644 kernel/proc/mutex.c create mode 100644 kernel/proc/mutex.h create mode 100644 kernel/proc/suspension_q.h diff --git a/include/m/syscall_defs.h b/include/m/syscall_defs.h index 625bd51..9a54233 100644 --- a/include/m/syscall_defs.h +++ b/include/m/syscall_defs.h @@ -7,6 +7,9 @@ #define SYS_PROC_UNMAP 4 #define SYS_PROC_CREATE_RESOURCE_MEM 5 #define SYS_PROC_DROP_RESOURCE 6 +#define SYS_PROC_CREATE_RESOURCE_MUTEX 7 +#define SYS_PROC_MUTEX_LOCK 8 +#define SYS_PROC_MUTEX_UNLOCK 9 #define SR_OK 0 #define SR_SYSCALL_NOT_FOUND 1 @@ -14,5 +17,6 @@ #define SR_OOM_ERROR 3 #define SR_NOT_FOUND 4 #define SR_BAD_ADDRESS_SPACE 5 +#define SR_PERMISSION_ERROR 6 #endif // _M_SYSCALL_DEFS_H diff --git a/init/init.c b/init/init.c index 9e58855..086efeb 100644 --- a/init/init.c +++ b/init/init.c @@ -15,4 +15,14 @@ void app_main (void) { m_proc_unmap (M_PROC_MAP_BASE, 16); m_proc_drop_resource (mem_rid); + + /* m_proc_test (); */ + + int mutex_rid = m_proc_create_resource_mutex (RV_PRIVATE); + + m_proc_mutex_lock (mutex_rid); + /* m_proc_test (); */ + m_proc_mutex_unlock (mutex_rid); + + /* m_proc_test (); */ } diff --git a/kernel/amd64/mm.c b/kernel/amd64/mm.c index 0b186c2..ec32c5f 100644 --- a/kernel/amd64/mm.c +++ b/kernel/amd64/mm.c @@ -240,15 +240,11 @@ uintptr_t mm_alloc_user_pd_phys (void) { /* Reload after map/unmap operation was performed. This function does the TLB shootdown. */ void mm_reload (void) { - spin_lock (&mm_lock); - struct limine_mp_response* mp = limine_mp_request.response; for (size_t i = 0; i < mp->cpu_count; i++) { amd64_lapic_ipi (mp->cpus[i]->lapic_id, TLB_SHOOTDOWN); } - - spin_unlock (&mm_lock); } bool mm_validate (struct pd* pd, uintptr_t vaddr, uint32_t flags) { diff --git a/kernel/amd64/proc.c b/kernel/amd64/proc.c index 4ac570e..e1a56ce 100644 --- a/kernel/amd64/proc.c +++ b/kernel/amd64/proc.c @@ -50,7 +50,7 @@ struct proc* proc_from_elf (uint8_t* elf_contents) { struct proc_resource* ustk_r = proc_create_resource (proc, ustk_rid, PR_MEM, RV_PRIVATE, (void*)&ustk_mem_init); if (ustk_r == NULL) { - kstk_r->ops.cleanup (kstk_r); + kstk_r->ops.cleanup (proc, kstk_r); free (kstk_r); free (proc); return NULL; diff --git a/kernel/amd64/smp.c b/kernel/amd64/smp.c index f020193..da614cc 100644 --- a/kernel/amd64/smp.c +++ b/kernel/amd64/smp.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include #include @@ -27,7 +27,7 @@ struct cpu* cpu_make (void) { struct cpu* cpu = &cpus[id]; memset (cpu, 0, sizeof (*cpu)); - cpu->lock = RW_SPIN_LOCK_INIT; + cpu->lock = SPIN_LOCK_INIT; cpu->id = id; cpu->self = cpu; diff --git a/kernel/amd64/smp.h b/kernel/amd64/smp.h index d6a8eaa..ad35016 100644 --- a/kernel/amd64/smp.h +++ b/kernel/amd64/smp.h @@ -7,7 +7,7 @@ #include #include #include -#include +#include #define CPUS_MAX 32 @@ -30,7 +30,7 @@ struct cpu { atomic_int nesting; } irq_ctx; - rw_spin_lock_t lock; + spin_lock_t lock; struct rb_node_link* proc_run_q; struct proc* proc_current; diff --git a/kernel/proc/mutex.c b/kernel/proc/mutex.c new file mode 100644 index 0000000..17fa672 --- /dev/null +++ b/kernel/proc/mutex.c @@ -0,0 +1,42 @@ +#include +#include +#include +#include +#include +#include +#include + +void proc_mutex_lock (struct proc* proc, struct proc_mutex* mutex) { + while (atomic_flag_test_and_set_explicit (&mutex->flag, memory_order_acquire)) + proc_suspend (proc, &mutex->suspension_q); + + /* taken */ + + mutex->owner = proc; +} + +bool proc_mutex_unlock (struct proc* proc, struct proc_mutex* mutex) { + if (mutex->owner != proc) + return false; + + atomic_flag_clear_explicit (&mutex->flag, memory_order_release); + + struct proc* resumed_proc; + struct rb_node_link* node; + rbtree_first (&mutex->suspension_q.proc_tree, node); + + while (node) { + struct rb_node_link* next; + rbtree_next (node, next); + + resumed_proc = rbtree_entry (node, struct proc, suspension_link); + + proc_resume (resumed_proc); + + node = next; + } + + assert (mutex->suspension_q.proc_tree == NULL); + + return true; +} diff --git a/kernel/proc/mutex.h b/kernel/proc/mutex.h new file mode 100644 index 0000000..724a2dd --- /dev/null +++ b/kernel/proc/mutex.h @@ -0,0 +1,19 @@ +#ifndef _KERNEL_PROC_MUTEX_H +#define _KERNEL_PROC_MUTEX_H + +#include +#include +#include + +struct proc; + +struct proc_mutex { + atomic_flag flag; + struct proc_suspension_q suspension_q; + struct proc* owner; +}; + +void proc_mutex_lock (struct proc* proc, struct proc_mutex* mutex); +bool proc_mutex_unlock (struct proc* proc, struct proc_mutex* mutex); + +#endif // _KERNEL_PROC_MUTEX_H diff --git a/kernel/proc/proc.c b/kernel/proc/proc.c index 78e696f..03346f2 100644 --- a/kernel/proc/proc.c +++ b/kernel/proc/proc.c @@ -25,6 +25,8 @@ #include #endif +#define SCHED_REAP_FREQ 200 + /* * Lock hierachy: * - proc_tree_lock @@ -36,6 +38,8 @@ static struct rb_node_link* proc_tree = NULL; static rw_spin_lock_t proc_tree_lock = RW_SPIN_LOCK_INIT; +static atomic_int sched_cycles = 0; + static bool proc_check_elf (uint8_t* elf) { if (!((elf[0] == 0x7F) && (elf[1] == 'E') && (elf[2] == 'L') && (elf[3] == 'F'))) return false; @@ -194,29 +198,30 @@ static struct proc* proc_spawn_rd (char* name) { static void proc_register (struct proc* proc, struct cpu* cpu) { proc->cpu = cpu; - rw_spin_write_lock (&proc_tree_lock); - rw_spin_write_lock (&cpu->lock); - + spin_lock (&cpu->lock); rbtree_insert (struct proc, &cpu->proc_run_q, &proc->cpu_run_q_link, cpu_run_q_link, pid); - rbtree_insert (struct proc, &proc_tree, &proc->proc_tree_link, proc_tree_link, pid); if (cpu->proc_current == NULL) cpu->proc_current = proc; - rw_spin_write_unlock (&cpu->lock); + spin_unlock (&cpu->lock); + + rw_spin_write_lock (&proc_tree_lock); + rbtree_insert (struct proc, &proc_tree, &proc->proc_tree_link, proc_tree_link, pid); rw_spin_write_unlock (&proc_tree_lock); } -static struct proc* proc_find_sched (void) { +/* caller holds cpu->lock */ +static struct proc* proc_find_sched (struct cpu* cpu) { struct rb_node_link* node = NULL; - struct proc* start = thiscpu->proc_current; + struct proc* start = cpu->proc_current; struct proc* proc = NULL; if (start) node = &start->cpu_run_q_link; if (!node) - rbtree_first (&thiscpu->proc_run_q, node); + rbtree_first (&cpu->proc_run_q, node); if (!node) return NULL; @@ -231,7 +236,7 @@ static struct proc* proc_find_sched (void) { rbtree_next (node, node); if (!node) { - rbtree_first (&thiscpu->proc_run_q, node); + rbtree_first (&cpu->proc_run_q, node); } if (node == first) @@ -241,51 +246,81 @@ static struct proc* proc_find_sched (void) { return NULL; } +static void proc_reap (void) { + struct proc* proc = NULL; + struct list_node_link* reap_list = NULL; + + rw_spin_write_lock (&proc_tree_lock); + + struct rb_node_link* node; + rbtree_first (&proc_tree, node); + + while (node) { + struct rb_node_link* next; + rbtree_next (node, next); + proc = rbtree_entry (node, struct proc, proc_tree_link); + + if (atomic_load (&proc->state) == PROC_DEAD) { + spin_lock (&proc->lock); + rbtree_delete (&proc_tree, &proc->proc_tree_link); + spin_unlock (&proc->lock); + + list_append (reap_list, &proc->reap_link); + } + + node = next; + } + + rw_spin_write_unlock (&proc_tree_lock); + + struct list_node_link *reap_link, *reap_link_tmp; + list_foreach (reap_list, reap_link, reap_link_tmp) { + proc = list_entry (reap_link, struct proc, reap_link); + + list_remove (reap_list, &proc->reap_link); + DEBUG ("cleanup PID %d\n", proc->pid); + proc_cleanup (proc); + } +} + void proc_sched (void) { + if (atomic_fetch_add (&sched_cycles, 1) % SCHED_REAP_FREQ == 0) + proc_reap (); + struct proc* next = NULL; + struct cpu* cpu = thiscpu; - rw_spin_read_lock (&thiscpu->lock); + spin_lock (&cpu->lock); - if (thiscpu->proc_run_q == NULL) { - rw_spin_read_unlock (&thiscpu->lock); - goto idle; + if (cpu->proc_run_q != NULL) { + next = proc_find_sched (cpu); + if (next) + cpu->proc_current = next; } - next = proc_find_sched (); + spin_unlock (&thiscpu->lock); - rw_spin_read_unlock (&thiscpu->lock); - - if (next != NULL) { - rw_spin_write_lock (&thiscpu->lock); - thiscpu->proc_current = next; - rw_spin_write_unlock (&thiscpu->lock); - } - - if (next != NULL && atomic_load (&next->state) == PROC_READY) + if ((next != NULL) && (atomic_load (&next->state) == PROC_READY)) do_sched (next); -idle: spin (); } void proc_kill (struct proc* proc) { atomic_store (&proc->state, PROC_DEAD); - rw_spin_write_lock (&proc_tree_lock); - spin_lock (&proc->lock); - rbtree_delete (&proc_tree, &proc->proc_tree_link); - spin_unlock (&proc->lock); - rw_spin_write_unlock (&proc_tree_lock); - struct cpu* cpu = proc->cpu; - rw_spin_write_lock (&cpu->lock); + + spin_lock (&cpu->lock); + rbtree_delete (&cpu->proc_run_q, &proc->cpu_run_q_link); - rw_spin_write_unlock (&cpu->lock); + if (cpu->proc_current == proc) + cpu->proc_current = NULL; + + spin_unlock (&cpu->lock); DEBUG ("killed PID %d\n", proc->pid); - proc_cleanup (proc); - if (cpu == thiscpu) proc_sched (); else @@ -293,22 +328,20 @@ void proc_kill (struct proc* proc) { } void proc_suspend (struct proc* proc, struct proc_suspension_q* sq) { - struct cpu* cpu; - spin_lock (&proc->lock); - atomic_store (&proc->state, PROC_SUSPENDED); - cpu = proc->cpu; + struct cpu* cpu = proc->cpu; /* remove from run q */ - rw_spin_write_lock (&cpu->lock); + spin_lock (&cpu->lock); rbtree_delete (&cpu->proc_run_q, &proc->cpu_run_q_link); if (cpu->proc_current == proc) cpu->proc_current = NULL; - rw_spin_write_unlock (&cpu->lock); + spin_unlock (&cpu->lock); proc->suspension_q = sq; + spin_lock (&proc->suspension_q->lock); rbtree_insert (struct proc, &proc->suspension_q->proc_tree, &proc->suspension_link, suspension_link, pid); @@ -319,25 +352,23 @@ void proc_suspend (struct proc* proc, struct proc_suspension_q* sq) { cpu_request_sched (cpu); } -void proc_wakeup (struct proc* proc) { - struct cpu* cpu; - +void proc_resume (struct proc* proc) { spin_lock (&proc->lock); - cpu = proc->cpu; + struct cpu* cpu = proc->cpu; + struct proc_suspension_q* sq = proc->suspension_q; - spin_lock (&proc->suspension_q->lock); - rbtree_delete (&proc->suspension_q->proc_tree, &proc->suspension_link); - spin_unlock (&proc->suspension_q->lock); + spin_lock (&sq->lock); + rbtree_delete (&sq->proc_tree, &proc->suspension_link); + spin_unlock (&sq->lock); proc->suspension_q = NULL; - rw_spin_write_lock (&cpu->lock); + spin_lock (&cpu->lock); rbtree_insert (struct proc, &cpu->proc_run_q, &proc->cpu_run_q_link, cpu_run_q_link, pid); - rw_spin_write_unlock (&cpu->lock); + spin_unlock (&cpu->lock); atomic_store (&proc->state, PROC_READY); - spin_unlock (&proc->lock); cpu_request_sched (cpu); diff --git a/kernel/proc/proc.h b/kernel/proc/proc.h index df8dad5..13e3f05 100644 --- a/kernel/proc/proc.h +++ b/kernel/proc/proc.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -39,6 +40,7 @@ struct proc { 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 reap_link; struct list_node_link* mappings; /* pd.lock implicitly protects this field */ struct proc_platformdata pdata; @@ -51,12 +53,8 @@ struct proc { struct proc_suspension_q* suspension_q; }; -struct proc_suspension_q { - struct rb_node_link* proc_tree; - spin_lock_t lock; -}; - void proc_suspend (struct proc* proc, struct proc_suspension_q* sq); +void proc_resume (struct proc* proc); void proc_sched (void); void proc_kill (struct proc* proc); bool proc_map (struct proc* proc, uintptr_t start_paddr, uintptr_t start_vaddr, size_t pages, diff --git a/kernel/proc/resource.c b/kernel/proc/resource.c index 195a654..6237c1c 100644 --- a/kernel/proc/resource.c +++ b/kernel/proc/resource.c @@ -4,7 +4,9 @@ #include #include #include +#include #include +#include #include #include @@ -33,7 +35,7 @@ void proc_drop_resource (struct proc* proc, struct proc_resource* resource) { rbtree_delete (&proc->resource_tree, &resource->proc_resource_tree_link); spin_unlock (&proc->lock); - resource->ops.cleanup (resource); + resource->ops.cleanup (proc, resource); free (resource); } } @@ -53,10 +55,23 @@ static bool proc_create_resource_mem (struct proc_resource_mem* mem, return true; } -static void proc_cleanup_resource_mem (struct proc_resource* resource) { +static void proc_cleanup_resource_mem (struct proc* proc, struct proc_resource* resource) { + (void)proc; pmm_free (resource->u.mem.paddr, resource->u.mem.pages); } +static bool proc_create_resource_mutex (struct proc_mutex* mutex) { + memset (mutex, 0, sizeof (*mutex)); + + return true; +} + +static void proc_cleanup_resource_mutex (struct proc* proc, struct proc_resource* resource) { + struct proc_mutex* mutex = &resource->u.mutex; + + proc_mutex_unlock (proc, mutex); +} + struct proc_resource* proc_create_resource (struct proc* proc, int rid, int type, int vis, void* data) { /* Check if resource RID already exists */ @@ -83,9 +98,14 @@ struct proc_resource* proc_create_resource (struct proc* proc, int rid, int type struct proc_resource_mem_init* mem_init = data; proc_create_resource_mem (&resource->u.mem, mem_init); resource->ops.cleanup = &proc_cleanup_resource_mem; - DEBUG ("resource=%p type=%d rid=%d paddr=%p, pages=%zu\n", resource, resource->type, + DEBUG ("PR_MEM resource=%p type=%d rid=%d paddr=%p, pages=%zu\n", resource, resource->type, resource->rid, resource->u.mem.paddr, resource->u.mem.pages); } break; + case PR_MUTEX: { + proc_create_resource_mutex (&resource->u.mutex); + resource->ops.cleanup = &proc_cleanup_resource_mutex; + DEBUG ("PR_MUTEX resource=%p, type=%d rid=%d\n", resource, resource->type, resource->rid); + } break; default: { free (resource); return NULL; diff --git a/kernel/proc/resource.h b/kernel/proc/resource.h index 678bdec..9535487 100644 --- a/kernel/proc/resource.h +++ b/kernel/proc/resource.h @@ -3,9 +3,11 @@ #include #include +#include #include -#define PR_MEM 0 +#define PR_MEM 0 +#define PR_MUTEX 1 #define RV_PRIVATE 0 #define RV_PUBLIC 1 @@ -30,9 +32,10 @@ struct proc_resource { struct rb_node_link proc_resource_tree_link; union { struct proc_resource_mem mem; + struct proc_mutex mutex; } u; struct { - void (*cleanup) (struct proc_resource* resource); + void (*cleanup) (struct proc* proc, struct proc_resource* resource); } ops; }; diff --git a/kernel/proc/src.mk b/kernel/proc/src.mk index 156627c..db5603a 100644 --- a/kernel/proc/src.mk +++ b/kernel/proc/src.mk @@ -1,5 +1,7 @@ -c += proc/proc.c -c += proc/resource.c +c += proc/proc.c \ + proc/resource.c \ + proc/mutex.c -o += proc/proc.o -o += proc/resource.o +o += proc/proc.o \ + proc/resource.o \ + proc/mutex.o diff --git a/kernel/proc/suspension_q.h b/kernel/proc/suspension_q.h new file mode 100644 index 0000000..02e4fe7 --- /dev/null +++ b/kernel/proc/suspension_q.h @@ -0,0 +1,12 @@ +#ifndef _KERNEL_PROC_SUSPENTION_Q_H +#define _KERNEL_PROC_SUSPENTION_Q_H + +#include +#include + +struct proc_suspension_q { + struct rb_node_link* proc_tree; + spin_lock_t lock; +}; + +#endif // _KERNEL_PROC_SUSPENTION_Q_H diff --git a/kernel/syscall/syscall.c b/kernel/syscall/syscall.c index 993adce..d1eac5b 100644 --- a/kernel/syscall/syscall.c +++ b/kernel/syscall/syscall.c @@ -3,7 +3,10 @@ #include #include #include +#include #include +#include +#include #include #include #include @@ -87,6 +90,51 @@ DEFINE_SYSCALL (sys_proc_create_resource_mem) { } } +/* int proc_create_resource_mutex (int vis) */ +DEFINE_SYSCALL (sys_proc_create_resource_mutex) { + int vis = (int)a1; + + int rid = atomic_fetch_add (&proc->rids, 1); + struct proc_resource* r = proc_create_resource (proc, rid, PR_MUTEX, vis, NULL); + if (r != NULL) + return r->rid; + else + return -SR_OOM_ERROR; +} + +/* int proc_mutex_lock (int mutex_rid) */ +DEFINE_SYSCALL (sys_proc_mutex_lock) { + int rid = (int)a1; + + struct proc_resource* resource; + spin_lock (&proc->lock); + rbtree_find (struct proc_resource, &proc->resource_tree, rid, resource, proc_resource_tree_link, + rid); + spin_unlock (&proc->lock); + + if (resource == NULL) + return -SR_NOT_FOUND; + + proc_mutex_lock (proc, &resource->u.mutex); + + return SR_OK; +} + +DEFINE_SYSCALL (sys_proc_mutex_unlock) { + int rid = (int)a1; + + struct proc_resource* resource; + spin_lock (&proc->lock); + rbtree_find (struct proc_resource, &proc->resource_tree, rid, resource, proc_resource_tree_link, + rid); + spin_unlock (&proc->lock); + + if (resource == NULL) + return -SR_NOT_FOUND; + + return proc_mutex_unlock (proc, &resource->u.mutex) ? SR_OK : -SR_PERMISSION_ERROR; +} + /* int proc_drop_resource (int rid) */ DEFINE_SYSCALL (sys_proc_drop_resource) { int rid = (int)a1; @@ -112,6 +160,9 @@ static syscall_handler_func_t handler_table[] = { [SYS_PROC_UNMAP] = &sys_proc_unmap, [SYS_PROC_CREATE_RESOURCE_MEM] = &sys_proc_create_resource_mem, [SYS_PROC_DROP_RESOURCE] = &sys_proc_drop_resource, + [SYS_PROC_CREATE_RESOURCE_MUTEX] = &sys_proc_create_resource_mutex, + [SYS_PROC_MUTEX_LOCK] = &sys_proc_mutex_lock, + [SYS_PROC_MUTEX_UNLOCK] = &sys_proc_mutex_unlock, }; syscall_handler_func_t syscall_find_handler (int syscall_num) { diff --git a/libmsl/m/proc.c b/libmsl/m/proc.c index 84dec6b..1369868 100644 --- a/libmsl/m/proc.c +++ b/libmsl/m/proc.c @@ -23,3 +23,15 @@ int m_proc_create_resource_mem (size_t pages, int vis, uintptr_t* out_paddr) { int m_proc_drop_resource (int rid) { return m_syscall (SYS_PROC_DROP_RESOURCE, (uintptr_t)rid, 0, 0, 0, 0, 0); } + +int m_proc_create_resource_mutex (int vis) { + return m_syscall (SYS_PROC_CREATE_RESOURCE_MUTEX, (uintptr_t)vis, 0, 0, 0, 0, 0); +} + +int m_proc_mutex_lock (int mutex_rid) { + return m_syscall (SYS_PROC_MUTEX_LOCK, (uintptr_t)mutex_rid, 0, 0, 0, 0, 0); +} + +int m_proc_mutex_unlock (int mutex_rid) { + return m_syscall (SYS_PROC_MUTEX_UNLOCK, (uintptr_t)mutex_rid, 0, 0, 0, 0, 0); +} diff --git a/libmsl/m/proc.h b/libmsl/m/proc.h index 476c9b8..f876ead 100644 --- a/libmsl/m/proc.h +++ b/libmsl/m/proc.h @@ -22,5 +22,8 @@ int m_proc_map (uintptr_t paddr, uintptr_t vaddr, size_t pages, uint32_t flags); int m_proc_unmap (uintptr_t vaddr, size_t pages); int m_proc_create_resource_mem (size_t pages, int vis, uintptr_t* out_paddr); int m_proc_drop_resource (int rid); +int m_proc_create_resource_mutex (int vis); +int m_proc_mutex_lock (int mutex_rid); +int m_proc_mutex_unlock (int mutex_rid); #endif // _LIBMSL_M_PROC_H