From 76b41149bc931e756514ead7e2653db5973ab813 Mon Sep 17 00:00:00 2001 From: Tulio A M Mendes Date: Tue, 10 Feb 2026 00:59:11 -0300 Subject: [PATCH] fix: add rq_enqueue on wake in keyboard, tty, pty drivers keyboard.c, tty.c, pty.c all transition processes from BLOCKED to READY without enqueuing them into the O(1) scheduler runqueue. This causes woken processes to be invisible to rq_pick_next(), leading to starvation until the active/expired swap rescues them. Add sched_enqueue_ready() public API in scheduler.c and call it from all three wake sites. Passes: make, cppcheck, QEMU smoke test (10s, all init tests OK). --- include/process.h | 4 ++++ src/drivers/keyboard.c | 1 + src/kernel/pty.c | 1 + src/kernel/scheduler.c | 9 +++++++++ src/kernel/tty.c | 1 + 5 files changed, 16 insertions(+) diff --git a/include/process.h b/include/process.h index d0ac450e..87f9151f 100644 --- a/include/process.h +++ b/include/process.h @@ -118,6 +118,10 @@ int process_waitpid(int pid, int* status_out, uint32_t options); // Mark current process as exiting and notify/wake a waiter (if any). void process_exit_notify(int status); +// Enqueue a READY process into the active O(1) runqueue. +// Must be called whenever a process transitions to PROCESS_READY from outside scheduler.c. +void sched_enqueue_ready(struct process* p); + // Kill a process (minimal signals). Returns 0 on success or -errno. int process_kill(uint32_t pid, int sig); diff --git a/src/drivers/keyboard.c b/src/drivers/keyboard.c index 7cf2e934..f9501f87 100644 --- a/src/drivers/keyboard.c +++ b/src/drivers/keyboard.c @@ -43,6 +43,7 @@ static void hal_kbd_bridge(char c) { if (kbd_waiter) { if (kbd_waiter->state == PROCESS_BLOCKED) { kbd_waiter->state = PROCESS_READY; + sched_enqueue_ready(kbd_waiter); } kbd_waiter = NULL; } diff --git a/src/kernel/pty.c b/src/kernel/pty.c index 6948588d..2695a636 100644 --- a/src/kernel/pty.c +++ b/src/kernel/pty.c @@ -96,6 +96,7 @@ static void waitq_wake_one(struct process** q, uint32_t* head, uint32_t* tail) { struct process* p = waitq_pop(q, head, tail); if (p && p->state == PROCESS_BLOCKED) { p->state = PROCESS_READY; + sched_enqueue_ready(p); } } diff --git a/src/kernel/scheduler.c b/src/kernel/scheduler.c index 65bb04be..d8c3f698 100644 --- a/src/kernel/scheduler.c +++ b/src/kernel/scheduler.c @@ -91,6 +91,15 @@ static struct process* rq_pick_next(void) { return NULL; // only idle task left } +void sched_enqueue_ready(struct process* p) { + if (!p) return; + uintptr_t flags = spin_lock_irqsave(&sched_lock); + if (p->state == PROCESS_READY) { + rq_enqueue(rq_active, p); + } + spin_unlock_irqrestore(&sched_lock, flags); +} + void thread_wrapper(void (*fn)(void)); static struct process* process_find_locked(uint32_t pid) { diff --git a/src/kernel/tty.c b/src/kernel/tty.c index 74df2cc9..950b846a 100644 --- a/src/kernel/tty.c +++ b/src/kernel/tty.c @@ -168,6 +168,7 @@ static void tty_wake_one(void) { struct process* p = waitq_pop(); if (p && p->state == PROCESS_BLOCKED) { p->state = PROCESS_READY; + sched_enqueue_ready(p); } } -- 2.43.0