Outils personnels
Vous êtes ici : Accueil C & C++ Programmation système La projection de fichiers en mémoire

La projection de fichiers en mémoire

Par Eric Salice - Dernière modification 18/04/2008 22:40
Contributeurs : Benjamin Poulain (Ikipou)
GPL

La projection de fichier en mémoire consiste à charger la totalité ou une partie d'un fichier dans un zone mémoire de l'espace d'adressage d'un processus pour que celui-ci puisse le manipuler directement, comme il manipule des variables, sans passer par des appels systèmes et donc de façon très rapide.

La projection d'un fichier en mémoire s'effectue par l'appel système mmap:

#include <sys/mman.h>
void *mmap(void *start, size_t length, int prot,int flags, int  fd, off_t offset);

où start indique la position dans la mémoire où l'on souhaite projeter le fichier mais on passera généralement un pointeur NULL pour laisser le système choisir l'emplacement.

fd est le descripteur de fichier à projeter

length est la longueur de la partie du fichier projetée et offset la position dans le fichier où commence la projection. Ces deux valeurs sont exprimées en octets. offset doit être un multiple de la taille des pages.

prot permet d'imposer des limitations d'accès à la zone mémoire. On utilisera généralement une combinaison à l'aide d'un ou binaire des valeurs PROT_READ (permission de lecture), PROT_WRITE (permission d'écriture). Ces permissions doivent être compatibles avec celles du descripteur de fichier.

flag permet d'indiquer si la zone mémoire est partagée par tout les processus projetant le fichier (MAP_SHARED) ou si le processus possède un copie de cette zone qui lui est propre (MAP_PRIVATE) auquel cas, les autres processus ne voient pas les modifications qu'il apporte à la zone projetée. Pour des raisons d'efficacité, un mécanisme de copy on write est mis en place pour ne pas dupliquer toute la zone mémoire projetée mais uniquement les pages modifiées.

La fonction retourne l'adresse de la projection.

La taille de la projection sera un multiple de la taille des pages. Au besoin les données du fichier seront complétées par des octets nul pour remplir la dernière page mais ceux-ci ne feront pas partie du fichier.

La projection de fichier en mémoire avec l'option MAP_SHARED permet à plusieurs processus de partager une même zone mémoire mais les IPC système V fournissent un mécanisme plus pratique car ne nécessitant pas de fichier.

Suppression de la projection

La fonction

#include <sys/mman.h>
int munmap(void *start, size_t length);

supprime la projection en libérant les ressources utilisées par celle-ci. Les modifications apportées à la projection sont écrites dans le fichier si le type de projection est MAP_SHARED.

start est l'adresse de la projection et length est sa taille (celle indiquée) lors de l'appel à mmap().

La suppression des zones mémoire est automatiquement effectuée à la terminaison d'un processus.

La fonction retourne 0 si elle réussit, -1 en cas d'échec.

Synchronisation de la projection

La fonction

#include <unistd.h>
#include <sys/mman.h>
int msync(const void *start, size_t length, int flags);

permet d'écrire dans le fichier les modifications apportées à la projection dans la portion commençant à start et de longueur length.

flag peut prendre comme valeur:

  • MS_ASYNC: l'appel revient immédiatement sans attendre la fin des écritures dans le fichier
  • MS_SYNC: la fonction attend la fin des écritures dans le fichier

Ces valeurs peuvent être combinée à l'aide d'un ou binaire à la valeur MS_INVALIDATE qui demande l'invalidation des données mises en cache pour le fichier.

La fonction retourne 0 si elle réussit, -1 en cas d'échec.

Exemple

programme 1

#include <fcntl.h> 
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
int fichier;
struct stat info;
int taille;
char *tab;
int i;
fichier = open(argv[1], O_RDWR);
stat(argv[1], &info);
taille = info.st_size;
tab = mmap(NULL,
taille,
PROT_READ | PROT_WRITE,
MAP_SHARED,
fichier,
0);
close(fichier);
while( 1 ) {
char tmp = tab[0];
for ( i = 1; i < taille; ++i )
tab[i -1] = tab[i];
tab[taille - 1] = tmp;
sleep(1);
}
return EXIT_SUCCESS;
}

programme 2

#include <fcntl.h> 
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
int fichier;
struct stat info;
int taille;
char *tab;
fichier = open(argv[1], O_RDONLY);
stat(argv[1], &info);
taille = info.st_size;
tab = mmap(NULL,
taille,
PROT_READ,
MAP_SHARED,
fichier,
0);
close(fichier);
sleep(1);
while( 1 ) {
write(STDOUT_FILENO, (void*)tab, taille);
printf("\n");
sleep(1);
}
return EXIT_SUCCESS;
}

Si le fichier dont le nom est passé comme paramètre aux deux programmes contient le texte:

La projection de fichiers en mémoire.

sans retour à la ligne.

L'exécution du programme 2 en parallèle avec le programme 1 provoque l'affichage des lignes:

$ ./prog1 project &
[1] 5980
$ ./prog2 project
tion de fichiers en memoire.La projec
ion de fichiers en memoire.La project
on de fichiers en memoire.La projecti
n de fichiers en memoire.La projectio
de fichiers en memoire.La projection
de fichiers en memoire.La projection
e fichiers en memoire.La projection d
fichiers en memoire.La projection de
fichiers en memoire.La projection de
ichiers en memoire.La projection de f
chiers en memoire.La projection de fi
hiers en memoire.La projection de fic
iers en memoire.La projection de fich
ers en memoire.La projection de fichi
rs en memoire.La projection de fichie

On peut observer, en affichant (par exemple avec cat) le fichier dont le nom est passé en paramètre aux deux programmes, que le contenu "sur disque" du fichier ne change pas tant que le premier programme ne s'est pas terminé (à cause d'un signal).

Si on indique l'option MAP_PRIVATE dans la fonction map():

tab = mmap(NULL, taille, PROT_READ | PROT_WRITE, MAP_PRIVATE, fichier, 0);

On observe que le programme 2 affiche toujours la même ligne qui est le contenu du fichier dont le nom est passé en paramètre aux programmes et qui ne sera pas modifié même après la terminaison du programme 1.

Si au contraire, on ajoute à la fin de la boucle un appel à la fonction msync() en gardant l'option MAP_SHARED:

msync(tab, taille, MS_ASYNC);

on constate que l'affichage, par cat, du contenu du fichier reflète les modifications réalisées par le programme 1 sur la projection du fichier.

Actions sur le document