Zum Inhalt

Jade VM-Scheduler & Intrinsic-Grenze

Status: Konsolidierter normativer Entwurf
Version: 0.3.0
Datum: 2026-09-23
Geltungsbereich: Tasks, Scheduling, Suspension, I/O-Wakeup, Timer, Engine-Runtime-Konfiguration, native Ausführung außerhalb der Worker und Scheduler-Intrinsics
Bezieht sich auf: Runtime-Modell (03), VM Instruction Set (05), Intrinsics & VM API (08), JadeValue/Register-Layout (11), IR (13), Effect Rows & Throw[E], Fehlermodell, FFI-Spec, JME-/Handle-Vertrag
Ring-Zugehörigkeit: Scheduler Ring 0; JDL-/Stdlib-Abstraktionen darüber Ring 1/2
Host: Zig; konkrete Zig-Strukturen sind nicht Teil des Vertrags


1. Architektur

Der Scheduler ist Teil der Jade VM. Er führt M leichtgewichtige Tasks auf N konfigurierbaren Worker-Threads aus.

Zwei Fragen bleiben getrennt:

Task wird wieder lauffähig:
    Event oder Zeit

Lauffähige Task bekommt CPU:
    Run Queue / Worker / Reduction-Budget
 Event-/I/O-Poller        Master Clock
         │                     │
         ▼                     ▼
   Event-Wakeup          Engine Timer-Wheel
         │                     │
         └─────────┬───────────┘
                   ▼
                Runnable
                   │
                   ▼
            Worker / Run Queue
                   │
                   ▼
                 VM Loop

1.1 M:N und Work-Stealing

Work-Stealing ist die vorgesehene Mehrworker-Strategie. Eine Referenzreihenfolge für Worker ist:

  1. lokale Run Queue,
  2. globale Inject-/Wakeup-Queue,
  3. Work-Stealing,
  4. Worker parken.

Deque-Typ, Steal-Größe und Victim-Auswahl sind Implementierungsdetails. Die beobachtbare Semantik einer Jade-Task darf nicht davon abhängen, auf welchem Worker sie ausgeführt wird.

Native Ausführungsanforderungen ändern diese Regel nicht. Ein nativer Aufruf mit fester Affinität wird nicht an einen Worker gebunden, sondern außerhalb des Worker-Pools auf einer NativeExecutionLane ausgeführt (§1.3). Nach seiner Rückkehr darf die wartende Jade-Task auf einem beliebigen Worker fortgesetzt werden.

1.2 Event-Poller und Clock

Der Event-/I/O-Poller übersetzt externe Completions in Scheduler-Wakeups. Die konkrete OS-Anbindung (epoll, io_uring, kqueue, IOCP oder äquivalent) ist Plattformdetail.

Die Master Clock bedient ausschließlich aktive Timer-Wheels. Der Scheduler besitzt keinen globalen Heartbeat. Ohne Arbeit, Events oder aktive Timer darf die Runtime schlafen.

1.3 Native Ausführung außerhalb der Worker

Worker-Threads führen Jade-Tasks aus. Native Aufrufe dürfen davon getrennte Host-Threads verwenden, wenn ihr materialisierter Vertrag das verlangt. Dafür gibt es zwei mechanische Formen:

NativeExecutionLane
    genau ein Host-Thread
    führt native Aufrufe nacheinander aus
    kann mehrere AffinityDomains bedienen

NativeBlockingPool
    kleiner Vorrat an Host-Threads
    führt blockierende native Aufrufe ohne feste Affinität aus

Threads beider Formen sind keine Worker. Auf ihnen läuft keine Jade-Task und kein VM-Loop für Benutzercode.

Ein fertiger nativer Aufruf wird wie jede andere externe Completion in einen Scheduler-Wakeup übersetzt.

                    Jade-Tasks
                        │
                 Worker-Pool (M:N)
                   │         │
      native direct│         │ Task wartet
                   │         ├──────── NativeBlockingPool
                   │         └──────── NativeExecutionLane
                   │                        │
                   │                   Completion
                   │                        ▼
                   └──────────────────── Wakeup

Was ein nativer Aufruf verlangt, entscheidet nicht der Scheduler. Er liest es aus dem materialisierten FFI-Vertrag (§3.7). Die Wahrheit über Handles, ihre AffinityDomain und ihren Exklusiv-Zustand, gehört der JME.


