mirror of
https://github.com/subhobhai943/SUB-OS.git
synced 2026-10-25 16:52:29 +00:00
feat(sched): Weave tiered scheduler with real kernel-thread context switching
Replace the state-relabel-only round-robin with the SUB-OS "Weave" scheduler backed by a genuine callee-saved context switch. Threads now actually run on their own kernel stacks instead of merely having their state field rewritten. What was implemented: - sub_ctx_switch(): per-arch assembly (arch/x86_64/cpu/switch.asm, arch/aarch64/cpu/switch.S, arch/armv8i/cpu/switch.S) that saves/restores the callee-saved register set (+ flags on x86_64) on each thread's own stack, plus a first-run trampoline (sub_thread_trampoline) that launches a freshly forged thread frame with entry/arg in callee-saved registers. - task_forge_frame(): builds the initial saved-context frame per arch so the very first switch into a new thread lands on the trampoline; task_t gains a pointer-sized ctx_sp so the same struct works on 64- and 32-bit. - Weave policy (kernel/sched.c): WEAVE_NLANES priority lanes, always dispatch the lowest non-empty lane round-robin; a task that yields voluntarily is woven UP a lane (interactive), one preempted after burning its quantum is woven DOWN (CPU-bound). Cooperative switching (sched_yield / task_exit) is always live; timer-driven preemption is gated behind sched_set_preempt() and left disarmed for now. - task_exit() now switches to the next runnable thread via sched_exit_current() instead of spinning/halting. - Boot-time weave_selftest() (x86_64) and sched_dump() diagnostics. How it was verified: - Builds clean for all three targets: x86_64 (CROSS_COMPILE=x86_64-linux-gnu-, RUSTC="rustc --target x86_64-unknown-none"), aarch64, armv8i. No new warnings; the new x86_64 asm carries a .note.GNU-stack section. - Booted x86_64 under QEMU (TCG): the self-test runs three cooperative kernel threads to completion on separate stacks with the expected 1->2->3 round-robin interleave, reports "20 real context switches, 3/3 workers exited", returns cleanly to the boot thread, and boot proceeds normally to ring-3 init and the shell. No fault/panic. Left unverified: - The aarch64/armv8i sub_ctx_switch frames build and link but are not yet boot-tested on their QEMU targets (tracked in docs/AUTODEV_ROADMAP.md). - Timer preemption path is implemented but disarmed; exited kernel threads currently leak their stack (reaper is next in the backlog). Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01Jk6K69yGS7zYgvoWd6nJxQ
This commit is contained in:
10 files changed
+570
-58
No files matched your search
+40
-3
@@ -3,11 +3,48 @@
|
||||
|
||||
#include "task.h"
|
||||
|
||||
/*
|
||||
* SUB-OS "Weave" scheduler
|
||||
* ------------------------
|
||||
* A distinctive tiered-rotation scheduler rather than a plain run queue. Every
|
||||
* runnable task threads through one of WEAVE_NLANES priority lanes. The
|
||||
* dispatcher always pulls from the lowest-numbered non-empty lane and rotates
|
||||
* round-robin inside it, so latency-sensitive work stays near the front.
|
||||
*
|
||||
* The lane a task sits in is not fixed: a task that gives up the CPU
|
||||
* voluntarily (sched_yield) is treated as interactive and woven UP a lane,
|
||||
* while a task that burns its whole quantum and is preempted (sched_schedule)
|
||||
* is woven DOWN. This lets throughput-bound threads and interactive threads
|
||||
* coexist without either starving, and it is driven entirely by observed
|
||||
* behaviour rather than a static nice value.
|
||||
*
|
||||
* The mechanism underneath is a real callee-saved context switch
|
||||
* (sub_ctx_switch, per-arch assembly); this is genuine multitasking, not a
|
||||
* state relabel.
|
||||
*/
|
||||
|
||||
#define WEAVE_NLANES 4
|
||||
|
||||
void sched_init(void);
|
||||
void sched_yield(void);
|
||||
void sched_schedule(void);
|
||||
void sched_tick(void);
|
||||
void sched_yield(void); /* voluntary: rewards the caller (woven up) */
|
||||
void sched_schedule(void); /* involuntary/preemptive: caller woven down */
|
||||
void sched_tick(void); /* timer hook: charges the running quantum */
|
||||
void sched_add_task(task_t* task);
|
||||
void sched_remove_task(task_t* task);
|
||||
|
||||
/* Let the currently-running context join or leave the run rotation. The kernel
|
||||
* idle/boot thread uses these to briefly participate while it drives a batch
|
||||
* of kernel threads to completion. */
|
||||
void sched_join(void);
|
||||
void sched_leave(void);
|
||||
|
||||
/* Arm or disarm preemptive switching from the timer tick. Cooperative
|
||||
* switching (sched_yield / task_exit) always works; preemption is opt-in so
|
||||
* early boot can run to completion deterministically. */
|
||||
void sched_set_preempt(bool armed);
|
||||
|
||||
/* Diagnostics + the boot-time context-switch self-test. */
|
||||
void sched_dump(void);
|
||||
void weave_selftest(void);
|
||||
|
||||
#endif // _KERNEL_SCHED_H
|
||||
@@ -26,6 +26,20 @@ typedef struct task_struct {
|
||||
int priority;
|
||||
int time_slice;
|
||||
int exit_code;
|
||||
|
||||
/* --- SUB-OS "Weave" scheduler context ---------------------------------
|
||||
* ctx_sp is the saved stack pointer handed to sub_ctx_switch(); it is
|
||||
* pointer-sized so the same struct works on 64- and 32-bit targets.
|
||||
* A task lives in exactly one lane while it is runnable; weave_credit is
|
||||
* the quantum it has left in that lane, and weave_on marks it as an active
|
||||
* participant in the run rotation (so a bare kernel idle task that merely
|
||||
* calls sched_yield() is never enqueued). */
|
||||
void* ctx_sp;
|
||||
uint32_t weave_lane;
|
||||
uint32_t weave_credit;
|
||||
uint64_t sched_runs;
|
||||
uint8_t weave_on;
|
||||
|
||||
struct list_head list;
|
||||
struct list_head all_list;
|
||||
} task_t;
|
||||
|
||||
Reference in new issue
Block a user