Provided by: manpages-fr-dev_4.23.1-1_all bug

NOM

       shmat, shmdt - Opérations sur la mémoire partagée System V

BIBLIOTHÈQUE

       Bibliothèque C standard (libc, -lc)

SYNOPSIS

       #include <sys/shm.h>

       void *shmat(int shmid, const void *_Nullable shmaddr, int shmflg);
       int shmdt(const void *shmaddr);

DESCRIPTION

   shmat()
       La fonction shmat() attache le segment de mémoire partagée System V identifié par shmid au
       segment de données du processus appelant. L'adresse d'attachement est indiquée par shmaddr
       avec les critères suivants :

       -  Si shmaddr vaut NULL, le système choisit une adresse (non utilisée) alignée sur la page
          convenant pour attacher le segment.

       -  Si shmaddr n'est pas NULL et si SHM_RND est indiqué dans shmflg, l'attachement a lieu à
          l'adresse égale à shmaddr arrondie au multiple inférieur de SHMLBA.

       -  Sinon, shmaddr doit être alignée sur une frontière de page, où l'attachement a lieu.

       En  plus  de  SHM_RND,  les  attributs suivants peuvent être indiqués dans le paramètre de
       masque shmflg :

       SHM_EXEC (spécifique à Linux, depuis Linux 2.6.9)
              Autoriser l'exécution du contenu du segment.  L'appelant  doit  disposer  du  droit
              d'exécution 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 indiqué, le  segment  est  attaché  en
              lecture et écriture, et le processus doit disposer des deux permissions d'accès. Il
              n'y a pas de notion d'écriture seule pour les segments de mémoire partagée.

       SHM_REMAP (spécifique à Linux)
              Cet attribut indique que la projection du segment  doit  remplacer  une  projection
              précédente  dans  l'intervalle commençant en shmaddr et s'étendant sur la taille du
              segment. Normalement une erreur EINVAL devrait se produire si une projection existe
              déjà dans l'intervalle indiqué. Dans ce cas, shmaddr ne doit pas être NULL.

       La valeur brk(2) du processus appelant n'est pas altérée par l'attachement. Le segment est
       automatiquement détaché quand le processus se termine. Le même segment peut être attaché à
       la  fois  en  lecture  seule  et  en  lecture/écriture.  Il peut également être attaché en
       plusieurs endroits de l'espace d'adressage du processus.

       Quand shmat() réussit, les membres de la structure shmid_ds associée au segment de mémoire
       partagée (consultez shmctl(2)) sont mis à jour ainsi :

       -  shm_atime correspond à l'heure actuelle.

       -  shm_lpid contient le PID de l'appelant.

       -  shm_nattch est incrémenté de 1.

   shmdt()
       La  fonction shmdt() détache le segment de mémoire partagée situé à l'adresse indiquée par
       shmaddr. Le segment doit être effectivement attaché, et l'adresse shmaddr doit être  celle
       renvoyée précédemment par l'appel shmat().

       Quand shmdt() réussit, les membres de la structure shmid_ds associée au segment de mémoire
       partagée sont mis à jour ainsi par le système :

       -  shm_dtime correspond à l'heure actuelle.

       -  shm_lpid contient le PID de l'appelant.

       -  shm_nattch est décrémenté de 1. S'il devient nul et  si  le  segment  est  marqué  pour
          destruction, il est effectivement détruit.

VALEUR RENVOYÉE

       S'il  réussit,  shmat() renvoie l'adresse d'attachement du segment de mémoire partagée. En
       cas d'échec (void *) -1 est renvoyé, et errno est positionné pour indiquer l'erreur.

       S'il réussit, shmdt() renvoie 0. En cas d'échec, -1 est renvoyé et  errno  est  positionné
       pour indiquer l'erreur.