2. Task-Modell

Eine Task ist die kleinste vom Scheduler verwaltete, suspendierbare VM-Ausführungseinheit.

Konzeptionell:

Task
    id
    schedulingState
    executionState      // IP, Frames, Register
    reductions
    engineId
    waitCondition?
    nativeEntryToken?
    cancellationRequested
    outcome?

nativeEntryToken ist die mechanische Identität eines laufenden nativen Eintrittspfads (§3.11). Er ist kein JDL-Wert und keine Autorität. Eine Task trägt ihn gegebenenfalls; er gehört nicht ihr.

2.1 Schedulerzustand und Ausgang

Schedulerzustand:

Runnable
Running
Waiting
Completed

Task-Ausgang:

Success(value)
Failure(error)      // materialisierter Throw[E]
Trap(info)
Cancelled

Beides sind getrennte Dimensionen. Completed bedeutet nicht automatisch Erfolg.

stateDiagram-v2
    [*] --> Runnable: spawn
    Runnable --> Running: dispatch
    Running --> Runnable: preemption / yield
    Running --> Waiting: event / timer
    Waiting --> Runnable: wakeup / cancellation
    Running --> Completed: return / throw / trap / cancellation
    Completed --> [*]

2.2 Task-Grenze und Throw[E]

Ein Throw[E] darf nicht durch den Stack einer anderen Task unwinden.

Throw[E] im Child
      ↓
Task-Grenze
      ↓
materialisierter Failure-Ausgang

Eine Join-/Wait-Abstraktion darf den Fehler im wartenden Task wieder lokal als Throw[E] erzeugen. Die konkrete JDL-Task-API wird separat spezifiziert.

Throw[E], Trap und Cancellation bleiben getrennt.

2.3 Task vs. Actor

Tasks besitzen keine eingebaute Mailbox und keine Supervision.

Task
    VM-Ausführungseinheit

Actor
    Task + State + Mailbox + Supervision

Actors, Channels und Mailboxes dürfen generische Wait-/Wakeup-Mechanismen verwenden, gehören aber nicht zum Scheduler-Core.


3. Scheduling und Suspension

3.1 Reduction-basierte Fairness

Jede laufende Task besitzt ein Reduction-Budget aus ihrer EngineRuntimeConfig.

Bei erschöpftem Budget wird die Task an einem VM-sicheren Preemption-Point gespeichert und erneut als Runnable eingereiht.

Das ist keine willkürliche OS-Präemption in nativen Code. Eine dauerhaft runnable Task darf andere runnable Tasks nicht dauerhaft verdrängen.

3.2 Event-getriebene Suspension

Muss eine Operation warten, registriert die Runtime eine Wait-Condition und setzt die aktuelle Task auf Waiting.

Operation
   ↓
Ergebnis nicht verfügbar
   ↓
Wait-Condition registrieren
   ↓
Waiting
   ↓ Event
Runnable

Der Scheduler kennt nur die Wait-/Wakeup-Identität, nicht die fachliche Bedeutung des Events.

3.3 Suspension ist kein Result

VM-interner Ausführungskontrollfluss muss mindestens unterscheiden können zwischen:

Completed(value)
Suspended(waitCondition)
Trap(info)

Die konkrete Struktur ist Implementierungsdetail.

Die frühere Form JadeResult.yield() ist kein JDL-Result[T,E] und wird nicht als Fehlersemantik verwendet.

3.4 Transparente Suspension in JDL

JDL besitzt keine spezielle async-Funktionsklasse und benötigt für normale Service-Aufrufe keine async/await-Schlüsselwörter.

def loadConfig(path: Path) ->{Fs, Throw[IoError]} Config {
    val data = Fs.read(path)
    parseConfig(data)
}

Fs.read darf die aktuelle Task suspendieren. Die Funktion bleibt eine normale JDL-Funktion.

Effect Row:
    semantische Anforderungen und propagierbare Effekte

Scheduler:
    wann die Berechnung weiterlaufen kann

Suspendierbarkeit ist kein Row-Element; es gibt keinen Async-Effekt.

3.5 Explizite Parallelität

Suspension erzeugt keine neue Task. Parallele Arbeit wird explizit durch Task-Erzeugung gestartet, konzeptionell über spawn.

