NOM
mmap, munmap - Établir/supprimer une projection en mémoire (map/unmap)
des fichiers ou des périphériques
SYNOPSIS
#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags,
int fd, off_t offset);
int munmap(void *addr, size_t length);
mmap() crée une nouvelle projection dans l’espace d’adressage virtuel
du processus appelant. L’adresse de démarrage de la nouvelle projection
est indiquée dans addr. Le paramètre length indique la longueur de la
projection.
Si addr est NULL, le noyau choisit l’adresse à laquelle démarrer la
projection ; c’est la méthode la plus portable pour créer une nouvelle
projection. Si addr n’est pas NULL, le noyau le considère comme une
indication sur l’endroit où placer la projection ; sous Linux, elle
sera placée à une frontière de page proche. L’adresse de la nouvelle
projection est renvoyée comme résultat de l’appel.
Le contenu d’une projection de fichier (par opposition à une projection
anonyme ; voir ci-dessous MAP_ANONYMOUS) est initialisé avec length
octets à partir de la position offset dans le fichier (ou autre objet)
correspondant au descripteur de fichier fd. offset doit être un
multiple de la taille de page, renvoyée par sysconf(_SC_PAGE_SIZE).
L’argument prot indique la protection que l’on désire pour cette zone
de mémoire, et ne doit pas entrer en conflit avec le mode d’ouverture
du fichier. Il s’agit soit de PROT_NONE (le contenu de la mémoire est
inaccessible) soit d’un OU binaire entre les constantes suivantes :
PROT_EXEC On peut exécuter du code dans la zone mémoire.
PROT_READ On peut lire le contenu de la zone mémoire.
PROT_WRITE On peut écrire dans la zone mémoire.
PROT_NONE Les pages ne peuvent pas être accédées.
Le paramètre flags détermine si les modifications de la projection sont
visibles depuis les autres processus projetant la même région, et si
les modifications sont appliquées au fichier sous-jacent. Ce
comportement est déterminé en incluant exactement une des valeurs
suivantes dans flags :
MAP_SHARED Partager la projection. Les modifications de la projection
sont visibles dans les autres processus qui projettent ce
fichier, et sont appliquées au fichier sous-jacent. En
revanche, ce dernier n’est pas nécessairement mis à jour
tant qu’on n’a pas appelé msync(2) ou munmap().
MAP_PRIVATE
Créer une projection privée, utilisant la méthode de copie à
l’écriture. Les modifications de la projection ne sont pas
visibles depuis les autres processus projetant le même
fichier, et ne modifient pas le fichier lui-même. Il n’est
pas précisé si les changements effectués dans le fichier
après l’appel mmap() seront visibles.
Ces deux attributs sont décrits dans POSIX.1-2001.
De plus, zéro ou plus des valeurs suivantes peuvent être incluses dans
flags (avec un OU binaire) :
MAP_32BIT (depuis Linux 2.4.20, 2.6)
Placer la projection dans les deux premiers gigaoctets de
l’espace d’adressage du processus. Cet attribut n’est pris en
charge que sous x86-64, pour les programmes 64 bits. Il a été
ajouté pour permettre à la pile d’un thread d’être allouée dans
les deux premiers gigaoctets de mémoire, afin d’améliorer les
performances des changements de contexte sur les premiers
processeurs 64 bits. Les processeurs x86-64 modernes n’ont plus
ces problèmes de performance, donc l’utilisation de cete
attribut n’est pas nécessaire sur ces systèmes. L’attribut
MAP_32BIT est ignoré quand MAP_FIXED est positionné.
MAP_ANON
Synonyme de MAP_ANONYMOUS. Déconseillé.
MAP_ANONYMOUS
La projection n’est supportée par aucun fichier ; son contenu
est initialisé à 0. Les arguments fd et offset sont ignorés ;
cependant, certaines implémentations demandent que fd soit -1 si
MAP_ANONYMOUS (ou MAP_ANON) est utilisé, et les applications
portables doivent donc s’en assurer. Cet attribut, utilisé en
conjonction de MAP_SHARED, n’est implémenté que depuis Linux
2.4.
MAP_DENYWRITE
Cet attribut est ignoré. (Autrefois, une tentative d’écriture
dans le fichier sous‐jacent échouait avec l’erreur ETXTBUSY.
Mais ceci permettait des attaques par déni de service.)
MAP_EXECUTABLE
Cet attribut est ignoré.
MAP_FILE
Attribut pour compatibilité. Ignoré.
MAP_FIXED
Ne pas considérer addr comme une indication : n’utiliser que
l’adresse indiquée. addr doit être un multiple de la taille de
page. Si la zone mémoire indiquée par addr et len recouvre des
pages d’une projection existante, la partie recouverte de la
projection existante sera ignorée. Si l’adresse indiquée ne peut
être utilisée, mmap() échouera. Il est déconseillé d’utiliser
cette option, car requérir une adresse fixe pour une projection
n’est pas portable.
MAP_GROWSDOWN
Utilisé pour les piles. Indique au système de gestion de la
mémoire virtuelle que la projection doit s’étendre en croissant
vers le bas de la mémoire.
MAP_HUGETLB (depuis Linux 2.6.32)
Allouer la projection à l’aide « d’énormes pages ». Voyez le
fichier source du noyau Documentation/vm/hugetlbpage.txt pour
plus d’informations.
MAP_LOCKED (depuis Linux 2.5.37)
Verrouille la page projetée en mémoire à la manière de mlock(2).
Cet attribut est ignoré sur les noyaux plus anciens.
MAP_NONBLOCK (depuis Linux 2.5.46)
N’a de sens qu’en conjonction avec MAP_POPULATE. Ne pas
effectuer de lecture anticipée : créer seulement les entrées de
tables de page pour les pages déjà présentes en RAM. Depuis
Linux 2.6.23, cet attribut fait que MAP_POPULATE n’a aucun
effet. Un jour la combinaison de MAP_POPULATE et MAP_NONBLOCK
pourra être implémentée de nouveau.
MAP_NORESERVE
Ne pas réserver d’espace de swap pour les pages de cette
projection. Une telle réservation garantit que l’on puisse
modifier les zones soumises à une copie-en-écriture. Sans
réservation, on peut recevoir un signal SIGSEGV durant une
écriture, s’il n’y a plus de place disponible. Voir également la
description du fichier /proc/sys/vm/overcommit_memory dans la
page proc(5). Dans les noyaux antérieurs à 2.6, cet attribut
n’avait d’effet que pour les projections privées modifiables.
MAP_POPULATE (depuis Linux 2.5.46)
Remplit les tables de pages pour une projection. Pour une
projection de fichier, ceci s’effectue par une lecture anticipée
du fichier. Les accès ultérieurs à la projection ne seront pas
bloqués par des fautes de pages. MAP_POPULATE n’est géré pour
les projections privées que depuis Linux 2.6.23.
Parmi les attributs ci-dessus, seul MAP_FIXED est spécifié dans
POSIX.1-2001. Cependant, la plupart des systèmes gèrent aussi
MAP_ANONYMOUS (ou son synonyme MAP_ANON).
MAP_STACK (depuis Linux 2.6.27)
Alloue la projection à une adresse qui convient pour la pile
d’un processus ou d’un thread. Cet attribut n’a pour l’instant
aucun effet, mais est utilisé par l’implémentation des threads
de la glibc de telle sorte que si certaines architectures
nécessitent un traitement particulier pour l’allocation de la
pile, leur prise en charge par la suite par la glibc pourra être
implémentée de façon transparente.
Certains systèmes utilisent les attributs supplémentaires MAP_AUTOGROW,
MAP_AUTORESRV, MAP_COPY et MAP_LOCAL.
La mémoire obtenue par mmap est préservée au travers d’un fork(2), avec
les mêmes attributs.
La projection doit avoir une taille multiple de celle des pages. Pour
un fichier dont la longueur n’est pas un multiple de la taille de page,
la mémoire restante est remplie de zéros lors de la projection, et les
écritures dans cette zone n’affectent pas le fichier. Les effets de la
modification de la taille du fichier sous‐jacent sur les pages
correspondant aux zones ajoutées ou supprimées ne sont pas précisés.
munmap()
L’appel système munmap() détruit la projection dans la zone de mémoire
spécifiée, et s’arrange pour que toute référence ultérieure à cette
zone mémoire déclenche une erreur d’adressage. La projection est aussi
automatiquement détruite lorsque le processus se termine. À l’inverse,
la fermeture du descripteur de fichier ne supprime pas la projection.
L’adresse addr doit être un multiple de la taille de page. Toutes les
pages contenant une partie de l’intervalle indiqué sont libérées, et
tout accès ultérieur déclenchera SIGSEGV. Aucune erreur n’est détectée
si l’intervalle indiqué ne contient pas de page projetée.
Modifications d’horodatage pour les projections supportées par un fichier
Pour les projections supportées par un fichier, le champ st_atime du
fichier peut être mis à jour à tout moment entre l’appel mmap() et le
munmap() correspondant. Le premier accès dans la page projetée mettra
le champ à jour si cela n’a pas été déjà fait.
Les champs st_ctime et st_mtime pour un fichier projeté avec PROT_WRITE
et MAP_SHARED seront mis à jour après une écriture dans la région
projetée, et avant l’éventuel msync(2) suivant avec attribut MS_SYNC ou
MS_ASYNC.
VALEUR RENVOYÉE
mmap() renvoie un pointeur sur la zone de mémoire, s’il réussit. En cas
d’échec il retourne la valeur MAP_FAILED (c.‐à‐d. (void *) -1) et errno
contient le code d’erreur. munmap() renvoie 0 s’il réussit. En cas
d’échec, -1 est renvoyé et errno contient le code d’erreur
(probablement EINVAL).
ERREURS
EACCES Le descripteur ne correspond pas à un fichier normal, ou on
demande une projection privée MAP_PRIVATE mais fd n’est pas
ouvert en lecture, ou on demande une projection partagée
MAP_SHARED avec protection PROT_WRITE, mais fd n’est pas ouvert
en lecture et écriture (O_RDWR). Ou encore PROT_WRITE est
demandé, mais le fichier est ouvert en ajout seulement.
EAGAIN Le fichier est verrouillé, ou trop de pages ont été verrouillées
en mémoire (voir setrlimit(2)).
EBADF fd n’est pas un descripteur de fichier valable (et MAP_ANONYMOUS
n’était pas précisé).
EINVAL addr ou length ou offset sont invalides (par exemple : zone trop
grande, ou non alignée sur une frontière de page).
EINVAL (depuis Linux 2.6.12) length est nul.
EINVAL flags ne contient ni MAP_PRIVATE ni MAP_SHARED, ou les contient
tous les deux.
ENFILE La limite du nombre total de fichiers ouverts sur le système a
été atteinte.
ENODEV Le système de fichiers sous‐jacent ne supporte pas la projection
en mémoire.
ENOMEM Pas assez de mémoire, ou le nombre maximal de projection par
processus a été dépassé.
EPERM L’argument prot a demandé PROT_EXEC mais la zone appartient à un
fichier sur un système de fichiers monté sans permission
d’exécution.
ETXTBSY
MAP_DENYWRITE a été réclamé mais fd est ouvert en écriture.
L’accès à une zone de projection peut déclencher les signaux suivants :
SIGSEGV
Tentative d’écriture dans une zone en lecture seule.
SIGBUS Tentative d’accès à une portion de la zone qui ne correspond pas
au fichier (par exemple après la fin du fichier, y compris
lorsqu’un autre processus l’a tronqué).
CONFORMITÉ
SVr4, BSD 4.4, POSIX.1-2001.
DISPONIBILITÉ
Sur les systèmes POSIX sur lesquels mmap(), msync(2) et munmap() sont
disponibles, la constante symbolique _POSIX_MAPPED_FILES est définie
dans <unistd.h> comme étant une valeur supérieure à 0. (Voir aussi
sysconf(3).)
NOTES
Depuis le noyau 2.4, cet appel système a été remplacé par mmap2(2). De
nos jours, la fonction mmap() de la glibc appelle mmap2(2) avec la
bonne valeur pour offset.
Sur certaines architectures matérielles (par exemple, i386), PROT_WRITE
implique PROT_READ. Cela dépend de l’architecture si PROT_READ implique
PROT_EXEC ou non. Les programmes portables doivent toujours indiquer
PROT_EXEC s’ils veulent exécuter du code dans la projection.
La manière portable de créer une projection est de spécifier addr à 0
(NULL), et d’omettre MAP_FIXED dans flags. Dans ce cas, le système
choisit l’adresse de la projection ; l’adresse est choisie de manière à
ne pas entrer en conflit avec une projection existante et de ne pas
être nulle. Si l’attribut MAP_FIXED est indiqué et si addr vaut 0
(NULL), l’adresse projetée sera zéro (NULL).
BOGUES
Sous Linux, il n’y a aucune garantie comme celles indiquées plus haut à
propos de MAP_NORESERVE. Par défaut, n’importe quel processus peut être
tué à tout moment lorsque le système n’a plus de mémoire.
Dans les noyaux antérieurs à 2.6.7, le drapeau MAP_POPULATE n’avait
d’effet que si prot était PROT_NONE.
SUSv3 indique que mmap() devrait échouer si length est 0. Cependant,
avec les versions de Linux antérieures à 2.6.12, mmap() réussissait
dans ce cas : aucune projection n’était créée, et l’appel renvoyait
addr. Depuis le noyau 2.6.12, mmap() échoue avec le code d’erreur
EINVAL si length est nul.
EXEMPLE
Le programme suivant affiche la partie du fichier, précisé par le
premier argument de la ligne de commande, sur la sortie standard. Les
octets qui seront affichés sont précisés à partir d’un offset
(déplacement) et d’une longueur en deuxième et troisième paramètre. Le
code fait une projection mémoire des pages nécessaires du fichier puis
utilise write(2) pour afficher les octets voulus.
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
int
main(int argc, char *argv[])
{
char *addr;
int fd;
struct stat sb;
off_t offset, pa_offset;
size_t length;
ssize_t s;
if (argc < 3 || argc > 4) {
fprintf(stderr, "%s fichier offset [longueur]\n", argv[0]);
exit(EXIT_FAILURE);
}
fd = open(argv[1], O_RDONLY);
if (fd == -1)
handle_error("open");
if (fstat(fd, &sb) == -1) /* Pour obtenir la taille du fichier */
handle_error("fstat");
offset = atoi(argv[2]);
pa_offset = offset & ~(sysconf(_SC_PAGE_SIZE) - 1);
/* l’offset pour mmap() doit être aligné sur une page */
if (offset >= sb.st_size) {
fprintf(stderr, "L’offset dépasse la fin du fichier\n");
exit(EXIT_FAILURE);
}
if (argc == 4) {
length = atoi(argv[3]);
if (offset + length > sb.st_size)
length = sb.st_size - offset;
/* Impossible d’afficher les octets en dehors du fichier */
} else { /* Pas de paramètre longueur
==> affichage jusqu’à la fin du fichier */
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, "écriture partielle");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
} /* main */
VOIR AUSSI
getpagesize(2), mincore(2), mlock(2), mmap2(2), mprotect(2), mremap(2),
msync(2), remap_file_pages(2), setrlimit(2), shmat(2), shm_open(3),
shm_overview(7)
B.O. Gallmeister, POSIX.4, O’Reilly, pp. 128–129 et 389–391.
COLOPHON
Cette page fait partie de la publication 3.23 du projet man-pages
Linux. Une description du projet et des instructions pour signaler des
anomalies peuvent être trouvées à l’adresse
http://www.kernel.org/doc/man-pages/.
TRADUCTION
Cette page de manuel a été traduite par Thierry Vignaud <tvignaud AT
mandriva DOT com> en 2002, puis a été mise à jour par Alain Portal
<aportal AT univ-montp2 DOT fr> jusqu’en 2006, et mise à disposition
sur http://manpagesfr.free.fr/.
Les mises à jour et corrections de la version présente dans Debian sont
directement gérées par Julien Cristau <jcristau@debian.org> et l’équipe
francophone de traduction de Debian.
Veuillez signaler toute erreur de traduction en écrivant à
<debian-l10n-french@lists.debian.org> ou par un rapport de bogue sur le
paquet manpages-fr.
Vous pouvez toujours avoir accès à la version anglaise de ce document
en utilisant la commande « man -L C <section> <page_de_man> ».