====== std.mmap_ext ======
Erweiterte Memory-Operationen (WP-9): Ergänzt das Basis-''mmap''/''munmap'' um Größenänderung (''mremap''), Zugriffshinweise an den Kernel (''madvise''), Synchronisierung memory-gemappter Dateien (''msync''), In-Memory-Dateien ohne Filesystem (''memfd_create''), RAM-Pinning (''mlock'') und Residency-Prüfung (''mincore'').
→ [[lyx_-_programmiersprache:units|Standard Library]] · [[lyx_-_programmiersprache:units:alloc|std.alloc]] · [[lyx_-_programmiersprache:units:fs_ext|std.fs_ext]]
----
===== Konstanten =====
==== madvise-Hinweise ====
^ Konstante ^ Wert ^ Beschreibung ^
| ''MADV_NORMAL'' | 0 | Standard-Verhalten, keine Optimierung |
| ''MADV_RANDOM'' | 1 | Zufälliger Zugriff — Prefetching deaktivieren |
| ''MADV_SEQUENTIAL'' | 2 | Sequenzieller Zugriff — aggressives Prefetching |
| ''MADV_WILLNEED'' | 3 | Seiten werden bald benötigt — im Voraus einlesen |
| ''MADV_DONTNEED'' | 4 | Seiten werden nicht mehr benötigt — physikalischen RAM freigeben |
| ''MADV_FREE'' | 8 | Seiten dürfen freigegeben werden (lazy — erst bei Speicherdruck) |
| ''MADV_REMOVE'' | 9 | Bereich aus Backing-Store entfernen (tmpfs/shmem) |
| ''MADV_HUGEPAGE'' | 14 | Transparent Huge Pages für diesen Bereich aktivieren |
| ''MADV_NOHUGEPAGE'' | 15 | Transparent Huge Pages deaktivieren |
| ''MADV_COLD'' | 20 | Seiten als kalt markieren — werden bei Speicherdruck zuerst ausgelagert |
| ''MADV_PAGEOUT'' | 21 | Seiten sofort auslagern |
==== msync-Flags ====
^ Konstante ^ Wert ^ Beschreibung ^
| ''MS_ASYNC'' | 1 | Synchronisierung im Hintergrund starten |
| ''MS_SYNC'' | 4 | Blockierend warten bis Daten auf Disk geschrieben sind |
| ''MS_INVALIDATE'' | 2 | Andere Mappings derselben Datei invalidieren |
==== mremap-Flags ====
^ Konstante ^ Wert ^ Beschreibung ^
| ''MREMAP_MAYMOVE'' | 1 | Kernel darf den Bereich verschieben wenn nötig |
| ''MREMAP_FIXED'' | 2 | Mapping auf feste Zieladresse erzwingen |
| ''MREMAP_DONTUNMAP'' | 4 | Altes Mapping beibehalten (Kernel 5.7+) |
==== memfd_create-Flags ====
^ Konstante ^ Wert ^ Beschreibung ^
| ''MFD_CLOEXEC'' | 1 | fd bei ''exec()'' schließen |
| ''MFD_ALLOW_SEALING'' | 2 | Sealing-Operationen erlauben (fcntl F_ADD_SEALS) |
| ''MFD_HUGETLB'' | 4 | Mapping mit Huge Pages |
==== Sonstiges ====
Weitere Hilfsfunktionen:
^ Konstante ^ Wert ^ Beschreibung ^
| ''PAGE_SIZE'' | 4096 | Seitengröße auf x86-64 Linux in Bytes |
----
===== Funktionen =====
==== Mapping-Größe ändern ====
^ Signatur ^ Beschreibung ^
| ''MmapResize(addr: int64, oldSize: int64, newSize: int64): int64'' | Ändert die Größe eines bestehenden Mappings. Der Kernel darf es verschieben (''MREMAP_MAYMOVE''). Gibt die neue Adresse zurück — diese kann sich gegenüber ''addr'' ändern! |
| ''MmapResizeFixed(addr: int64, oldSize: int64, newSize: int64, newAddr: int64): int64'' | Wie ''MmapResize'', verschiebt aber auf eine feste Zieladresse ''newAddr'' |
==== Zugriffshinweise ====
^ Signatur ^ Beschreibung ^
| ''MmapAdvise(addr: int64, len: int64, advice: int64): int64'' | Gibt dem Kernel einen Hinweis über das geplante Zugriffsverhalten (''MADV_*''). Gibt 0 bei Erfolg |
| ''MmapFreePages(addr: int64, len: int64): int64'' | Gibt physikalische Seiten zurück ohne das Mapping zu entfernen (''MADV_DONTNEED''). Nächster Zugriff liefert nullisierte Seiten |
==== Datei-Mapping synchronisieren ====
^ Signatur ^ Beschreibung ^
| ''MmapSync(addr: int64, len: int64, flags: int64): int64'' | Schreibt Änderungen am Mapping in die zugrunde liegende Datei zurück. ''MS_SYNC'' = blockierend, ''MS_ASYNC'' = im Hintergrund. Auf anonymen Mappings ist dies ein No-Op |
==== In-Memory-Datei ====
^ Signatur ^ Beschreibung ^
| ''MemFdCreate(name: pchar, flags: int64): int64'' | Erstellt eine anonyme In-Memory-Datei. ''name'' ist ein Debug-Name (sichtbar in ''/proc/pid/fd''). Danach ''ftruncate'' + ''mmap'' für Shared Memory ohne Filesystem. Gibt fd zurück |
==== RAM-Pinning ====
^ Signatur ^ Beschreibung ^
| ''MemLock(addr: int64, len: int64): int64'' | Sperrt die Seiten im RAM — kein Swapping. Erfordert ''CAP_IPC_LOCK'' oder genug ''RLIMIT_MEMLOCK''-Budget |
| ''MemUnlock(addr: int64, len: int64): int64'' | Hebt die RAM-Sperre auf — Seiten dürfen wieder ausgelagert werden |
==== Residency-Prüfung ====
^ Signatur ^ Beschreibung ^
| ''MemInCore(addr: int64, len: int64, vecOut: int64): int64'' | Füllt ''vecOut'' mit dem Residency-Status: Ein Byte pro Seite, Bit 0 = 1 → Seite ist im RAM. ''vecOut'': ''alloc(ceil(len / PAGE_SIZE))'' |
| ''MemIsResident(addr: int64): bool'' | Gibt ''true'' zurück wenn die erste Seite an ''addr'' aktuell im RAM ist |
----
===== Verwendung =====
==== Wachsender Puffer via mremap ====
import std.mmap_ext;
import std.alloc;
// mmap-basierter Puffer der ohne Kopie wachsen kann.
fn GrowBuffer(addr: int64, oldSize: int64, newSize: int64): int64 {
var newAddr := MmapResize(addr, oldSize, newSize);
if (newAddr < 0) { return -1; }
// WICHTIG: newAddr kann != addr sein — alten Pointer nicht mehr verwenden!
return newAddr;
}
==== Sequential Read: Prefetching aktivieren ====
import std.mmap_ext;
fn ProcessLargeFile(addr: int64, size: int64): void {
// Kernel wird Seiten aggressiv prefetchen
MmapAdvise(addr, size, MADV_SEQUENTIAL);
// Nach dem Verarbeiten: physikalischen RAM freigeben
MmapFreePages(addr, size);
}
==== Shared Memory via memfd_create ====
import std.mmap_ext;
import std.fs_ext;
import std.io;
fn CreateSharedMem(size: int64): int64 {
var fd := MemFdCreate("shm_worker", MFD_CLOEXEC);
if (fd < 0) { return -1; }
// Größe festlegen
Ftruncate(fd, size);
// Mapping erstellen (PROT_READ|WRITE = 3, MAP_SHARED = 1)
var addr := mmap(0, size, 3, 1, fd, 0);
close(fd); // fd kann nach mmap geschlossen werden
return addr;
}
==== Latenz-kritischer Code: Seiten im RAM fixieren ====
import std.mmap_ext;
import std.alloc;
fn LockCriticalBuffer(size: int64): int64 {
// size muss Vielfaches von PAGE_SIZE sein
var addr := mmap(0, size, 3, 34, -1, 0); // PROT_RW, MAP_PRIVATE|ANON
if (addr < 0) { return -1; }
// Seiten vorwärts anfassen (erzwingt Seitenzuteilung)
MmapAdvise(addr, size, MADV_WILLNEED);
// RAM fixieren — kein Swapping mehr
MemLock(addr, size);
return addr;
}
fn UnlockAndFree(addr: int64, size: int64): void {
MemUnlock(addr, size);
munmap(addr, size);
}
==== Prüfen welche Seiten im RAM sind ====
import std.mmap_ext;
import std.alloc;
import std.io;
fn PrintResidency(addr: int64, size: int64): void {
var pages := (size + PAGE_SIZE - 1) / PAGE_SIZE;
var vecOut := alloc(pages);
MemInCore(addr, size, vecOut);
var inRam: int64 := 0;
var i: int64 := 0;
while (i < pages) {
if ((peek8(vecOut + i) & 1) != 0) { inRam := inRam + 1; }
i := i + 1;
}
PrintLn("Seiten im RAM: " + IntToStr(inRam) + " / " + IntToStr(pages));
free(vecOut, pages);
}
----
===== Hinweise =====
* ''MmapResize'' gibt eine neue Adresse zurück — den alten Zeiger danach nicht mehr dereferenzieren.
* ''MmapFreePages'' (''MADV_DONTNEED'') gibt nur physikalischen RAM frei; das virtuelle Mapping bleibt erhalten und wird beim nächsten Zugriff mit Nullen neu befüllt.
* ''MFD_ALLOW_SEALING'' ermöglicht es, nach dem Befüllen das Mapping read-only zu versiegeln — nützlich für unveränderliche Shared-Memory-Objekte.
* ''MemLock'' schlägt mit ''-ENOMEM'' fehl wenn das Prozess-Limit (''RLIMIT_MEMLOCK'') erreicht ist; Root hat standardmäßig kein Limit.
* ''addr'' und ''len'' müssen bei allen Funktionen auf ''PAGE_SIZE'' (4096) ausgerichtet sein.
----
===== Verwandte Units =====
* ''[[lyx_-_programmiersprache:units:alloc|std.alloc]]'' — Basis-Speicherverwaltung (mmap/munmap-basiert)
* ''[[lyx_-_programmiersprache:units:fs_ext|std.fs_ext]]'' — Fstat, Ftruncate (für memfd-Workflow)
* ''[[lyx_-_programmiersprache:units:fs|std.fs]]'' — Dateizugriff für dateibasierte Mappings
* ''[[lyx_-_programmiersprache:units:sched|std.sched]]'' — CPU-Affinität (ergänzt RAM-Pinning bei Echtzeit-Anforderungen)
Letzte Aktualisierung: 2026-06-05