// exemplarisch; Oberfläche separat zu spezifizieren
val first = spawn { load("a") }
val b = load("b")
val a = first.join()

Task-Captures unterliegen den normalen Ownership-/Sharing-Regeln der Task-Grenze.

3.6 Cancellation

Cancellation ist kooperativer Scheduler-Kontrollfluss und kein Throw[E].

  • die Anforderung bleibt sticky,
  • wartende Tasks werden geweckt,
  • laufende Tasks beobachten sie an definierten Checkpoints,
  • es gibt keine willkürliche Unterbrechung beliebigen VM-/FFI-Codes.

Der Fault-Pfad wartet nicht auf Cancellation. Trappt eine Task, erklärt die Runtime ihre FaultDomain sofort für nicht mehr ausführbar und gibt ihre Ressourcen getrennt davon frei, sobald keine Holds mehr offen sind (jade-fehlermodell §7, §8). Cancellation bleibt davon unberührt kooperativ.

Eine höhere Abstraktion darf Cancellation in einen Wert oder Domain-Fehler übersetzen.

Wartet eine Task auf einen nativen Aufruf oder auf die Freigabe eines exklusiven Handles, gilt dasselbe wie für jedes andere Warten: Sie wird geweckt und verlässt die Warteschlange. Was mit einem bereits laufenden nativen Aufruf geschieht, regelt §3.12.

3.7 Nativer Dispatch

Der FFI-Vertrag eines nativen Aufrufs trägt zwei voneinander unabhängige Angaben:

affinity:   any | stable
execution:  direct | blocking

Der Scheduler setzt daraus um:

affinity execution Ausführungsort Jade-Task
any direct aktueller Worker, synchron läuft weiter
any blocking NativeBlockingPool wartet
stable direct gebundene NativeExecutionLane wartet
stable blocking gebundene NativeExecutionLane wartet

blocking heißt: Dieser Aufruf darf seinen Host-Thread länger blockieren und darf deshalb keinen Worker blockieren. Es heißt nicht „immer der Pool“. Bei stable ist der zulässige Host-Thread die Lane; blocking überstimmt stable nie.

any plus direct läuft auf dem Worker, ohne dass das Reduction-Budget während des nativen Aufrufs zählt. Die Angabe direct ist eine Zusage des Bindings, dass der Aufruf kurz ist. Stimmt sie nicht, leidet die Fairness des Workers, nicht die Semantik.

3.8 NativeExecutionLane und AffinityDomain

Eine AffinityDomain bezeichnet eine Menge nativer Ressourcen, deren affine Aufrufe auf demselben Host-Thread ausgeführt werden müssen.

Jede aktive AffinityDomain ist genau einer NativeExecutionLane zugeordnet. Eine Lane:

  • besitzt genau einen Host-Thread,
  • führt native Aufrufe nacheinander aus,
  • darf mehrere AffinityDomains bedienen,
  • führt keine Jade-Tasks aus.

Für die gesamte Lebensdauer einer AffinityDomain bleibt ihr Host-Thread derselbe. Welche Lane eine neue Domain bekommt, ist Implementierungsdetail.

Eine Domain entsteht, wenn ein nativer Aufruf laut FFI-Vertrag ein Handle mit fester Affinität erzeugt. Der Scheduler wählt dann zuerst die Lane und führt den erzeugenden Aufruf dort aus; erst danach entsteht das Handle und wird von der JME an die Domain gebunden. Handles, die aus einem gebundenen Handle hervorgehen, erben dessen Domain. Die Form dieser Angaben steht in der FFI-Spec.

3.9 Stabile Domains sind bereits serialisiert

Eine Lane führt Aufrufe nacheinander aus. Ein Handle mit affinity = stable kann deshalb nie von zwei nativen Aufrufen gleichzeitig benutzt werden. Eine zusätzliche Exklusiv-Sperre ist dafür nicht nötig.

Davon getrennt bleibt der Wiedereintritt während eines noch laufenden Aufrufs über einen Callback (§3.11).

3.10 Exklusive nicht-affine Handles

Für Handles mit affinity = any und access = exclusive:

Handle frei                                  → der eintretende Token erhält den Eintritt
Handle durch anderen NativeEntryToken belegt → aufrufende Task wartet
Handle durch denselben Token belegt          → Trap

