Provided by: manpages-de-dev_4.13-4_all bug

BEZEICHNUNG

       shmat, shmdt - System-V-Operationen mit gemeinsam benutztem Speicher

ÜBERSICHT

       #include <sys/types.h>
       #include <sys/shm.h>

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

       int shmdt(const void *shmaddr);

BESCHREIBUNG

   shmat()
       shmat()  blendet  das  durch  shmid bezeichnete gemeinsame System-V-Speichersegment in den Adressraum des
       aufrufenden Prozesses ein. Die Adresse der Einblendung  wird  durch  shmaddr  nach  einem  der  folgenden
       Kriterien bestimmt:

       • Falls  shmaddr  NULL ist, wählt das System eine geeignete (freie), an einer Speicherseite ausgerichtete
         Adresse, um das Segment einzublenden.

       • Wenn shmaddr nicht NULL ist und SHM_RND in shmflg angegeben wurde, wird die Adresse durch Abrundung von
         shmaddr bis auf ein Vielfaches von SHMLBA bestimmt.

       • Andernfalls muss shmaddr eine an  einer  Speicherseite  ausgerichtete  Adresse  sein,  an  welcher  das
         Einblenden beginnt.

       Zusätzlich zu SHM_RND dürfen die folgenden Schalter im Bitmask-Argument von shmflg angegeben werden:

       SHM_EXEC (Linux-spezifisch; seit Linux 2.6.9)
              ermöglicht,  dass  der  Inhalt  des  Segments ausgeführt wird. Der Aufrufende muss auf dem Segment
              Ausführungsrechte besitzen.

       SHM_RDONLY
              blendet das Segment mit Lesezugriff ein. Der Prozess muss die Berechtigung  für  Lesezugriffe  auf
              das  Segment  besitzen.  Falls dieser Schalter nicht angegeben ist, wird das Segment mit Lese- und
              Schreibzugriff eingeblendet und der Prozess muss die Berechtigung für  Lese-  und  Schreibzugriffe
              auf  das  Segment  besitzen.  Ein  gemeinsames Speichersegment mit reinem Schreibzugriff ist nicht
              vorgesehen.

       SHM_REMAP (Linux-spezifisch)
              Dieser Schalter gibt an, dass das Abbilden des Segments jedes existierende Abbilden im Bereich von
              shmaddr bis zur Größe des  Segments  ersetzen  soll.  (Falls  bereits  eine  Abbildung  in  diesem
              Adressbereich  existiert,  würde  dies  normalerweise zu dem Fehler EINVAL führen.) In diesem Fall
              darf shmaddr nicht NULL sein.

       Der brk(2)-Wert des aufrufenden Prozesses wird durch das Einblenden nicht verändert. Das Segment wird bei
       Beenden des Prozesses automatisch abgetrennt. Das gleiche Segment kann mit  Lese-  sowie  mit  Lese-  und
       Schreibzugriff einmal oder mehrfach in den Adressraum des Prozesses eingeblendet werden.

       Nach  einem erfolgreichen shmat()-Aufruf aktualisiert das System die Bestandteile der dem Speichersegment
       zugeordneten shmid_ds-Struktur (siehe shmctl(2)) wie folgt:

       • shm_atime wird auf die aktuelle Zeit gesetzt.

       • shm_lpid wird auf die Prozesskennung des aufrufenden Prozesses gesetzt.

       • shm_nattch wird um Eins erhöht.

   shmdt()
       shmdt() löst das gemeinsame Speichersegment, das an der Adresse shmaddr liegt,  aus  dem  Adressraum  des
       aufrufenden   Prozesses.  Das  zu  entfernende  gemeinsame  Speichersegment  muss  momentan  mit  shmaddr
       eingeblendet sein, das dem Rückgabewert des einbendenden shat()-Aufrufs entspricht.

       Nach einem erfolgreichen shmdt()-Aufruf aktualisiert das System die Bestandteile der dem  Speichersegment
       zugeordneten Struktur shmid_ds wie folgt:

       • shm_dtime wird auf die aktuelle Zeit gesetzt.

       • shm_lpid wird auf die Prozesskennung des aufrufenden Prozesses gesetzt.

       • shm_nattch  wird  um Eins verringert. Wenn es dabei zu 0 wird und das Segment zum Löschen markiert ist,
         wird es gelöscht.