ERREURS

       shmat() peut échouer avec une des erreurs suivantes :

       EACCES Le  processus  appelant  n'a  pas  les permissions d'accès nécessaires pour ce type
              d'attachement  et  n'a  pas  la  capacité  CAP_IPC_OWNER  dans  l'espace  de   noms
              utilisateur qui gère son espace de noms IPC.

       EIDRM  shmid pointe sur un segment détruit.

       EINVAL La  valeur  shmid  n'est pas valable, mal alignée (c'est-à-dire pas alignée sur une
              page et SHM_RND n'a pas été précisé) ou la valeur shmaddr n'est pas valable, ou  ne
              peut pas être attaché à shmaddr, ou SHM_REMAP a été réclamé et shmaddr est NULL.

       ENOMEM Pas assez de mémoire pour le descripteur ou pour les tables de pages.

       shmdt() peut échouer avec une des erreurs suivantes :

       EINVAL Aucun  segment  de  mémoire  partagée  n'est  attaché  à l'adresse shmaddr, ou bien
              shmaddr n'est pas aligné une limite de page.

STANDARDS

       POSIX.1-2008.

HISTORIQUE

       POSIX.1-2001, SVr4.

       Dans SVID 3 (ou peut être auparavant), le type de l'argument  shmaddr  a  été  modifié  de
       char * en const void *, et le type de retour de shmat() de char * en void *.

