SHMOP(2) System Calls Manual SHMOP(2) BEZEICHNUNG shmat, shmdt - System-V-Operationen mit gemeinsam benutztem Speicher BIBLIOTHEK Standard-C-Bibliothek (libc, -lc) UBERSICHT #include void *shmat(int shmid, const void *_Nullable 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: o Falls shmaddr NULL ist, wahlt das System eine geeignete (freie), an einer Speicherseite ausgerichtete Adresse, um das Segment einzublenden. o 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. o Andernfalls muss shmaddr eine an einer Speicherseite ausgerichtete Adresse sein, an welcher das Einblenden beginnt. Zusatzlich zu SHM_RND durfen die folgenden Schalter im Bitmask-Argument von shmflg angegeben werden: SHM_EXEC (Linux-spezifisch; seit Linux 2.6.9) ermoglicht, dass der Inhalt des Segments ausgefuhrt wird. Der Aufrufende muss auf dem Segment Ausfuhrungsrechte besitzen. SHM_RDONLY blendet das Segment mit Lesezugriff ein. Der Prozess muss die Berechtigung fur 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 fur 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 Grosse des Segments ersetzen soll. (Falls bereits eine Abbildung in diesem Adressbereich existiert, wurde dies normalerweise zu dem Fehler EINVAL fuhren.) In diesem Fall darf shmaddr nicht NULL sein. Der brk(2)-Wert des aufrufenden Prozesses wird durch das Einblenden nicht verandert. 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: o shm_atime wird auf die aktuelle Zeit gesetzt. o shm_lpid wird auf die Prozesskennung des aufrufenden Prozesses gesetzt. o shm_nattch wird um Eins erhoht. shmdt() shmdt() lost 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 Ruckgabewert des einbendenden shat()-Aufrufs entspricht. Nach einem erfolgreichen shmdt()-Aufruf aktualisiert das System die Bestandteile der dem Speichersegment zugeordneten Struktur shmid_ds wie folgt: o shm_dtime wird auf die aktuelle Zeit gesetzt. o shm_lpid wird auf die Prozesskennung des aufrufenden Prozesses gesetzt. o shm_nattch wird um Eins verringert. Wenn es dabei zu 0 wird und das Segment zum Loschen markiert ist, wird es geloscht. RUCKGABEWERT Bei Erfolg gibt shmat() die Adresse des eingeblendeten gemeinsamen Speichersegments zuruck; bei einem Fehler wird (void *) -1 zuruckgegeben und errno gesetzt, um den Fehlers anzuzeigen. Bei Erfolg gibt shmdt() 0 zuruck; bei einem Fehler wird -1 zuruckgegeben und errno gesetzt, um den Fehlers anzuzeigen. FEHLER shmat() kann mit einem der folgenden Fehler fehlschlagen: EACCES Dem aufrufenden Prozess fehlen die notigen Zugriffsrechte fur 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 Ungultiger shmid-Wert, nicht ausgerichteter (d.h. nicht an die Seitengrosse angepasst und SHM_RND wurde nicht angegeben) oder ungultiger shmaddr-Wert oder es wurde SHM_REMAP angegeben und shmaddr war NULL. ENOMEM Es konnte kein Speicher fur den Deskriptor oder die Seitentabellen reserviert werden. shmdt() kann mit einem der folgenden Fehler fehlschlagen: EINVAL Es ist kein gemeinsames Speichersegment in shmaddr eingeblendet oder shmaddr ist nicht an der Seitengrenze ausgerichtet. STANDARDS POSIX.1-2008. GESCHICHTE POSIX.1-2001, SVr4. In SVID 3 (oder vielleicht fruher) wurde der Typ des Arguments shmaddr von char * in const void * und der von shmat() zuruckgegebene Typ von char * in void * geandert. ANMERKUNGEN Nach einem fork(2) erbt der Kindprozess das eingeblendete gemeinsame Speichersegment. Nach einem exec(2) sind alle eingeblendeten gemeinsamen Speichersegmente vom Prozess abgelost. Bei einem exit(2) sind alle eingeblendeten gemeinsamen Speichersegmente vom Prozess abgelost. Die bevorzugte, portierbare Moglichkeit, 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 mussen alle innerhalb des gemeinsamen Speichers verwalteten Zeiger relativ (typischerweise zur Startadresse des Segments) statt absolut sein. Unter Linux ist es moglich, sogar ein gemeinsames Speichersegment einzublenden, wenn es bereits zum Loschen markiert ist. POSIX.1 spezifiziert dieses Verhalten jedoch nicht und andere Implementierungen unterstutzen 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 gewahrleisten oder um sicherzustellen, dass unterschiedliche Einblendungen desselben Segments konsistente Ansichten innerhalb des CPU-Zwischenspeichers haben. SHMLBA ist normalerweise irgendein Vielfaches von der Seitengrosse des Systems. (Auf vielen Linux-Architekturen ist SHMLBA dasselbe wie die Seitengrosse des Systems.) Die Implementierung hat keine inharenten pro-Prozess-Einschrankungen bezuglich der maximalen Anzahl von gemeinsamen Speichersegmenten (SHMSEG). BEISPIELE Die zwei nachfolgend aufgefuhrten Programme tauschen eine Zeichenkette uber ein gemeinsames Speichersegment aus. Weitere Details uber die Programme finden Sie nachfolgend. Zuerst wird eine Shell-Sitzung gezeigt, die ihre Verwendung zeigt. In einem Terminalfenster fuhren wir das >>Lese<<-Programm aus, das ein gemeinsam benutztes Speichersegment und eine Semaphoren-Gruppe gemass System-V erstellt. Das Programm gibt die Kennung der erstellten Objekte aus und wartet dann darauf, dass die Semaphore ihren Wert andern. $ ./svshm_string_read shmid = 1114194; semid = 15 In einem anderen Terminal-Fenster fuhren 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 verandert den Wert der Semaphore. $ ./svshm_string_write 1114194 15 'Hallo, Welt' In dem Terminal-Fenster, in dem das >>Lese<<-Programm lauft, konnen wir sehen, dass das Programm aufgehort 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: /* svshm_string.h Lizenziert unter der GNU General Public License v2 oder neuer. */ #ifndef SVSHM_STRING_H #define SVSHM_STRING_H #include #include #include #define errExit(msg) do { perror(msg); 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 enthalt. Es blendet dann das gemeinsam benutzte Speicherobjekt in seinen Adressraum ein und initialisiert den Semaphoren-Wert auf 1. Schliesslich 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 #include #include #include #include #include "svshm_string.h" int main(void) { int semid, shmid; char *addr; union semun arg, dummy; struct sembuf sop; /* Gemeinsam benutzten Speicher und eine Semaphoren-Gruppe, die eine Semaphore enthalt, erstellen. */ 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"); /* 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 #include #include #include #include #include "svshm_string.h" int main(int argc, char *argv[]) { int semid, shmid; char *addr; size_t size; struct sembuf sop; if (argc != 4) { fprintf(stderr, "Aufruf: %s shmid semid string\n", argv[0]); exit(EXIT_FAILURE); } size = strlen(argv[3]) + 1; /* +1, um abschliessende >>\0<< einzuschliessen */ if (size > MEM_SIZE) { fprintf(stderr, "Zeichenkette ist zu gross!\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 (einschliesslich abschliessendem Nullbyte) in den Speicher kopieren */ addr = shmat(shmid, NULL, 0); if (addr == (void *) -1) errExit("shmat"); memcpy(addr, argv[3], size); /* 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) UBERSETZUNG Die deutsche Ubersetzung dieser Handbuchseite wurde von Ralf Demmer , Chris Leick und Helge Kreutzmann erstellt. Diese Ubersetzung ist Freie Dokumentation; lesen Sie die GNU General Public License Version 3 oder neuer bezuglich der Copyright-Bedingungen. Es wird KEINE HAFTUNG ubernommen. Wenn Sie Fehler in der Ubersetzung dieser Handbuchseite finden, schicken Sie bitte eine E-Mail an die Mailingliste der Ubersetzer . Linux man-pages 6.12 17. November 2024 SHMOP(2)