====== 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