Im dritten Fall würde der Eintritt auf sich selbst warten. Das ist ein Programmierfehler ohne sinnvolle Reaktion und damit nach dem Fehlermodell ein Trap.

Welcher Token ein Handle gerade benutzt, weiß die JME. Der Scheduler besitzt nur das Warten und Wecken. Wird das Handle frei, wird mindestens eine wartende Task wieder runnable.

3.11 NativeEntryToken und Wiedereintritt

Ein NativeEntryToken entsteht beim Eintritt in einen nativen Aufrufpfad.

Ruft nativer Code synchron nach Jade zurück, trägt die Callback-Task denselben Token. Erzeugt diese Task strukturierte Kind-Tasks und wartet auf sie, erben diese den Token für die Dauer dieses strukturierten Pfads.

Ein synchroner Callback mit Token T darf keine native Ausführung in eine AffinityDomain anfordern, die derselbe Token T gerade aktiv hält. Ein solcher Eintritt trappt: Die Lane wartet auf den Callback und könnte den neuen Auftrag erst nach dessen Rückkehr ausführen.

Lane A → C → Callback (T) → Lane B → C → Callback (T) → Lane A   ✗ Trap

Grenze. Der Token ist kein allgemeiner Deadlock-Detektor. Ein Wartekreis über lose Kommunikation bleibt unerkannt:

Callback      wartet auf eine Kanal-Nachricht
andere Task   wartet auf das exklusive Handle
Handle        wird erst nach Rückkehr des Callbacks frei

Einen solchen Kreis zu erkennen, bräuchte einen allgemeinen Wartegraphen (Suchwort: wait-for graph). v0.3 verspricht das nicht. Es ist ein Programmierfehler. Introspection darf den Wartegraphen zur Diagnose sichtbar machen.

3.12 Cancellation während nativer Ausführung

Cancellation einer wartenden Task beendet einen bereits laufenden nativen Aufruf nicht.

  • Die Task darf ihren gewöhnlichen Cancellation-Pfad fortsetzen.
  • Der native Aufruf läuft weiter und behält alle Holds, die er für seine sichere Ausführung braucht.
  • Nach seiner Rückkehr wird das Ergebnis nur zugestellt, wenn noch ein Empfänger existiert.
  • Die Holds werden erst gelöst, wenn der native Eintritt tatsächlich beendet ist.

Bietet eine native API eine eigene Abbruchoperation, kann eine höhere FFI-Abstraktion einen Abbruchpfad beschreiben. Der Scheduler erfindet ihn nicht.

3.13 Native Callback-Eintritte

Ein nativer Callback führt nie Jade-Code direkt auf dem aufrufenden nativen Thread aus. Er wird in eine Jade-Task übersetzt und über den gewöhnlichen Scheduler ausgeführt. Das gilt für Lanes, für den Pool und für fremde Threads, die eine Bibliothek selbst erzeugt. Kein fremder Thread wird dadurch zum Worker.

asynchron   Callback-Task wird eingereiht; der native Thread wartet nicht
synchron    Callback-Task wird eingereiht; der native Thread wartet auf ihren Ausgang
            und setzt danach den nativen Aufruf fort; der Token wird weitergegeben

Die Callback-Task läuft unter der Engine-Konfiguration des Eintritts, der sie ausgelöst hat: bei synchronen Callbacks die der ursprünglichen Task, bei asynchronen die, die bei der Registrierung des Callbacks festgehalten wurde.

Offen: Endet eine synchrone Callback-Task nicht mit Success (sondern mit Failure, Cancelled oder Trap), braucht der wartende native Thread trotzdem einen Rückgabewert für C. Welcher das ist, muss der Callback-Vertrag in der FFI-Spec festlegen. Ein Trap in der Callback-Task folgt davon unabhängig dem Fehlermodell.

3.14 Blockierende Aufrufe auf stabilen Lanes

Blockiert ein Aufruf auf einer Lane, können bis zu seiner Rückkehr keine weiteren Aufrufe dieser Lane laufen. Das verletzt keine Semantik, es verlängert nur die Wartezeit anderer Domains derselben Lane.

Eine Implementierung darf Domains, deren Vertrag blockierende Aufrufe enthält, bevorzugt auf eigene oder wenig geteilte Lanes legen. Das ist Scheduling-Policy, keine Semantikzusage.


