mmap(2) | System Calls Manual | mmap(2) |
mmap, munmap - (un)mapt Dateien oder Geräte im Speicher
Standard-C-Bibliothek (libc, -lc)
#include <sys/mman.h>
void *mmap(void Adr[.laenge], size_t laenge, int prot, int Schalter, int dd, off_t Versatz); int munmap(void Adr[.laenge], size_t laenge);
Siehe ANMERKUNGEN für Informationen über Feature-Test-Makros-Anforderungen.
mmap() erstellt ein neues Mapping in den virtuellen Adressraum des aufrufenden Prozesses. Die Anfangsadresse für dieses neue Mapping wird in Adr angegeben. Das Argument laenge gibt an, welche Größe das Mapping haben soll (dies muss größer als 0 sein).
Falls Adr NULL ist, wählt der Kernel die (Seiten-ausgerichtete) Adresse aus, an der das Mapping erstellt wird. Dies ist die portabelste Methode, ein neues Mapping zu erstellen. Falls Adr nicht NULL ist, wertet der Kernel die Adresse als Hinweis, wo das Mapping erstellt werden soll. Unter Linux wird das Mapping dann eine Speicherseitengrenze in der Nähe auswählen (allerdings immer identisch zu oder oberhalb von dem durch /proc/sys/vm/mmap_min_addr festgelegten Wert) und versuchen, dort ein Mapping zu erstellen. Falls dort bereits ein anderes Mapping existiert, dann wählt der Kernel eine neue Adresse, die den Hinweis berücksichtigen kann, aber nicht muss. Die Adresse des neuen Mappings wird als Ergebnis des Aufrufs zurückgegeben.
Die Inhalte eines Datei-Mappings werden initialisiert, indem laenge Byte aus der Datei (oder einem anderen Objekt), die durch den Dateideskriptor dd beschrieben wird, ab dem Versatz Versatz verwendet werden. Dies ist anders als beim anonymen Mapping, siehe MAP_ANONYMOUS unten. Versatz muss ein Vielfaches der Seitengröße sein, die von sysconf(_SC_PAGE_SIZE) zurückgegeben wird.
Nachdem der mmap()-Aufruf zurückgekehrt ist, kann der Dateideskriptor dd sofort geschlossen werden, ohne dass das Mapping ungültig wird.
Das Argument prot beschreibt den gewünschten Speicherschutz des Mappings (und darf nicht im Widerspruch zum Öffnungsmodus der Datei stehen). Es ist entweder PROT_NONE oder das bitweise ODER von einem oder mehreren der folgenden Schalter:
Das Argument Schalter bestimmt, ob Aktualisierungen des Mappings für andere Prozesse sichtbar sind, die denselben Bereich mappen und ob Aktualisierungen auch in die zugrundeliegende Datei weitergereicht werden. Dieses Verhalten wird durch genau einen der folgenden Werte in Schalter festgelegt:
Sowohl MAP_SHARED als auch MAP_PRIVATE werden in POSIX.1-2001 und POSIX.1-2008 beschrieben. MAP_SHARED_VALIDATE ist eine Linux-Erweiterung.
Zusätzlich können null oder mehrere der folgenden Werte mit OR in Schalter hinzugefügt werden:
#define MAP_HUGE_2MB (21 << MAP_HUGE_SHIFT) #define MAP_HUGE_1GB (30 << MAP_HUGE_SHIFT)
Von den obigen Schaltern ist nur MAP_FIXED in POSIX.1-2001 und POSIX.1-2008 spezifiziert. Allerdings unterstützen die meisten Systeme MAP_ANONYMOUS (oder sein Synonym MAP_ANON).
Der munmap-Systemaufruf hebt die Mappings im angegebenen Speicherbereich auf. Zukünftige Zugriffe auf diesen Adressraum erzeugen dann einen Fehler vom Typ »invalid memory reference« - Ungültiger Speicherzugriff. Der Adressraum wird außerdem automatisch ausgemappt, wenn der Prozess beendet wird. Das Schließen des Dateideskriptors hingegen führt nicht dazu, dass der Adress-Mapping aufgehoben wird.
Die Adresse Adr muss ein Vielfaches der Seitengröße sein (für laenge ist das nicht der Fall). Alle Seiten, die einen Teil des angezeigten Bereichs enthalten, werden ausgemappt, und nachfolgende Referenzen auf diese Seiten führen zu SIGSEGV. Es ist kein Fehler, falls der angezeigte Bereich keine gemappten Seiten enthält.
Bei Erfolg gibt mmap einen Zeiger auf den gemappten Speicherbereich zurück. Bei Fehlern wird MAP_FAILED ((void *) -1) zurückgegeben und errno gesetzt, um den Fehler anzuzeigen.
Bei Erfolg liefert munmap() 0 zurück. Im Fehlerfall liefert es -1 und errno wird gesetzt, um den Fehler (wahrscheinlich EINVAL) anzuzeigen.
Die Verwendung eines gemappten Bereichs kann diese Signale verursachen:
Siehe attributes(7) für eine Erläuterung der in diesem Abschnitt verwandten Ausdrücke.
Schnittstelle | Attribut | Wert |
mmap(), munmap() | Multithread-Fähigkeit | MT-Safe |
POSIX.1-2001, POSIX.1-2008, SVr4, 4.4BSD.
Auf POSIX-Systemen, auf denen mmap(), msync(2) und munmap() verfügbar sind, ist _POSIX_MAPPED_FILES in <unistd.h> auf einen Wert größer 0 definiert. (Siehe auch sysconf(3).)
Speicher, der mit mmap() gemappt wurde, wird über fork(2) hinweg mit den gleichen Attributen erhalten.
Eine Datei wird in Vielfachen der Seitengröße gemappt. Für eine Datei, die nicht ein Vielfaches der Seitengröße ist, werden die verbliebenen Bytes in der unvollständigen Seite am Ende des Mappings beim Mappen mit Nullen überschrieben und Änderungen an diesem Bereich werden nicht in die Datei geschrieben. Es ist nicht spezifiziert, wie sich die Größenänderung der zugrundeliegenden Datei auf das Mapping der Seiten, die hinzugefügten oder entfernten Regionen der Datei entsprechen, auswirkt.
Auf einigen Hardware-Architekturen (z.B. i386) impliziert PROT_WRITE PROT_READ. Es ist architekturabhängig, ob PROT_READ PROT_EXEC impliziert (oder nicht). Portable Programme sollten immer PROT_EXEC setzen, falls sie vorhaben, Code in dem neuen Mapping auszuführen.
Die portierbare Art, ein Mapping zu erstellen, ist die Angabe von Adr als 0 (NULL) und das Auslassen von MAP_FIXED aus Schalter. In diesem Fall wählt das System die Adresse für das Mapping; die Adresse wird so gewählt, dass sie mit keinem bestehenden Mapping in Konflikt steht und nicht 0 sein wird. Falls der Schalter MAP_FIXED angegeben und Adr 0 (NULL) ist, dann wird die gemappte Adresse 0 (NULL) sein.
Bestimmte Schalter-Konstanten sind nur definiert, falls die geeigneten Feature-Test-Makros definiert sind (möglicherweise standardmäßig): _DEFAULT_SOURCE mit Glibc 2.19 oder neuer; oder _BSD_SOURCE oder _SVID_SOURCE in Glibc 2.19 und älter. (Es reicht auch aus, _GNU_SOURCE einzusetzen, und dieses Makro zu verlangen, wäre logischer gewesen, da alle diese Schalter Linux-spezifisch sind). Die relevanten Schalter sind: MAP_32BIT, MAP_ANONYMOUS (und das Synonym MAP_ANON), MAP_DENYWRITE, MAP_EXECUTABLE, MAP_FILE, MAP_GROWSDOWN, MAP_HUGETLB, MAP_LOCKED, MAP_NONBLOCK, MAP_NORESERVE, MAP_POPULATE und MAP_STACK.
Durch Verwendung von mincore(2) kann eine Anwendung ermitteln, welche Seiten eines Mappings sich derzeit im Puffer/Seitenzwischenspeicher befinden.
Der einzige sichere Anwendungsfall für MAP_FIXED ist, falls der durch Adr und laenge festgelegte Adressbereich vorher durch ein anderes Mapping reserviert wurde; andernfalls ist die Verwendung von MAP_FIXED gefährlich, da sie bereits bestehende Mappings zwangsweise entfernt, wodurch es für einen Prozess mit mehreren Threads leicht wird, seinen eigenen Adressraum zu beschädigen.
Nehmen wir beispielsweise an, dass Thread A /proc/<PID>/maps durchsucht, um einen nicht benutzten Adressbereich zu finden, den er mittels MAP_FIXED mappen kann, während Thread B gleichzeitig Teile des gleichen Adressbereichs (oder den gesamten Adressbereich) erlangt. Wenn Thread A anschließend mmap(MAP_FIXED) einsetzt, wird es das Mapping, das Thread B erstellte, durcheinanderbringen. In diesem Szenario muss Thread B nicht das Mapping direkt erstellen: einfach ein Aufruf einer Bibliotheksfunktion, die intern dlopen(3) zum Laden einer anderen dynamische Bibliothek verwendet, reicht aus. Der Aufruf von dlopen(3) wird die Bibliothek in den Adressraum des Prozesses einmappen. Desweiteren kann fast jeder Bibliotheksaufruf auf eine Art implementiert sein, die Speicher-Mappings zu dem Adressraum hinzufügt, entweder mit dieser Technik oder einfach durch Reservierung von Speicher. Beispiele sind brk(2), malloc(3), pthread_create(3) und die PAM-Bibliotheken http://www.linux-pam.org.
Seit Linux 4.17 kann ein Multithread-Programm den Schalter MAP_FIXED_NOREPLACE verwenden, um die oben beschriebene Gefahr zu vermeiden, dass ein Mapping an einer festen Adresse versucht wird, die nicht durch ein bereits existierendes Mapping reserviert wurde.
Für Datei-basierte Mappings wird das Feld st_atime für die gemappte Datei zu jedem Zeitpunkt zwischen mmap() und dem entsprechenden Entmappen aufgerufen werden; die erste Referenz auf die gemappte Seite wird das Feld aktualisieren, falls es nicht bereits erfolgt ist.
Das Feld st_ctime und st_mtime für eine mit PROT_WRITE und MAP_SHARED gemappte Datei wird nach einem Schreibzugriff auf den gemappten Bereich und vor dem nachfolgenden msync(2) mit den Schalter MS_SYNC oder MS_ASYNC, falls dieser erfolgt, aktualisiert.
Für Mappings, die große Speicherseiten einsetzen, unterscheiden sich die Anforderungen für die Argumente von mmap() und munmap() etwas von den Anforderungen für Mappings, die die native Systemseitengröße verwenden.
Für mmap() muss Versatz ein Vielfaches der unterliegenden Größe der großen Speicherseiten sein. Das System richtet laenge automatisch aus, dass es ein Vielfaches der unterliegenden Größe der großen Speicherseiten ist.
Für munmap() müssen sowohl Adr als auch laenge ein Vielfaches der unterliegenden Größe der großen Speicherseiten sein.
Diese Seite beschreibt die durch den mmap()-Wrapper der Glibc bereitgestellte Funktion. Ursprünglich rief diese Funktion einen Systemaufruf mit dem gleichen Namen auf. Seit Linux 2.4 wurde dieser Systemaufruf durch mmap2(2) ersetzt und heutzutage ruft die Wrapperfunktion mmap() der Glibc mmap2(2) mit einem geeignet angepassten Wert für Versatz auf.
Unter Linux gibt es keine Garantien, wie die, die unter MAP_NORESERVE vorgeschlagen werden. Standardmäßig kann jeder Prozess jederzeit getötet werden, wenn dem System der Speicher ausgeht.
Vor Linux 2.6.7 hatte der Schalter MAP_POPULATE nur einen Effekt, falls prot als PROT_NONE festgelegt ist.
SUSv3 spezifiziert, dass mmap() fehlschlagen soll, falls laenge 0 ist. Vor Linux 2.6.12 war mmap() in diesem Fall allerdings erfolgreich: es wurde kein Mapping erstellt und der Aufruf lieferte Adr zurück. Seit Linux 2.6.12 schlägt es in diesem Fall mit dem Fehler EINVAL fehl.
POSIX spezifiziert, dass das System immer jede teilweise gefüllte Seite am Ende des Objektes mit Nullen auffüllen muss und dass das System niemals Änderungen an dem Objekt hinter seinem Ende schreibt. Unter Linux verbleiben sämtliche geschriebenen Daten in solchen Teilseiten nach dem Ende des Objektes im Seitenzwischenspeicher, selbst nachdem die Datei geschlossen und entmappt wurde und selbst obwohl die Daten niemals zu der Datei selbst geschrieben wurden, könnten nachfolgende Mappings die veränderten Inhalte sehen. In einigen Fällen könnte dies durch einen Aufruf von msync(2), bevor das Aufheben des Mappings stattfindet, behoben werden, allerdings funktioniert dies nicht auf tmpfs(5) (beispielsweise beim Einsatz der POSIX-Schnittstelle für gemeinsamen Speicher, wie in shm_overview(7) dokumentiert).
Das nachfolgende Programm gibt Teile der als sein erstes Befehlszeilenargument übergebenen Datei auf die Standardausgabe aus. Der ausgegebene Byte-Bereich wird mittels des Versatzes und des Längenwertes im zweiten und dritten Befehlszeilenargument angegeben. Das Programm erstellt ein Speicher-Mapping der benötigten Seiten der Datei und verwendet write(2), um die gewünschten Bytes auszugeben.
#include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <sys/mman.h> #include <sys/stat.h> #include <unistd.h> #define handle_error(msg) \ do { perror(msg); exit(EXIT_FAILURE); } while (0) int main(int argc, char *argv[]) { int fd; char *addr; off_t offset, pa_offset; size_t length; ssize_t s; struct stat sb; if (argc < 3 || argc > 4) { fprintf(stderr, "%s Dateiversatz [Länge]\n", argv[0]); exit(EXIT_FAILURE); } fd = open(argv[1], O_RDONLY); if (fd == -1) handle_error("open"); if (fstat(fd, &sb) == -1) /* Um die Dateigröße zu erhalten */ handle_error("fstat"); offset = atoi(argv[2]); pa_offset = offset & ~(sysconf(_SC_PAGE_SIZE) - 1); /* Versatz für mmap() muss an der Seite ausgerichtet sein */ if (offset >= sb.st_size) { fprintf(stderr, "Versatz ist hinter dem Dateiende\n"); exit(EXIT_FAILURE); } if (argc == 4) { length = atoi(argv[3]); if (offset + length > sb.st_size) length = sb.st_size - offset; /* Bytes hinter dem Dateiende können nicht angezeigt werden */ } else { /* Kein Längen-Argument ==> Anzeige bis zum Dateiende */ length = sb.st_size - offset; } addr = mmap(NULL, length + offset - pa_offset, PROT_READ, MAP_PRIVATE, fd, pa_offset); if (addr == MAP_FAILED) handle_error("mmap"); s = write(STDOUT_FILENO, addr + offset - pa_offset, length); if (s != length) { if (s == -1) handle_error("write"); fprintf(stderr, "Schreiben unvollständig"); exit(EXIT_FAILURE); } munmap(addr, length + offset - pa_offset); close(fd); exit(EXIT_SUCCESS); }
ftruncate(2), getpagesize(2), memfd_create(2), mincore(2), mlock(2), mmap2(2), mprotect(2), mremap(2), msync(2), remap_file_pages(2), setrlimit(2), shmat(2), userfaultfd(2), shm_open(3), shm_overview(7)
Die Beschreibung der folgenden Dateien in proc(5): /proc/[PID]/maps, /proc/[PID]/map_files und /proc/[PID]/smaps.
B.O. Gallmeister, POSIX.4, O'Reilly, Seiten 128–129 und 389–391.
Die deutsche Übersetzung dieser Handbuchseite wurde von Johnny Teveßen <j.tevessen@gmx.de>, Martin Schulze <joey@infodrom.org>, Dr. Tobias Quathamer <toddy@debian.org> und Helge Kreutzmann <debian@helgefjell.de> 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.
5. Februar 2023 | Linux man-pages 6.03 |