rumpk/core/sched.nim

171 lines
5.5 KiB
Nim

# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## Rumpk Layer 1: The Reactive Dispatcher (The Tyrant)
##
## Implements the Silence Doctrine (SPEC-250).
## - No Tick.
## - No Policy.
## - Only Physics.
{.push stackTrace: off, lineTrace: off.}
import fiber
# We might need to access the Fiber globals from fiber.nim
# fiber.nim exports current_fiber, but we need to iterate them.
# Currently kernel.nim manages the specific fibers variables (fiber_ion, fiber_ui, etc.)
# We need a centralized registry or a way to iterate.
#
# For the first pass, we can replicate the logic in kernel.nim which explicitly checks
# the known fibers, but structured as the Spectrum loop.
# Or we can make kernel.nim pass the fibers to us.
#
# Let's keep it simple and stateless in sched.nim if possible, or have it manage the queue.
# Since kernel.nim holds the variables, sched.nim should probably define the *Strategy*
# and kernel.nim calls it, OR sched.nim should import kernel (circular!).
#
# Better: fiber.nim holds a linked list of fibers?
# Or sched.nim is just a helper module that kernel.nim uses.
# Let's define the Strategy here.
# To avoid circular imports, kernel.nim will likely INCLUDE sched.nim or sched.nim
# will act on a passed context.
# BUT, SPEC-250 implies sched.nim *is* the logic.
#
# Let's define the Harmonic logic.
# We need access to `current_fiber` (from fiber.nim) and `get_now_ns` (helper).
proc sched_get_now_ns*(): uint64 {.importc: "get_now_ns", cdecl.}
# Forward declaration for the tick function
# Returns TRUE if a fiber was switched to (work done/found).
# Returns FALSE if the system should sleep (WFI).
proc sched_tick_spectrum*(fibers: openArray[ptr FiberObject]): bool =
let now = sched_get_now_ns()
# =========================================================
# Phase 1: PHOTON (Hard Real-Time / Hardware Driven)
# =========================================================
# - V-Sync (Compositor)
# - Audio Mix
# - Network Polling (War Mode)
var run_photon = false
for f in fibers:
if f != nil and f.getSpectrum() == Spectrum.Photon:
if now >= f.sleep_until:
if f != current_fiber:
switch(f); return true
else:
run_photon = true
if run_photon: return true
# =========================================================
# Phase 2: MATTER (Interactive / Latency Sensitive)
# =========================================================
# - Shell
# - Editor
var run_matter = false
for f in fibers:
if f != nil and f.getSpectrum() == Spectrum.Matter:
if now >= f.sleep_until:
if f != current_fiber:
switch(f); return true
else:
run_matter = true
if run_matter: return true
# =========================================================
# Phase 3: GRAVITY (Throughput / Background)
# =========================================================
# - Compiler
# - Ledger Sync
var run_gravity = false
for f in fibers:
if f != nil and f.getSpectrum() == Spectrum.Gravity:
if now >= f.sleep_until:
if f != current_fiber:
switch(f); return true
else:
run_gravity = true
if run_gravity: return true
# =========================================================
# Phase 4: VOID (Scavenger)
# =========================================================
# - Untrusted Code
# - Speculative Execution
for f in fibers:
if f != nil and f.getSpectrum() == Spectrum.Void:
if now >= f.sleep_until:
if f != current_fiber:
switch(f)
return true
else:
return true
# =========================================================
# THE SILENCE
# =========================================================
# If we reached here, NO fiber is runnable.
return false
# =========================================================
# THE RATCHET (Post-Execution Analysis)
# =========================================================
proc console_write(p: pointer, len: csize_t) {.importc, cdecl.}
proc sched_log(msg: string) =
if msg.len > 0:
console_write(unsafeAddr msg[0], csize_t(msg.len))
proc sched_demote(f: ptr FiberObject) =
## Demote a fiber to a lower Spectrum tier
let current = f.getSpectrum()
case current:
of Spectrum.Photon:
f.setSpectrum(Spectrum.Matter)
console_write(cstring("[Ratchet] DEMOTED fiber to Matter\n"), 34)
of Spectrum.Matter:
f.setSpectrum(Spectrum.Gravity)
console_write(cstring("[Ratchet] DEMOTED fiber to Gravity\n"), 35)
of Spectrum.Gravity:
f.setSpectrum(Spectrum.Void)
console_write(cstring("[Ratchet] DEMOTED fiber to Void\n"), 32)
of Spectrum.Void:
discard # Already at the bottom
proc sched_analyze_burst*(f: ptr FiberObject, burst_ns: uint64) =
## Analyze the burst duration of a fiber after it yields/switches
## Implements the 3-strike rule for budget violations
if f == nil: return
f.last_burst_ns = burst_ns
# Update moving average (exponential: 75% old, 25% new)
if f.avg_burst == 0:
f.avg_burst = burst_ns
else:
f.avg_burst = (f.avg_burst * 3 + burst_ns) div 4
# Budget enforcement
if f.budget_ns > 0 and burst_ns > f.budget_ns:
f.violations += 1
console_write(cstring("[Ratchet] Violation: fiber exceeded budget\n"), 42)
if f.violations >= 3:
sched_demote(f)
f.violations = 0 # Reset after demotion
{.pop.}