4. Engine-Konfiguration und Zeit

4.1 Trennung der Ebenen

EngineDefinition
    ↓
EngineDescriptor
    ↓
EngineRuntimeConfig
    ↓
Scheduler

Der Scheduler kennt keine semantische JDL-Engine. Er konsumiert ausschließlich EngineRuntimeConfig.

Tasks speichern ihre engineId.

4.2 EngineRuntimeConfig

Scheduler-relevante Konfiguration umfasst mindestens:

engineId
reductionLimit
optional timerWheelConfig
resourceLimits
overrunPolicy
metricsConfig

Capabilities gehören nicht zur Scheduler-Semantik. Enforcement erfolgt an RuntimeBus-/VM-Grenzen.

Registrierung und Änderungen der Runtime-Konfiguration laufen über den RuntimeBus.

4.3 Engine-lokale Timer-Wheels

Nicht jede Engine besitzt ein Timer-Wheel.

typisch zeitgetrieben:
    Rendering, periodische Jobs, Health Checks, Simulation

typisch eventgetrieben:
    HTTP-Transport, Socket-Completion, viele Actor-/Channel-Wakeups

Ein hierarchisches Timer-Wheel ist die vorgesehene Referenzimplementierung. Anzahl der Ebenen und Slots sind kein Sprachvertrag.

4.4 Overrun-Policies

Für periodische Arbeit existieren drei Policies:

Drift   nächster Lauf relativ zum tatsächlichen Abschluss; kein Aufstauen
Skip    verpasste Intervalle überspringen
Queue   verpasste Intervalle nachholen

Drift ist Default, sofern die Engine nichts anderes verlangt.

4.5 Beobachtbarkeit

Scheduler und Timer-Wheels sollen mindestens Größen wie folgende bereitstellen:

runnableTasks
waitingTasks
activeWorkers
queuePressure
targetRate
actualRate
handlerDuration
overrunCount

Das konkrete Metrikformat ist nicht normativ.


5. RuntimeBus und Intrinsic-Grenze

5.1 Mutationsgrenze

Zustandsändernde Scheduler-Operationen laufen ausschließlich über den RuntimeBus.

JDL / VM Intrinsic
        ↓
RuntimeBus Command
        ↓
Scheduler

Typische Operationen:

spawn
wait / yield
resume / wake
cancel
query cancellation
register / update EngineRuntimeConfig
native dispatch / native completion
park on native handle / wake native waiter
create / release affinity domain
callback inject

create / release affinity domain betrifft Scheduler und JME gemeinsam. Der Bus routet, er entscheidet nichts.

Mailbox-, Channel- und Actor-Logik liegen darüber.

5.2 Intrinsic-Encoding

Die Intrinsic-Grenze ist stabil und versioniert. Diese Scheduler-Spezifikation friert jedoch keine 16-Bit-ID-Bereiche oder Opcode-Nummern ein.

Gemäß VM-Spec bleiben zwei kompatible Lowering-Strategien zulässig:

  1. compiler-known Builtin/Intrinsic über den normalen Call-Pfad,
  2. ein generischer Intrinsic-Opcode mit Subcode.

Konkrete IDs und Encoding gehören in die zentrale VM-/Intrinsic-Spezifikation.

5.3 JadeValue

Intrinsics umgehen das aktuelle Grenzmodell nicht.

Gemäß 11-jadevalue-und-register-layout ist JadeValue das Transportformat an Call-, Return-, Intrinsic- und FFI-Grenzen. Innerhalb einer Funktion arbeitet die VM auf dem statisch angelegten Register-Buffer.

Fast Paths sind zulässig, sofern sie dieselbe Semantik und dieselben Verifier-/ABI-Invarianten erhalten.

5.4 Capabilities

Capability-Prüfung ist keine Scheduler-Policy.

Runtime-Capabilities werden an RuntimeBus-/VM-Grenzen erzwungen. Der Scheduler erhält nur autorisierte Scheduler-Kommandos.


6. Normative Invarianten

