feat: P0-P6 kernel scheduler + relibc threading comprehensive implementation

P0-P2: Barrier SMP, sigmask/pthread_kill races, robust mutexes, RT scheduling, POSIX sched API
P3: PerCpuSched struct, per-CPU wiring, work stealing, load balancing, initial placement
P4: 64-shard futex table, REQUEUE, PI futexes (LOCK_PI/UNLOCK_PI/TRYLOCK_PI), robust futexes, vruntime tracking, min-vruntime SCHED_OTHER selection
P5: setpriority/getpriority, pthread_setaffinity_np, pthread_setname_np, pthread_setschedparam (Redox)
P6: Cache-affine scheduling (last_cpu + vruntime bonus), NUMA topology kernel hints + numad userspace daemon

Stability fixes: make_consistent stores 0 (dead TID fix), cond.rs error propagation, SPIN_COUNT adaptive spinning, Sys::open &str fix, PI futex CAS race, proc.rs lock ordering, barrier destroy

Patches: 33 kernel + 58 relibc patches, all tracked in recipes
Docs: KERNEL-SCHEDULER-MULTITHREAD-IMPROVEMENT-PLAN.md updated, SCHEDULER-REVIEW-FINAL.md created
Architecture: NUMA topology parsing stays userspace (numad daemon), kernel stores lightweight NumaTopology hints
This commit is contained in:
2026-04-30 18:21:48 +01:00
parent 55d00c3a24
commit 34360e1e4f
70 changed files with 15268 additions and 10 deletions
@@ -0,0 +1,56 @@
diff --git a/src/context/mod.rs b/src/context/mod.rs
--- a/src/context/mod.rs
+++ b/src/context/mod.rs
@@ -10,9 +10,9 @@ use core::{num::NonZeroUsize, ops::Deref};
use crate::{
context::memory::AddrSpaceWrapper,
- cpu_set::LogicalCpuSet,
+ cpu_set::{LogicalCpuId, LogicalCpuSet},
memory::{RmmA, RmmArch, TableKind},
- percpu::PercpuBlock,
+ percpu::{get_percpu_block, PercpuBlock},
sync::{
ArcRwLockWriteGuard, CleanLockToken, LockToken, Mutex, MutexGuard, RwLock, RwLockReadGuard,
RwLockWriteGuard, L0, L1, L2, L4,
@@ -118,6 +118,30 @@ pub fn run_contexts(token: LockToken<'_, L0>) -> MutexGuard<'_, L1, RunContextDa
RUN_CONTEXTS.lock(token)
}
+fn least_loaded_cpu() -> LogicalCpuId {
+ let current_cpu = crate::cpu_id();
+ let mut best_cpu = current_cpu;
+ let mut best_depth = usize::MAX;
+
+ for raw_id in 0..crate::cpu_count() {
+ let cpu_id = LogicalCpuId::new(raw_id);
+ let Some(percpu) = get_percpu_block(cpu_id) else {
+ continue;
+ };
+
+ percpu.sched.take_lock();
+ let depth = unsafe { percpu.sched.queues().iter().map(|queue| queue.len()).sum() };
+ percpu.sched.release_lock();
+
+ if depth < best_depth {
+ best_depth = depth;
+ best_cpu = cpu_id;
+ }
+ }
+
+ best_cpu
+}
+
pub fn init(token: &mut CleanLockToken) {
let owner = None; // kmain not owned by any fd
let mut context = Context::new(owner).expect("failed to create kmain context");
@@ -238,6 +262,9 @@ pub fn spawn(
context.kstack = Some(stack);
context.userspace = userspace_allowed;
+ let target_cpu = least_loaded_cpu();
+ context.sched_affinity = LogicalCpuSet::empty();
+ context.sched_affinity.atomic_set(target_cpu);
let context_lock = Arc::new(ContextLock::new(context));
let context_ref = ContextRef(Arc::clone(&context_lock));