RÜCKGABEWERT

       Bei Erfolg gibt shmat() die Adresse des eingeblendeten gemeinsamen  Speichersegments  zurück;  bei  einem
       Fehler wird (void *) -1 zurückgegeben und errno so gesetzt, dass es den Grund des Fehlers anzeigt.

       Bei  Erfolg  gibt  shmdt() 0 zurück; bei einem Fehler wird -1 zurückgegeben und errno so gesetzt, dass es
       den Grund des Fehlers anzeigt.

FEHLER

       Wenn shmat() fehlschlägt, wird errno mit einem der folgenden Werte belegt:

       EACCES Dem aufrufenden Prozess fehlen die nötigen Zugriffsrechte für den angeforderten  Einblendetyp  und
              die CAP_IPC_OWNER-Capability in dem Benutzernamensraum, der seinen IPC-Namensraum beherrscht.

       EIDRM  shmid zeigt auf einen entfernten Bezeichner.

       EINVAL Ungültiger  shmid-Wert,  nicht ausgerichteter (d.h. nicht an die Seitengröße angepasst und SHM_RND
              wurde nicht angegeben) oder ungültiger shmaddr-Wert oder es wurde SHM_REMAP angegeben und  shmaddr
              war NULL.

       ENOMEM Es konnte kein Speicher für den Deskriptor oder die Seitentabellen reserviert werden.

       Wenn shmdt() fehlschlägt, wird errno mit einem der folgenden Werte belegt:

       EINVAL Es  ist  kein  gemeinsames  Speichersegment  in shmaddr eingeblendet oder shmaddr ist nicht an der
              Seitengrenze ausgerichtet.

KONFORM ZU

       POSIX.1-2001, POSIX.1-2008, SVr4.

       In SVID 3 (oder vielleicht früher) wurde der Typ des Arguments shmaddr von char * in const void * und der
       von shmat() zurückgegebene Typ von char * in void * geändert.

ANMERKUNGEN

       Nach einem fork(2) erbt der Kindprozess das eingeblendete gemeinsame Speichersegment.

       Nach einem exec(2) sind alle eingeblendeten gemeinsamen Speichersegmente vom Prozess abgelöst.

       Bei einem exit(2) sind alle eingeblendeten gemeinsamen Speichersegmente vom Prozess abgelöst.

       Die bevorzugte, portierbare Möglichkeit, ein gemeinsames  Speichersegment  einzublenden,  besteht  darin,
       shmat()  mit  shmaddr  gleich  NULL  zu  benutzen.  Sie sollten wissen, dass das eingeblendete gemeinsame
       Speichersegment auf diese Art an unterschiedliche Adressen in  unterschiedlichen  Prozessen  eingeblendet
       werden  kann.  Deshalb  müssen  alle  innerhalb  des  gemeinsamen  Speichers  verwalteten  Zeiger relativ
       (typischerweise zur Startadresse des Segments) statt absolut sein.

       Unter Linux ist es möglich, sogar ein gemeinsames  Speichersegment  einzublenden,  wenn  es  bereits  zum
       Löschen  markiert  ist.  POSIX.1  spezifiziert dieses Verhalten jedoch nicht und andere Implementierungen
       unterstützen es nicht.

       Der folgende Systemparameter beeinflusst shmat():

       SHMLBA Untere Segmentgrenze des Adressvielfachen. Wenn in einem Aufruf von shmat() eine Adresse  explizit
              angegeben  wurde.  sollte  der  Aufrufende  sicherstellen,  dass die Adresse ein Vielfaches dieses
              Wertes  ist.  Dies  ist  auf  einigen  Architekturen  notwendig,  um  eine   gute   Leistung   des
              CPU-Zwischenspeichers   zu   gewährleisten   oder   um   sicherzustellen,   dass  unterschiedliche
              Einblendungen desselben Segments konsistente Ansichten innerhalb des CPU-Zwischenspeichers  haben.
              SHMLBA  ist  normalerweise  irgendein  Vielfaches  von  der  Seitengröße  des Systems. (Auf vielen
              Linux-Architekturen ist SHMLBA dasselbe wie die Seitengröße des Systems.)

       Die Implementierung hat keine inhärenten pro-Prozess-Einschränkungen bezüglich der maximalen  Anzahl  von
       gemeinsamen Speichersegmenten (SHMSEG).