S-1 Der Scheduler ist Teil der VM, kein Actor und kein Userland-Service.
S-2 Tasks werden M:N auf Worker-Threads ausgeführt; die Workerzahl ist konfigurierbar.
S-3 Die Task ist die kleinste suspendierbare Scheduler-Einheit; Actors liegen darüber.
S-4 Der Scheduler besitzt keinen globalen Heartbeat.
S-5 Wartende Tasks werden durch Events oder Zeitbedingungen wieder runnable.
S-6 Reduction-basierte Preemption schützt vor unbegrenzter Worker-Monopolisierung.
S-7 Preemption erfolgt nur an VM-definierten sicheren Punkten.
S-8 Suspension ist Runtime-Eigenschaft, keine eigene JDL-Funktionsklasse.
S-9 Für normale suspendierbare Aufrufe gibt es kein Async-Row-Element und keine notwendige async/await-Färbung.
S-10 Neue parallele Ausführung entsteht explizit durch Task-Erzeugung.
S-11 Schedulerzustand und Task-Ausgang sind getrennte Dimensionen.
S-12 Throw[E] unwindet nicht über Task-Grenzen; es wird beim Task-Ausgang materialisiert.
S-13 Cancellation ist weder Throw[E] noch Trap. Der Trap-Teardown wartet nicht auf kooperative Cancellation.
S-14 Der Scheduler kennt nur EngineRuntimeConfig, nicht die semantische Engine.
S-15 Timer-Wheels werden durch Engine-Runtime-Konfiguration aktiviert und parametrisiert.
S-16 Scheduler-Zustand wird ausschließlich über den RuntimeBus mutiert.
S-17 Tasks besitzen keine Scheduler-Mailbox; Messaging liegt oberhalb des Scheduler-Cores.
S-18 VM-Suspensionssignale sind keine JDL-Result[T,E]-Werte.
S-19 Intrinsic-Encoding und IDs werden zentral in VM-/Intrinsic-Spezifikationen festgelegt.
S-20 Capability-Enforcement liegt an RuntimeBus-/VM-Grenzen, nicht in der Scheduling-Policy.
S-21 Die beobachtbare Semantik einer Jade-Task hängt niemals von ihrer Worker-Zuordnung ab.
S-22 Thread-affine native Ausführung findet auf NativeExecutionLanes außerhalb des Worker-Pools statt.
S-23 Lane- und Pool-Threads führen keine Jade-Tasks aus.
S-24 Eine AffinityDomain ist für ihre gesamte Lebensdauer genau einem Host-Thread zugeordnet.
S-25 affinity = any mit execution = blocking läuft im NativeBlockingPool.
S-26 affinity = stable läuft unabhängig von execution auf der gebundenen Lane.
S-27 Stabile native Ausführung ist durch die Lane serialisiert; eine Exklusiv-Sperre ist dafür nicht nötig.
S-28 Bei affinity = any mit access = exclusive wartet ein fremder Token auf Freigabe; Wiedereintritt mit demselben Token trappt.
S-29 Der NativeEntryToken wird über synchrone Callbacks und deren strukturierte Kind-Tasks weitergegeben.
S-30 Der NativeEntryToken ersetzt keinen allgemeinen Wartegraphen; Deadlocks über lose Kommunikation werden nicht vollständig erkannt.
S-31 Ein laufender nativer Aufruf wird durch Cancellation nicht beendet; seine Holds bleiben bis zur echten Rückkehr.
S-32 Ein nativer Callback führt Jade-Code nur als Scheduler-Task aus, nie direkt auf einem nativen Thread.
S-33 Native Completions werden über den gewöhnlichen Wait-/Wakeup-Mechanismus zugestellt.
S-34 Der Scheduler besitzt keine Wahrheit über Handles; AffinityDomain und Exklusiv-Zustand eines Handles gehören der JME.


7. Bewusst offene Implementierungsdetails

Diese Punkte können später entschieden werden, ohne das semantische Modell zu ändern:

Punkt Offen
Worker-Default Ableitung aus CPU-/Environment-Ressourcen
Work-Stealing Deque, Steal-Größe, Victim-Auswahl
Event-Poller Plattform-Backend
Wait-Registry interne Datenstruktur
Timer-Wheel Ebenen, Slots, Speicherlayout
Master Clock eigener Thread oder äquivalente Integration
Task-Outcome konkrete Repräsentation / Error-Envelope
Task-Handle Join/Detach/Structured-Concurrency-Lifetime
Shutdown Drain, Graceful Stop, Forced Stop
Intrinsic-ABI ID-Breite, Nummern, Encoding
Metrics genaue Struktur und Export
NativeBlockingPool Threadzahl, Wachsen, Schrumpfen
NativeExecutionLane Anzahl und Lebenszyklus
Lane-Placement Zuordnung von AffinityDomains zu Lanes
Lane-Queue konkrete Warteschlangenstruktur
Exklusiv-Warteschlange wer zuerst geweckt wird, Fairness
NativeEntryToken Repräsentation und Breite
Native Completion interne Ereignisdarstellung
Deadlock-Diagnose optionale Beobachtung des Wartegraphen