NOTES

       Après un fork(2), l'enfant hérite des segments de mémoire partagée attachés.

       Après un execve(2), tous les segments de mémoire partagée sont détachés du (pas détruits).

       Lors  d'un _exit(2), tous les segments de mémoire partagée sont détachés du processus (pas
       détruits).

       Utiliser shmat() avec  shmaddr  égale  à  NULL  est  la  manière  conseillée  et  portable
       d'attacher  un  segment  de  mémoire  partagée. Soyez conscients que le segment attaché de
       cette manière peut l'être à des adresses différentes dans les différents processus. Ainsi,
       tout  pointeur  contenu  dans  la  mémoire  partagée doit être relatif (habituellement par
       rapport à l'adresse de départ du segment) et pas absolu.

       Sous Linux, il est possible d'attacher un segment de mémoire partagée qui est déjà  marqué
       pour  effacement.  Cependant,  ce  comportement  n'est  pas décrit par POSIX.1 et beaucoup
       d'autres implémentations ne le permettent pas.

       Le paramètre système 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  nécessaire  sur  certaines
              architectures, afin de s’assurer soit de bonne performances du cache de processeur,
              soit que différentes attaches du même segment ont des vues cohérentes dans le cache
              du  processeur.  SHMLBA est normalement un multiple de la taille de page du système
              (sur de nombreuses architectures Linux, SHMLBA est identique à la taille de page du
              système).

       L'implémentation  ne met pas de limite intrinsèque par processus pour le nombre maximal de
       segments de mémoire partagée (SHMSEG).

EXEMPLES

       Les deux programmes présentés ci-dessous échangent une chaîne en utilisant un  segment  de
       mémoire  partagée. Davantage de détails à leur sujet sont donnés ci-dessous. Tout d'abord,
       nous présentons une session d'interpréteur qui montre leur utilisation.

       Dans une fenêtre de terminal, nous exécutons le programme « reader » qui crée  un  segment
       de  mémoire  partagée System V et un ensemble de sémaphores System V. Le programme affiche
       les identifiants des objets créés puis attend que le sémaphore modifie la valeur.

           $ ./svshm_string_read
           shmid = 1114194; semid = 15

       Dans une autre fenêtre de terminal, on exécute le programme « writer ». Ce programme prend
       trois paramètres en ligne de commande : les identifiants du segment de mémoire partagée et
       le jeu de sémaphore, créés par le programme  « reader »  et  une  chaîne.  Il  attache  le
       segment  de mémoire partagée existant, copie la chaîne dans la mémoire partagée et modifie
       la valeur du sémaphore.

           $ ./svshm_string_write 1114194 15 'Bonjour'

       De retour dans le terminal où s'exécute « reader », on  voit  que  le  programme  a  cessé
       d'attendre  le  sémaphore  et affiche la chaîne copiée dans le segment de mémoire partagée
       par « writer » :

           Bonjour

   Source du programme : svshm_string.h
       Le fichier d'en-tête suivant est inclus dans les programmes « reader » et « writer » :

           /* svshm_string.h

              Sous licence GNU General Public v2 ou postérieure.
           */
           #ifndef SVSHM_STRING_H
           #define SVSHM_STRING_H

           #include <stdio.h>
           #include <stdlib.h>
           #include <sys/sem.h>

           #define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \
                                   } while (0)

           union semun {                   /* Utilisé dans les appels semctl() */
               int                 val;
               struct semid_ds     *buf;
               unsigned short      *array;
           #if defined(__linux__)
               struct seminfo      *__buf;
           #endif
           };

           #define MEM_SIZE 4096

           #endif  // include guard

   Source du programme : svshm_string_read.c
       Le programme « reader » crée un segment de mémoire partagée et un ensemble  de  sémaphores
       contenant  un  sémaphore.  Il  attache  ensuite  l'objet  en mémoire partagée à son espace
       d'adressage et initialise la valeur du sémaphore à 1. Enfin, il attend que  la  valeur  du
       sémaphore  devienne 0, après quoi il affiche la chaîne qui a été copiée dans le segment de
       mémoire partagée par « writer ».

           /* svshm_string_read.c

              Sous licence GNU General Public v2 ou postérieure.
           */
           #include <stdio.h>
           #include <stdlib.h>
           #include <sys/ipc.h>
           #include <sys/sem.h>
           #include <sys/shm.h>

           #include "svshm_string.h"

           int
           main(void)
           {
               int            semid, shmid;
               char           *addr;
               union semun    arg, dummy;
               struct sembuf  sop;

               /* Créer la mémoire partagée et le jeu de sémaphores contenant
                  un sémaphore. */

               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 mémoire partagée à notre espace d'adressage. */

               addr = shmat(shmid, NULL, SHM_RDONLY);
               if (addr == (void *) -1)
                   errExit("shmat");

               /* Initialiser le sémaphore 0 du jeu à 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 sémaphore devienne 0. */

               sop.sem_num = 0;
               sop.sem_op = 0;
               sop.sem_flg = 0;

               if (semop(semid, &sop, 1) == -1)
                   errExit("semop");

               /* Afficher la chaîne à partir de la mémoire partagée. */

               printf("%s\n", addr);

               /* Supprimer la mémoire partagée et le jeu de sémaphores. */

               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 paramètres en ligne de commande : les identifiants  du
       segment  de mémoire partagée et du jeu de sémaphore créés par « reader » et une chaîne. Il
       attache le segment de mémoire partagée à son espace d'adressage, puis décrémente la valeur
       du  sémaphore  à  0  pour informer « reader » qu'il peut examiner le contenu de la mémoire
       partagée.

           /* svshm_string_write.c

              Sous licence GNU General Public v2 ou postérieure.
           */
           #include <stdio.h>
           #include <stdlib.h>
           #include <string.h>
           #include <sys/sem.h>
           #include <sys/shm.h>

           #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 chaîne 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 mémoire partagée dans notre espace d'adressage et copier
                  la chaîne (et notamment l'octet NULL final) dans la mémoire. */

               addr = shmat(shmid, NULL, 0);
               if (addr == (void *) -1)
                   errExit("shmat");

               memcpy(addr, argv[3], len);

               /* Décrémenter le sémaphore à 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 française de cette  page  de  manuel  a  été  créée  par  Christophe  Blaess
       <https://www.blaess.fr/christophe/>,  Stéphan  Rafin  <stephan.rafin@laposte.net>, Thierry
       Vignaud <tvignaud@mandriva.com>, François Micaux, Alain  Portal  <aportal@univ-montp2.fr>,
       Jean-Philippe    Guérard   <fevrier@tigreraye.org>,   Jean-Luc   Coulon   (f5ibh)   <jean-
       luc.coulon@wanadoo.fr>,   Julien    Cristau    <jcristau@debian.org>,    Thomas    Huriaux
       <thomas.huriaux@gmail.com>, Nicolas François <nicolas.francois@centraliens.net>, Florentin
       Duneau <fduneau@gmail.com>, Simon Paillard <simon.paillard@resel.enst-bretagne.fr>,  Denis
       Barbier  <barbier@debian.org>,  David  Prévot <david@tilapin.org> et Jean-Philippe MENGUAL
       <jpmengual@debian.org>

       Cette traduction est une documentation libre ; veuillez vous reporter  à  la  GNU  General
       Public   License   version 3  ⟨https://www.gnu.org/licenses/gpl-3.0.html⟩  concernant  les
       conditions de copie et de distribution. Il n'y a aucune RESPONSABILITÉ LÉGALE.

       Si vous découvrez un bogue dans la traduction de cette page de manuel, veuillez envoyer un
       message à ⟨debian-l10n-french@lists.debian.org⟩.