mremap - eine virtuelle Speicheradresse neu mappen
Standard-C-Bibliothek (
libc,
-lc)
#define _GNU_SOURCE /* siehe feature_test_macros(7) */
#include <sys/mman.h>
void *mremap(void alte_Adresse[.alte_Größe], size_t alte_Größe,
size_t neue_Größe, int Schalter, … /* void *neue_Adresse */);
mremap() erweitert (oder verkleinert) ein bestehendes Speicher-Mapping,
potenziell durch gleichzeitiges Verschieben (bestimmt durch das Argument
Schalter und den zur Verfügung stehenden virtuellen
Speicherplatz).
alte_Adresse ist die alte Adresse des virtuellen Speicherblocks, den man
vergrößern (oder verkleinern) möchte. Beachten Sie, dass
alte_Adresse an den Speicherseiten ausgerichtet sein muss.
alte_Größe ist die alte Größe des
virtuellen Speicherblocks.
neue_Größe ist die
angeforderte Größe des virtuellen Speicherblocks nach der
Größenänderung. Optional kann ein fünftes
Argument,
neue_Adresse, angegeben werden; siehe die folgende
Beschreibung von
MREMAP_FIXED.
Falls der Wert von
alte_Größe Null ist und sich
alte_Adresse auf ein gemeinsam benutzbares Mapping bezieht (siehe
mmap(2) MAP_SHARED), dann wird
mremap() ein neues Mapping
der gleichen Seiten erstellen.
neue_Größe wird die
Größe des neuen Mappings sein und der Ort des neuen Mappings
kann mit
neue_Adresse festgelegt werden, siehe die nachfolgende
Beschreibung von
MREMAP_FIXED. Falls mittels dieser Methode ein neues
Mapping angefordert wird, dann muss der Schalter
MREMAP_MAYMOVE
angegeben werden.
Das Bitmasken-Argument
Schalter kann 0 sein oder die folgenden Schalter
enthalten:
- MREMAP_MAYMOVE
- Per Voreinstellung schlägt mremap() fehl,
wenn an der aktuellen Position nicht ausreichend Platz vorhanden ist, um
ein Mapping zu vergrößern. Wird dieser Schalter angegeben,
darf der Kernel das Speicher-Mapping an eine neue virtuelle Adresse
verlegen, falls das erforderlich ist. Wenn das Mapping verlegt wurde,
werden absolute Zeiger zum Ort des alten Mappings ungültig. (Es
sollten Offsets relativ zur Anfangsadresse des Mappings verwendet
werden.)
-
MREMAP_FIXED (seit Linux 2.3.31)
- Dieser Schalter dient einem ähnlichen Zweck wie der
Schalter MAP_FIXED von mmap(2). Wenn dieser Schalter
angegeben wird, dann akzeptiert mremap() ein fünftes
Argument, void *neue_Adresse, das eine an Seiten
ausgerichtete Adresse angibt, an die das Mapping verschoben werden muss.
Alle früheren Mappings auf den von neue_Adresse und
neue_Größe angegebenen Adressbereich werden
verworfen.
- Falls MREMAP_FIXED angegeben wird, muss ebenfalls
MREMAP_MAYMOVE angegeben werden.
-
MREMAP_DONTUNMAP (seit Linux 5.7)
- Dieser Schalter, der zusammen mit MREMAP_MAYMOVE
verwandt werden muss, verlegt das Mapping auf eine neue Adresse, aber
entfernt das Mapping an der alte_Adresse nicht.
- Der Schalter MREMAP_DONTUNMAP kann nur zusammen mit
privaten anonymen Mappings verwandt werden (siehe die Beschreibung von
MAP_PRIVATE und MAP_ANONYMOUS in mmap(2)).
- Nach Abschluss wird jeder Zugriff auf den durch
alte_Adresse und alte_Größe festgelegten
Bereich zu einer Seitenausnahmebehandlung führen. Die
Seitenausnahmebehandlung wird durch den Handler userfaultfd(2)
erledigt, falls die Adresse in dem vorher mit userfaultfd(2)
registrierten Bereich liegt. Andernfalls wird der Kernel einen mit Nullen
gefüllten Bereich belegen, der die Ausnahmebehandlung
erledigt.
- Der Schalter MREMAP_DONTUNMAP kann zur atomaren
Verschiebung eines Mappings verwandt werden, wobei die Quelle gemappt
bleibt. Siehe ANMERKUNGEN für mögliche Anwendungen von
MREMAP_DONTUNMAP.
Falls das von
alte_Adresse und
alte_Größe angegebene
Speichersegment gesperrt ist (mittels
mlock(2) oder etwas
Ähnlichem), wird diese Sperre aufrecht erhalten, wenn das
Speichersegment verschoben oder seine Größe geändert
wird. Als Folge davon kann sich die Größe des durch einen
Prozess gesperrten Speichers ändern.
Bei Erfolg gibt
mremap() einen Zeiger auf den neuen virtuellen
Speicherbereich zurück. Im Fehlerfall wird der Wert von
MAP_FAILED (d.h.
(void *) -1) zurückgegeben
und
errno gesetzt, um den Fehler anzuzeigen.
- EAGAIN
- Der Aufrufende versuchte, ein gesperrtes Speichersegment zu
vergrößern. Das war nicht möglich, ohne die
Resourcen-Begrenzung RLIMIT_MEMLOCK zu überschreiten.
- EFAULT
- Eine Adresse im Bereich von alte_Adresse bis
alte_Adresse+ alte_Größe ist für diesen
Prozess eine ungültige virtuelle Speicheradresse. Man erhält
sogar EFAULT, wenn Mappings existieren, die den gesamten
angeforderten Adressraum abdecken, aber von unterschiedlichem Typ
sind.
- EINVAL
- Ein ungültiges Argument wurde übergeben.
Mögliche Gründe sind:
- •
-
alte_Adresse war nicht an der Seitengrenze
ausgerichtet
- •
- ein von MREMAP_MAYMOVE, MREMAP_FIXED oder
MREMAP_DONTUNMAP verschiedener Wert wurde in Schalter
übergeben
- •
-
neue_Größe war Null
- •
-
neue_Größe oder neue_Adresse
war ungültig
- •
- der neue Adressbereich, der in neue_Adresse und
neue_Größe angegeben wurde, überlappte den in
alte_Adresse und alte_Größe angegebenen alten
Adressbereich
- •
-
MREMAP_FIXED oder MREMAP_DONTUNMAP wurde
angegeben, ohne auch MREMAP_MAYMOVE anzugeben
- •
-
MREMAP_DONTUNMAP wurde angegeben, aber eine oder
mehrere Seiten in dem durch alte_Adresse und
alte_Größe festgelegten Bereich waren nicht privat
anonym
- •
-
MREMAP_DONTUNMAP wurde angegeben und
alte_Größe war nicht zu
neue_Größe identisch
- •
-
alte_Größe war Null und
alte_Adresse bezieht sich nicht auf ein gemeinsam benutzbares
Mapping (siehe aber FEHLER)
- •
-
alte_Größe war Null und der Schalter
MREMAP_MAYMOVE war nicht angegeben
- ENOMEM
- Zur Ausführung der Aktion war nicht genug Speicher
verfügbar. Mögliche Gründe sind:
- •
- Der Speicherbereich kann an der aktuellen virtuellen
Adresse nicht erweitert werden und in Schalter ist der Schalter
MREMAP_MAYMOVE nicht gesetzt. Oder es gibt nicht genug freien
(virtuellen) Speicher.
- •
-
MREMAP_DONTUNMAP wurde verwandt und verursachte
dadurch die Erstellung eines neuen Mappings, das den verfügbaren
(virtuellen) Speicher überschreiten würde. Oder es
würde die maximale Anzahl an erlaubten Mappings
überschreiten.
Dieser Aufruf ist Linux-spezifisch und sollte nicht in portierbaren Programmen
benutzt werden.
mremap() ändert das Mapping zwischen virtuellen Adressen und
Speicherseiten. Dies kann benutzt werden, um ein sehr effizientes
realloc(3) zu implementieren.
Unter Linux ist der Speicher in Seiten eingeteilt. Ein Prozess verfügt
über (ein oder) mehrere lineare virtuelle Speichersegmente. Jedes
virtuelle Speichersegment hat ein oder mehr Mappings auf reale Speicherseiten
(in der Seitentabelle). Jedes virtuelle Speichersegment hat seinen eigenen
Schutz (Zugriffsrechte), welcher eine Segmentverletzung (Segmentation
violation,
SIGSEGV) verursachen kann, wenn auf den Speicher nicht
korrekt zugegriffen wird (z.B. beim Schreiben in ein schreibgeschütztes
Segment). Zugreifen auf virtuellen Speicher außerhalb der Segmente
verursacht ebenfalls eine Segmentverletzung.
Falls
mremap() dazu verwandt wird, einen mit
mlock(2) oder
Äquivalentem gesperrten Bereich zu verschieben oder zu erweitern, wird
der Aufruf
mremap() sich die beste Mühe geben, den neuen Bereich
zu bestücken, wird aber nicht mit
ENOMEM fehlschlagen, falls der
Bereich nicht bestückt werden kann.
Vor Version 2.4 machte die Glibc die Definition von
MREMAP_FIXED nicht
verfügbar und der Prototyp für
mremap() ließ das
Argument
neue_Adresse nicht zu.
Mögliche Anwendungen für
MREMAP_DONTUNMAP sind unter
Anderem:
- •
- Nicht kooperatives userfaultfd(2): eine Anwendung
kann sich einen virtuellen Adressbereich mittels MREMAP_DONTUNMAP
schnappen und dann einen userfaultfd(2)-Handler einsetzen, um die
Seitenausnahmebehandlungen zu handhaben, die nachfolgend auftreten, wenn
andere Threads in dem Prozess auf Seiten in dem geschnappten Bereich
zugreifen.
- •
- Automatische Speicherbereinigung: MREMAP_DONTUNMAP
kann im Zusammenspiel mit userfaultfd(2) verwandt werden, um
Algorithmen für automatische Speicherbereinigung zu implementieren
(z.B. in einer virtuellen Java-Maschine). Eine solche Implementierung kann
billiger (und einfacher) als konventionelle automatische
Speicherbereinigungstechniken sein, die Seiten mit einem
PROT_NONE-Schutz im Zusammenspiel mit dem SIGSEGV-Handler
markieren, um Zugriff auf diese Seiten abzufangen.
Vor Linux 4.14 erstellte
mremap() ein neues privates Mapping ohne Bezug
zum ursprünglichen Mapping, falls
alte_Größe Null
war und das Mapping auf das
alte_Adresse sich bezog, ein privates
Mapping war (
mmap(2) MAP_PRIVATE). Dieses Verhalten war nicht
beabsichtigt und für Anwendungen im Benutzerbereich unerwartet (da es
das Ziel von
mremap() ist, ein neues Mapping basierend auf dem
ursprünglichen Mapping zu erstellen). Seit Linux 4.14 schlägt
mremap() in diesem Szenario mit dem Fehler
EINVAL fehl.
brk(2),
getpagesize(2),
getrlimit(2),
mlock(2),
mmap(2),
sbrk(2),
malloc(3),
realloc(3)
Ihr Lieblingsbuch über Betriebssysteme für weitere Informationen
über »paged memory«. (
Modern Operating Systems
von Andrew S. Tanenbaum,
Inside Linux von Randolph Bentson,
The
Design of the UNIX Operating System von Maurice J. Bach.)
Die deutsche Übersetzung dieser Handbuchseite wurde von Patrick Rother
<
[email protected]>, Martin Eberhard Schauer <
[email protected]>,
Mario Blättermann <
[email protected]> und Helge
Kreutzmann <
[email protected]> erstellt.
Diese Übersetzung ist Freie Dokumentation; lesen Sie die
GNU
General Public License Version 3 oder neuer bezüglich der
Copyright-Bedingungen. Es wird KEINE HAFTUNG übernommen.
Wenn Sie Fehler in der Übersetzung dieser Handbuchseite finden, schicken
Sie bitte eine E-Mail an die
Mailingliste
der Übersetzer