Diese Fragen sind keine Blocker für das Scheduler-Grundmodell.


8. Inkrementeller Implementierungsweg

V1
    ein Worker
    eine Run Queue
    Task-Zustandsautomat
    Reduction-Counter
    generisches wait / wake
    Event-Poller

V2
    mehrere Worker
    Work-Stealing
    Worker-Parking

V3
    Master Clock
    optionales Timer-Wheel
    Sleep / Deadline / Timeout

V4
    EngineRuntimeConfig
    Engine-lokale Timer-Wheels
    Resource Limits
    Overrun-Policies

V5
    Metrics
    Scheduler-Introspection
    Queue-/Fast-Path-Optimierungen

V6
    NativeBlockingPool
    native Completion → Wakeup
    NativeExecutionLane
    AffinityDomain-Zuordnung

V7
    exklusive any-Handles
    NativeEntryToken
    synchroner Callback-Eingang
    strukturierte Token-Weitergabe

V8
    Lane-Placement-Heuristiken
    Diagnose nativer Wartezustände
    Introspection / Mission Control

Task-Outcome-Materialisierung für Throw[E], Trap und Cancellation muss spätestens mit Task-Join/Wait integriert werden.


Änderungsprotokoll

v0.3.0

  • Worker-Unabhängigkeit der Task-Semantik geschärft (§1.1, S-21), ohne Ausnahme für FFI.
  • Native Ausführung außerhalb der Worker eingeführt: NativeExecutionLane und NativeBlockingPool (§1.3).
  • Dispatch-Tabelle aus affinity und execution (§3.7); blocking überstimmt stable nie.
  • AffinityDomain mit stabilem Host-Thread; Domain entsteht beim erzeugenden Aufruf (§3.8).
  • Stabile Domains als bereits serialisiert festgehalten (§3.9); Exklusiv-Sperre nur für any (§3.10).
  • Trap-Teardown wartet nicht auf kooperative Cancellation (§3.6, S-13), Auftrag aus jade-fehlermodell §13.
  • NativeEntryToken im Task-Modell, Weitergabe über synchrone Callbacks und strukturierte Kinder, Grenze gegenüber allgemeiner Deadlock-Erkennung (§3.11).
  • Cancellation beendet laufende native Aufrufe nicht (§3.12).
  • Callbacks laufen immer als Scheduler-Task (§3.13); Rückgabewert bei nicht erfolgreicher synchroner Callback-Task offen und an die FFI-Spec verwiesen.
  • RuntimeBus-Operationen, Invarianten S-21 bis S-34, offene Implementierungsdetails und Implementierungsstufen V6 bis V8 ergänzt.

v0.2.0

  • D-spezifische Implementierungsdetails entfernt; Host auf Zig aktualisiert.
  • Effect[R,E,D] und die alte Trennung „imperativer Stil / Effect-Stil“ entfernt.
  • Effect Rows ->{...} übernommen; Suspendierbarkeit davon ausdrücklich getrennt.
  • Task-State und Task-Outcome getrennt.
  • Throw[E]-Materialisierung an Task-Grenzen ergänzt.
  • Cancellation von Throw[E] und Trap getrennt.
  • Task-Mailbox aus dem Scheduler-Core entfernt.
  • JadeResult.yield() als veraltete Vermischung von VM-Control und JDL-Result beseitigt.
  • JadeValue als Intrinsic-Grenzformat berücksichtigt.
  • Capability-Enforcement vom Scheduler an RuntimeBus-/VM-Grenzen verschoben.
  • feste Intrinsic-ID-Bereiche aus dieser Spezifikation entfernt.
  • Timer-Wheel-Slotzahlen, Queue-Strukturen und Plattform-I/O zu Implementierungsdetails gemacht.
  • Aufbau auf acht kompakte Abschnitte reduziert.