SHMOP(2) System Calls Manual SHMOP(2) NOM shmat, shmdt - Operations sur la memoire partagee System V BIBLIOTHEQUE Bibliotheque C standard (libc, -lc) SYNOPSIS #include void *shmat(int shmid, const void *_Nullable shmaddr, int shmflg); int shmdt(const void *shmaddr); DESCRIPTION shmat() La fonction shmat() attache le segment de memoire partagee System V identifie par shmid au segment de donnees du processus appelant. L'adresse d'attachement est indiquee par shmaddr avec les criteres suivants : - Si shmaddr vaut NULL, le systeme choisit une adresse (non utilisee) alignee sur la page convenant pour attacher le segment. - Si shmaddr n'est pas NULL et si SHM_RND est indique dans shmflg, l'attachement a lieu a l'adresse egale a shmaddr arrondie au multiple inferieur de SHMLBA. - Sinon, shmaddr doit etre alignee sur une frontiere de page, ou l'attachement a lieu. En plus de SHM_RND, les attributs suivants peuvent etre indiques dans le parametre de masque shmflg : SHM_EXEC (specifique a Linux, depuis Linux 2.6.9) Autoriser l'execution du contenu du segment. L'appelant doit disposer du droit d'execution sur le segment. SHM_RDONLY Attacher le segment en lecture seule. Le processus doit disposer de la permission de lecture dessus. Si cet attribut n'est pas indique, le segment est attache en lecture et ecriture, et le processus doit disposer des deux permissions d'acces. Il n'y a pas de notion d'ecriture seule pour les segments de memoire partagee. SHM_REMAP (specifique a Linux) Cet attribut indique que la projection du segment doit remplacer une projection precedente dans l'intervalle commencant en shmaddr et s'etendant sur la taille du segment. Normalement une erreur EINVAL devrait se produire si une projection existe deja dans l'intervalle indique. Dans ce cas, shmaddr ne doit pas etre NULL. La valeur brk(2) du processus appelant n'est pas alteree par l'attachement. Le segment est automatiquement detache quand le processus se termine. Le meme segment peut etre attache a la fois en lecture seule et en lecture/ecriture. Il peut egalement etre attache en plusieurs endroits de l'espace d'adressage du processus. Quand shmat() reussit, les membres de la structure shmid_ds associee au segment de memoire partagee (consultez shmctl(2)) sont mis a jour ainsi : - shm_atime correspond a l'heure actuelle. - shm_lpid contient le PID de l'appelant. - shm_nattch est incremente de 1. shmdt() La fonction shmdt() detache le segment de memoire partagee situe a l'adresse indiquee par shmaddr. Le segment doit etre effectivement attache, et l'adresse shmaddr doit etre celle renvoyee precedemment par l'appel shmat(). Quand shmdt() reussit, les membres de la structure shmid_ds associee au segment de memoire partagee sont mis a jour ainsi par le systeme : - shm_dtime correspond a l'heure actuelle. - shm_lpid contient le PID de l'appelant. - shm_nattch est decremente de 1. S'il devient nul et si le segment est marque pour destruction, il est effectivement detruit. VALEUR RENVOYEE S'il reussit, shmat() renvoie l'adresse d'attachement du segment de memoire partagee. En cas d'echec (void *) -1 est renvoye, et errno est positionne pour indiquer l'erreur. S'il reussit, shmdt() renvoie 0. En cas d'echec, -1 est renvoye et errno est positionne pour indiquer l'erreur. ERREURS shmat() peut echouer avec une des erreurs suivantes : EACCES Le processus appelant n'a pas les permissions d'acces necessaires pour ce type d'attachement et n'a pas la capacite CAP_IPC_OWNER dans l'espace de noms utilisateur qui gere son espace de noms IPC. EIDRM shmid pointe sur un segment detruit. EINVAL La valeur shmid n'est pas valable, mal alignee (c'est-a-dire pas alignee sur une page et SHM_RND n'a pas ete precise) ou la valeur shmaddr n'est pas valable, ou ne peut pas etre attache a shmaddr, ou SHM_REMAP a ete reclame et shmaddr est NULL. ENOMEM Pas assez de memoire pour le descripteur ou pour les tables de pages. shmdt() peut echouer avec une des erreurs suivantes : EINVAL Aucun segment de memoire partagee n'est attache a l'adresse shmaddr, ou bien shmaddr n'est pas aligne une limite de page. STANDARDS POSIX.1-2008. HISTORIQUE POSIX.1-2001, SVr4. Dans SVID 3 (ou peut etre auparavant), le type de l'argument shmaddr a ete modifie de char * en const void *, et le type de retour de shmat() de char * en void *. NOTES Apres un fork(2), l'enfant herite des segments de memoire partagee attaches. Apres un execve(2), tous les segments de memoire partagee sont detaches du (pas detruits). Lors d'un _exit(2), tous les segments de memoire partagee sont detaches du processus (pas detruits). Utiliser shmat() avec shmaddr egale a NULL est la maniere conseillee et portable d'attacher un segment de memoire partagee. Soyez conscients que le segment attache de cette maniere peut l'etre a des adresses differentes dans les differents processus. Ainsi, tout pointeur contenu dans la memoire partagee doit etre relatif (habituellement par rapport a l'adresse de depart du segment) et pas absolu. Sous Linux, il est possible d'attacher un segment de memoire partagee qui est deja marque pour effacement. Cependant, ce comportement n'est pas decrit par POSIX.1 et beaucoup d'autres implementations ne le permettent pas. Le parametre systeme suivant influe sur shmat() : SHMLBA Multiple d'adresse pour limite basse de segment. Lors d'une indication explicite d'adresse d'attache dans un appel shmat(), l'appelant devrait s'assurer que l'adresse est un multiple de cette valeur. Cela est necessaire sur certaines architectures, afin de s'assurer soit de bonne performances du cache de processeur, soit que differentes attaches du meme segment ont des vues coherentes dans le cache du processeur. SHMLBA est normalement un multiple de la taille de page du systeme (sur de nombreuses architectures Linux, SHMLBA est identique a la taille de page du systeme). L'implementation ne met pas de limite intrinseque par processus pour le nombre maximal de segments de memoire partagee (SHMSEG). EXEMPLES Les deux programmes presentes ci-dessous echangent une chaine en utilisant un segment de memoire partagee. Davantage de details a leur sujet sont donnes ci-dessous. Tout d'abord, nous presentons une session d'interpreteur qui montre leur utilisation. Dans une fenetre de terminal, nous executons le programme << reader >> qui cree un segment de memoire partagee System V et un ensemble de semaphores System V. Le programme affiche les identifiants des objets crees puis attend que le semaphore modifie la valeur. $ ./svshm_string_read shmid = 1114194; semid = 15 Dans une autre fenetre de terminal, on execute le programme << writer >>. Ce programme prend trois parametres en ligne de commande : les identifiants du segment de memoire partagee et le jeu de semaphore, crees par le programme << reader >> et une chaine. Il attache le segment de memoire partagee existant, copie la chaine dans la memoire partagee et modifie la valeur du semaphore. $ ./svshm_string_write 1114194 15 'Bonjour' De retour dans le terminal ou s'execute << reader >>, on voit que le programme a cesse d'attendre le semaphore et affiche la chaine copiee dans le segment de memoire partagee par << writer >> : Bonjour Source du programme : svshm_string.h Le fichier d'en-tete suivant est inclus dans les programmes << reader >> et << writer >> : /* svshm_string.h Sous licence GNU General Public v2 ou posterieure. */ #include #include #include #include #include #include #include #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \ } while (0) union semun { /* Utilise dans les appels semctl() */ int val; struct semid_ds * buf; unsigned short * array; #if defined(__linux__) struct seminfo * __buf; #endif }; #define MEM_SIZE 4096 Source du programme : svshm_string_read.c Le programme << reader >> cree un segment de memoire partagee et un ensemble de semaphores contenant un semaphore. Il attache ensuite l'objet en memoire partagee a son espace d'adressage et initialise la valeur du semaphore a 1. Enfin, il attend que la valeur du semaphore devienne 0, apres quoi il affiche la chaine qui a ete copiee dans le segment de memoire partagee par << writer >>. /* svshm_string_read.c Sous licence GNU General Public v2 ou posterieure. */ #include #include #include #include #include #include "svshm_string.h" int main(void) { int semid, shmid; char *addr; union semun arg, dummy; struct sembuf sop; /* Creer la memoire partagee et le jeu de semaphores contenant un semaphore. */ shmid = shmget(IPC_PRIVATE, MEM_SIZE, IPC_CREAT | 0600); if (shmid == -1) errExit("shmget"); semid = semget(IPC_PRIVATE, 1, IPC_CREAT | 0600); if (semid == -1) errExit("semget"); /*Attacher la memoire partagee a notre espace d'adressage. */ addr = shmat(shmid, NULL, SHM_RDONLY); if (addr == (void *) -1) errExit("shmat"); /* Initialiser le semaphore 0 du jeu a la valeur 1. */ arg.val = 1; if (semctl(semid, 0, SETVAL, arg) == -1) errExit("semctl"); printf("shmid = %d; semid = %d\n", shmid, semid); /* Attendre que la valeur du semaphore devienne 0. */ sop.sem_num = 0; sop.sem_op = 0; sop.sem_flg = 0; if (semop(semid, &sop, 1) == -1) errExit("semop"); /* Afficher la chaine a partir de la memoire partagee. */ printf("%s\n", addr); /* Supprimer la memoire partagee et le jeu de semaphores. */ if (shmctl(shmid, IPC_RMID, NULL) == -1) errExit("shmctl"); if (semctl(semid, 0, IPC_RMID, dummy) == -1) errExit("semctl"); exit(EXIT_SUCCESS); } Source du programme : svshm_string_write.c Le programme << writer >> prend trois parametres en ligne de commande : les identifiants du segment de memoire partagee et du jeu de semaphore crees par << reader >> et une chaine. Il attache le segment de memoire partagee a son espace d'adressage, puis decremente la valeur du semaphore a 0 pour informer << reader >> qu'il peut examiner le contenu de la memoire partagee. /* svshm_string_write.c Sous licence GNU General Public v2 ou posterieure. */ #include #include #include #include #include #include "svshm_string.h" int main(int argc, char *argv[]) { int semid, shmid; char *addr; size_t len; struct sembuf sop; if (argc != 4) { fprintf(stderr, "Utilisation : %s shmid semid string\n", argv[0]); exit(EXIT_FAILURE); } len = strlen(argv[3]) + 1; /* +1 pour inclure le '\0' final */ if (len > MEM_SIZE) { fprintf(stderr, "La chaine est trop longue !\n"); exit(EXIT_FAILURE); } /* Obtenir les identifiants de l'objet depuis la ligne de commande. */ shmid = atoi(argv[1]); semid = atoi(argv[2]); /* Attacher la memoire partagee dans notre espace d'adressage et copier la chaine (et notamment l'octet NULL final) dans la memoire. */ addr = shmat(shmid, NULL, 0); if (addr == (void *) -1) errExit("shmat"); memcpy(addr, argv[3], len); /* Decrementer le semaphore a 0 */ sop.sem_num = 0; sop.sem_op = -1; sop.sem_flg = 0; if (semop(semid, &sop, 1) == -1) errExit("semop"); exit(EXIT_SUCCESS); } VOIR AUSSI brk(2), mmap(2), shmctl(2), shmget(2), capabilities(7), shm_overview(7), sysvipc(7) TRADUCTION La traduction francaise de cette page de manuel a ete creee par Christophe Blaess , Stephan Rafin , Thierry Vignaud , Francois Micaux, Alain Portal , Jean-Philippe Guerard , Jean-Luc Coulon (f5ibh) , Julien Cristau , Thomas Huriaux , Nicolas Francois , Florentin Duneau , Simon Paillard , Denis Barbier , David Prevot et Jean-Philippe MENGUAL Cette traduction est une documentation libre ; veuillez vous reporter a la GNU General Public License version 3 concernant les conditions de copie et de distribution. Il n'y a aucune RESPONSABILITE LEGALE. Si vous decouvrez un bogue dans la traduction de cette page de manuel, veuillez envoyer un message a . Pages du manuel de Linux 6.06 31 octobre 2023 SHMOP(2)