BEISPIELE

       Die   zwei   nachfolgend   aufgeführten   Programme  tauschen  eine  Zeichenkette  über  ein  gemeinsames
       Speichersegment aus. Weitere Details  über  die  Programme  finden  Sie  nachfolgend.  Zuerst  wird  eine
       Shell-Sitzung gezeigt, die ihre Verwendung zeigt.

       In  einem Terminalfenster führen wir das »Lese«-Programm aus, das ein gemeinsam benutztes Speichersegment
       und eine Semaphoren-Gruppe gemäß System-V erstellt. Das Programm gibt die Kennung der erstellten  Objekte
       aus und wartet dann darauf, dass die Semaphore ihren Wert ändern.

           $ ./svshm_string_read
           shmid = 1114194; semid = 15

       In  einem  anderen  Terminal-Fenster  führen  wir  das  »Schreibe«-Programm  aus. Das »Schreibe«-Programm
       akzeptiert drei Befehlszeilenargumente:  die  Kennungen  des  vom  »Lese«-Programm  erstellten  gemeinsam
       benutzten  Speichersegments  und  die  erstellte  Semaphoren-Gruppe und eine Zeichenkette. Es blendet das
       bestehende gemeinsam benutzte Speichersegment ein, kopiert die Zeichenkette in  den  gemeinsam  benutzten
       Speicher und verändert den Wert der Semaphore.

           $ ./svshm_string_write 1114194 15 'Hallo, Welt'

       In  dem Terminal-Fenster, in dem das »Lese«-Programm läuft, können wir sehen, dass das Programm aufgehört
       hat, auf die Semaphore zu warten und die Zeichenkette ausgegeben hat, die vom  Schreibe-Programm  in  den
       gemeinsam benutzten Speicher kopiert wurde:

           Hallo Welt

   Quelle des Programms: svshm_string.h
       Die folgende Header-Datei wird von den »Lese«- und »Schreibe«-Programmen eingebunden:

           #include <sys/types.h>
           #include <sys/ipc.h>
           #include <sys/shm.h>
           #include <sys/sem.h>
           #include <stdio.h>
           #include <stdlib.h>
           #include <string.h>

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

           union semun {                   /* Wird in Aufrufen von semctl() verwandt */
               int                 val;
               struct semid_ds *   buf;
               unsigned short *    array;
           #if defined(__linux__)
               struct seminfo *    __buf;
           #endif
           };

           #define MEM_SIZE 4096

   Quelle des Programms: svshm_string_read.c
       Das  »Lese«-Programm erstellt ein gemeinsam benutztes Speichersegment und eine Semaphore-Gruppe, die eine
       Semaphore enthält. Es blendet dann das gemeinsam benutzte Speicherobjekt in  seinen  Adressraum  ein  und
       initialisiert den Semaphoren-Wert auf 1. Schließlich wartet das Programm darauf, dass der Semaphoren-Wert
       0  wird  und  gibt  danach  die  Zeichenkette  aus,  die  durch den »Schreiber« in das gemeinsam benutzte
       Speichersegment kopiert wurde.

           /* svshm_string_read.c

              Lizenziert unter der GNU General Public License v2 oder neuer.
           */
           #include "svshm_string.h"

           int
           main(int argc, char *argv[])
           {
               int semid, shmid;
               union semun arg, dummy;
               struct sembuf sop;
               char *addr;
           int
           main(int argc, char *argv[])
           {
               struct stat sb;
               char *buf;
               ssize_t nbytes, bufsiz;

               /* Gemeinsam benutzten Speicher und eine Semaphoren-Gruppe, die eine
                  Semaphore enthält, erstellen */

               shmid = shmget(IPC_PRIVATE, MEM_SIZE, IPC_CREAT | 0600);
               if (shmid == -1)
                   errExit("shmget");

               semid = semget(IPC_PRIVATE, 1, IPC_CREAT | 0600);
               if (shmid == -1)
                   errExit("shmget");

               /* Gemeinsamen Speicher in unseren Adressraum einblenden */

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

               /* Semaphore 0 in der Gruppe mit dem Wert 1 initialisieren */

               arg.val = 1;
               if (semctl(semid, 0, SETVAL, arg) == -1)
                   errExit("semctl");

               printf("shmid = %d; semid = %d\n", shmid, semid);

               /* Darauf warten, dass der Semaphore-Wert 0 wird */

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

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

               /* Die Zeichenkette aus dem gemeinsamen Speicher ausgeben */

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

               /* Den gemeinsam benutzten Speicher und die Semaphoren-Gruppe entfernen */

               if (shmctl(shmid, IPC_RMID, NULL) == -1)
                   errExit("shmctl");
               if (semctl(semid, 0, IPC_RMID, dummy) == -1)
                   errExit("semctl");

               exit(EXIT_SUCCESS);
           }

   Quelle des Programms: svshm_string_write.c
       Das Schreibe-Programm akzeptiert drei  Befehlszeilenargumente:  die  Kennungen  des  vom  »Lese«-Programm
       bereits erstellten, gemeinsam benutzten Speichersegments und die Sempahoren-Gruppe und eine Zeichenkette.
       Es  blendet  das  bestehende  gemeinsam benutzte Speichersegment in seinen Adressraum ein, verringert den
       Semaphoren-Wert auf 0, um den »Leser« zu informieren, dass er jetzt den Inhalt  des  gemeinsam  benutzten
       Speichers untersuchen kann.

           /* svshm_string_write.c

              Lizenziert unter der GNU General Public License v2 oder neuer.
           */
           #include "svshm_string.h"

           int
           main(int argc, char *argv[])
           {
               int semid, shmid;
               struct sembuf sop;
               char *addr;
               size_t len;

               if (argc != 4) {
                   fprintf(stderr, "Aufruf: %s Shmid Semid Zeichenkette\n", argv[0]);
                   exit(EXIT_FAILURE);
               }

               len = strlen(argv[3]) + 1;  /* +1, um abschließende '\0' einzuschließen */
               if (len > MEM_SIZE) {
                   fprintf(stderr, "Zeichenkette ist zu groß!\n");
                   exit(EXIT_FAILURE);
               }

               /* Objektkennungen von der Befehlszeile erhalten */

               shmid = atoi(argv[1]);
               semid = atoi(argv[2]);

               /* Gemeinsam benutzten Speicher in unseren Adressraum einblenden und Zeichenkette
                  (einschließlich abschließendem NULL-Byte) in den Speicher kopieren */

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

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

               /* Semaphore auf 0 verringern */

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

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

               exit(EXIT_SUCCESS);
           }

SIEHE AUCH

       brk(2), mmap(2), shmctl(2), shmget(2), capabilities(7), shm_overview(7), sysvipc(7)

KOLOPHON

       Diese  Seite  ist  Teil  der  Veröffentlichung  5.10  des Projekts Linux-man-pages. Eine Beschreibung des
       Projekts, Informationen, wie Fehler gemeldet werden können sowie die aktuelle Version dieser Seite finden
       sich unter https://www.kernel.org/doc/man-pages/.

ÜBERSETZUNG

       Die deutsche Übersetzung dieser Handbuchseite wurde von Ralf  Demmer  <rdemmer@rdemmer.de>,  Chris  Leick
       <c.leick@vollbio.de> 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.

Linux                                            11. April 2020                                         SHMOP(2)