====== Lyx OS – Sync-Primitive ======
Diese Seite dokumentiert die Synchronisations-Primitive in ''kernel/sync.lyx'' (WP9): Spinlock, Mutex und Semaphor. Alle Primitive sind für Kernel-Code (Ring-0) konzipiert.
→ [[lyxos:architektur|Architektur]] · [[lyxos:smp|SMP & Tasks]] · [[lyxos:kernel|Kernel-Interna]]
----
===== 1. Überblick =====
''sync.lyx'' stellt drei Arten von Synchronisations-Primitiven bereit:
^ Primitiv ^ Einsatz ^ Implementierung ^
| Spinlock | Kurze kritische Abschnitte, Unterbrechungsschutz | Aktives Warten via ''LOCK XCHG'' (''vmm_op8'') |
| Mutex | Längere Abschnitte, schlafen erlaubt | Kernel-verwaltet via ''vmm_op9–11'', optionaler Timeout |
| Semaphor | Producer-Consumer, Ressourcenzähler | Kernel-verwaltet via ''vmm_op12–14'', Zähler konfigurierbar |
----
===== 2. Spinlock =====
Ein Spinlock ist ein einfacher busy-wait-Lock. Er eignet sich für sehr kurze kritische Abschnitte, z.B. Schutz von Print-Ausgaben über mehrere Prozessoren.
// Adresse des system-weiten Print-Spinlocks holen (einmal, beim Start):
var print_lock: int64 := GetPrintSpinlockAddr(); // → vmm_op15
// Kritischen Abschnitt schützen:
SpinlockAcquire(print_lock);
PrintLn("Atomar ausgegeben");
SpinlockRelease(print_lock);
**Eigenschaften:**
* ''SpinlockAcquire(lock_ptr)'' — schreibt 1 in die Lock-Variable via ''LOCK XCHG''; dreht sich so lange, bis der alte Wert 0 war
* ''SpinlockRelease(lock_ptr)'' — schreibt 0 (''poke64(ptr, 0)'')
* Kein Schlaf, kein Scheduling-Eingriff — nur für sehr kurze Abschnitte geeignet
* ''GetPrintSpinlockAddr()'' gibt eine kernel-weite Lock-Adresse zurück, die alle Kernel-Threads und APs gemeinsam nutzen
----
===== 3. Mutex =====
Ein Mutex ist ein schläfender Lock. Der Kernel schläft wartende Threads ein und weckt sie nach dem Unlock wieder auf.
// Mutex anlegen:
var mx: int64 := MutexCreate(MUTEX_PLAIN); // MUTEX_PLAIN=0, MUTEX_RECURSIVE=1
// Lock mit unbegrenztem Timeout:
var err: int64 := MutexLock(mx);
// Lock mit Timeout (Nanosekunden):
var err: int64 := MutexLockTimeout(mx, 1000000); // 1 ms
// Unlock:
MutexUnlock(mx);
^ Konstante ^ Wert ^ Bedeutung ^
| MUTEX_PLAIN | 0 | Normaler Mutex — kein rekursives Lock erlaubt |
| MUTEX_RECURSIVE | 1 | Rekursiver Mutex — selber Thread darf mehrfach locken |
**Hinweis:** ''MutexCreate'' gibt eine Integer-ID zurück (kein Zeiger). Die eigentliche Mutex-Struktur liegt im Kernel-Verwaltungsbereich und ist nicht direkt zugänglich.
----
===== 4. Semaphor =====
Ein Semaphor verwaltet einen ganzzahligen Zähler. ''SemWait'' dekrementiert (und schläft, wenn Zähler = 0). ''SemPost'' inkrementiert und weckt einen wartenden Thread auf.
// Semaphor anlegen (initial count = 2):
var sem: int64 := SemCreate(2, 0); // flags: 0 = anonym, SEM_NAMED=1 = benannt
SemWait(sem); // Zähler −1; schläft wenn Zähler = 0
SemWait(sem); // nochmal −1
SemPost(sem); // Zähler +1; weckt ggf. wartenden Thread auf
**Typischer Einsatz — Producer/Consumer:**
var sem_full: int64 := SemCreate(0, 0); // Elemente im Puffer
var sem_empty: int64 := SemCreate(8, 0); // Freie Plätze (Puffergröße = 8)
// Producer:
SemWait(sem_empty);
// ... in Puffer schreiben ...
SemPost(sem_full);
// Consumer:
SemWait(sem_full);
// ... aus Puffer lesen ...
SemPost(sem_empty);
----
===== 5. Wann welches Primitiv? =====
^ Situation ^ Empfehlung ^
| Print-Ausgaben serialisieren (Multi-Core) | ''SpinlockAcquire'' / ''Release'' auf ''GetPrintSpinlockAddr()'' |
| Gemeinsame Datenstruktur schützen (kurz) | Spinlock |
| Gemeinsame Datenstruktur schützen (länger) | Mutex mit ''MUTEX_PLAIN'' |
| Initialisierung einmalig sicherstellen | Mutex: vor Init locken, danach unlocked lassen |
| Ressourcenzähler (n Slots verfügbar) | Semaphor |
| Producer-Consumer-Puffer | Zwei Semaphore (''sem_full'' + ''sem_empty'') |
Letzte Aktualisierung: 2026-06-13