oracular (2) shmdt.2.gz

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

NAZWA

       shmat, shmdt - operacje na segmentach pamięci dzielonej Systemu V

BIBLIOTEKA

       Standardowa biblioteka C (libc, -lc)

SKŁADNIA

       #include <sys/shm.h>

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

OPIS

   shmat()
       shmat()  dołącza  segment pamięci dzielonej Systemu V identyfikowany przez shmid do przestrzeni adresowej
       procesu, który ją wywołał. Adres, pod którym segment ma  być  widoczny  jest  przekazywany  w  parametrze
       shmaddr, przy czym system może przetworzyć ten adres w następujący sposób:

       •  Jeśli  shmaddr  jest  równy  NULL,  to  system  sam  wybierze  odpowiedni wyrównany do rozmiaru strony
          (nieużywany) adres, pod którym segment będzie widoczny.

       •  Jeśli shmaddr jest różny od NULL i w  shmflg  przekazany  został  znacznik  SHM_RND,  wówczas  segment
          zostanie dołączony pod adresem shmaddr zaokrąglonym w dół do wielokrotności SHMLBA.

       •  W innym przypadku shmaddr musi być wyrównanym do granicy strony adresem, pod którym nastąpi dołączenie
          segmentu.

       Oprócz SHM_RND można określić następujące znaczniki w argumencie maski bitowej shmflg:

       SHM_EXEC (charakterystyczne dla Linuksa; od Linuksa w wersji 2.6.9)
              Pozwala na wykonanie zawartości segmentu. Wywołujący musi mieć prawo wykonania segmentu.

       SHM_RDONLY
              Dołącza segment do dostępu tylko do odczytu. Proces wywołujący musi mieć prawa  odczytu  segmentu.
              Jeśli  znacznik  nie  jest  określona, w dołączanym segmencie możliwy jest dostęp do odczytu jak i
              zapisu, przy czym proces musi mieć prawa do  odczytu  i  zapisu  segmentu.  Nie  istnieje  pojęcie
              segmentu pamięci dzielonej tylko do zapisu.

       SHM_REMAP (charakterystyczne dla Linuksa)
              Ten  znacznik  oznacza,  że  odwzorowanie  tego  segmentu powinno zastąpić jakiekolwiek istniejące
              wcześniej odwzorowanie w zakresie rozpoczynającym się od shmaddr i rozciągającym  się  na  rozmiar
              segmentu. (Normalnie, gdy odwzorowanie w tym zakresie adresów już istnieje, powinien wystąpić błąd
              EINVAL). W tym przypadku shmaddr nie może być równy NULL.

       Wartość brk(2) procesu wywołującego nie jest zmieniana  podczas  dołączania  segmentu.  Segment  zostanie
       automatycznie  odłączony,  gdy  proces  się  zakończy.  Ten sam segment może być dołączony do przestrzeni
       adresowej procesu jako „tylko do odczytu” lub „do odczytu i zapisu” więcej niż raz.

       Pomyślne wywołanie shmdt aktualizuje pola struktury  shmid_ds  (patrz  shmctl(2))  opisującej  segment  w
       następujący sposób:

       •  shm_atime przypisywany jest bieżący czas.

       •  shm_lpid jest ustawiane na identyfikator procesu wywołującego.

       •  shm_nattch jest zwiększane o jeden.

   shmdt()
       shmdt odłącza segment pamięci dzielonej odwzorowany pod adresem podanym w shmaddr z przestrzeni adresowej
       procesu wywołującego tę funkcję. Przekazany funkcji w parametrze shmaddr adres musi  być  równy  adresowi
       zwróconemu wcześniej przez wywołanie shmat().

       Pomyślne wywołanie shmdt aktualizuje pola struktury shmid_ds opisującej segment w następujący sposób:

       •  shm_dtime przypisywany jest bieżący czas.

       •  shm_lpid jest ustawiane na identyfikator procesu wywołującego.

       •  shm_nattch  jest zmniejszane o jeden. Jeśli pole to osiągnie 0 i segment jest zaznaczony do usunięcia,
          wówczas zostanie on usunięty.

WARTOŚĆ ZWRACANA

       Jeśli się powiedzie, shmat() zwraca adres dołączonego segmentu pamięci dzielonej; w razie błędu  zwracane
       jest (void *) -1, a zmienna errno wskazuje błąd.

       Jeśli się powiedzie, shmdt() zwraca 0; w razie błędu zwracane jest -1, a zmienna errno wskazuje błąd.

BŁĘDY

       shmat() może zawieść z powodu następujących błędów:

       EACCES Proces wywołujący nie ma wystarczających uprawnień do dołączenia segmentu w żądany sposób oraz nie
              ma przywileju CAP_IPC_OWNER (ang. capability) w tej przestrzeni nazw użytkownika, która  odpowiada
              za przestrzeń nazw IPC.

       EIDRM  shmid wskazuje na usunięty identyfikator.

       EINVAL Niewłaściwa  wartość  parametru  shmid,  niewyrównana (do granicy strony i nie podano SHM_RND) lub
              niepoprawna wartość shmaddr albo  nieudane  dołączenie  pod  adresem  shmaddr  lub  został  podany
              znacznik SHM_REMAP, podczas gdy shmaddr było równe NULL.

       ENOMEM Brak pamięci na deskryptor lub tablice stron.

       shmdt() może zawieść z powodu następujących błędów:

       EINVAL Żaden  segment  pamięci  dzielonej  nie  jest  podłączony pod adresem shmaddr lub shmaddr nie jest
              wyrównany do granicy strony.

STANDARDY

       POSIX.1-2008.

HISTORIA

       POSIX.1-2001, SVr4.

       W SVID 3 (lub być może wcześniejszym) typ parametru shmaddr został zmieniony z char * na const void *,  a
       typ wyniku zwracanego przez shmat() z char * na void *.

UWAGI

       W wyniku wywołania fork(2) proces potomny dziedziczy dołączone segmenty pamięci dzielonej.

       Po wykonaniu exec(2) wszystkie dołączone segmenty pamięci dzielonej są odłączane od procesu.

       Po wykonaniu _exit(2) wszystkie dołączone segmenty pamięci dzielonej są odłączane od procesu.

       Używanie  shmat()  z  shmaddr  równym  NULL  jest zalecaną i przenośną metodą dołączania segmentu pamięci
       dzielonej. Trzeba jednak  być  świadomym,  że  ta  metoda  dołączania  segmentu  pamięci  dzielonej  może
       spowodować jego dołączenie pod różnymi adresami w różnych procesach.  W związku z tym wszystkie wskaźniki
       obsługiwane w pamięci dzielonej muszą być względne (zazwyczaj względem adresu początkowego segmentu), nie
       zaś bezwzględne.

       Linux  pozwala  na dołączenie segmentu pamięci dzielonej, nawet jeśli już został zaznaczony do usunięcia.
       Jednakże POSIX.1 nie określa takiego zachowania i wiele innych implementacji go nie obsługuje.

       Na wywołanie shmat() wpływa następujący parametr systemowy:

       SHMLBA Wielokrotność dolnej granicy adresu segmentu. Podczas bezpośredniego wskazania dołączonego  adresu
              w  wywołaniu  do  shmat(),  wywołujący  powinien  się  upewnić,  że adres jest wielokrotnością tej
              wartości. Jest to konieczne w przypadku  niektórych  architektur,  aby  zapewnić  dobrą  wydajność
              pamięci  podręcznej  procesora  lub  aby  zapewnić,  że różne dołączenia tego samego segmentu mają
              spójne widoki w pamięci podręcznej procesora. SHMLBA jest zwykle jakąś wielokrotnością systemowego
              rozmiaru  strony. (W wielu architekturach linuksowych wartość SHMLBA jest taka sama, jak systemowy
              rozmiar strony).

       Aktualna implementacja nie ma wewnętrznego ograniczenia na liczbę segmentów pamięci dzielonej dołączanych
       do jednego procesu (SHMSEG).

PRZYKŁADY

       Dwa programy pokazane poniżej, wymieniają łańcuch za pomocą segmentu pamięci dzielonej. Więcej szczegółów
       na temat programów  podano  poniżej.  Na  początku  zademonstrujmy  sesję  powłoki  pokazującą  działanie
       programów.

       W  jednym  oknie  terminala,  uruchamiamy  program  „odczytujący”, który tworzy segment pamięci dzielonej
       Systemu V oraz zestaw  semaforów  Systemu V.  Program  wypisuje  identyfikatory  dzielonych  obiektów,  a
       następnie oczekuje na zmianę wartości przez semafor.

           $ ./svshm_string_read
           shmid = 1114194; semid = 15

       W  drugim  oknie  terminala,  uruchamiamy  program  „zapisujący”.  Przyjmuje  on trzy argumenty w wierszu
       polecenia: identyfikatory: segmentu  pamięci  dzielonej  i  zestawu  semaforów  utworzone  przez  program
       „odczytujący”  oraz  łańcuch. Dołącza on istniejący segment pamięci dzielonej, kopiuje łańcuch do pamięci
       dzielonej i modyfikuje wartość semafora.

           $ ./svshm_string_write 1114194 15 'Witaj świecie!'

       Powracając do terminala, gdzie działa program „odczytujący” widzimy, że  program  przestał  oczekiwać  na
       semafor  i  wypisał  łańcuch,  który  został  skopiowany  do  segmentu  pamięci  dzielonej  przez program
       „zapisujący”:

           Witaj świecie!

   Kod źródłowy: svshm_string.h
       Poniższy plik nagłówkowy jest dołączany przez programy: „odczytujący” i „zapisujący”:

           /* svshm_string.h

              Na licencji GNU General Public License v2 lub późniejszej.
           */
           #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 {                   /* Używane w wywołaniach do semctl() */
               int                 val;
               struct semid_ds     *buf;
               unsigned short      *array;
           #if defined(__linux__)
               struct seminfo      *__buf;
           #endif
           };

           #define MEM_SIZE 4096

           #endif  // include guard (ochr. przed wielokr. przetw.)

   Kod źródłowy programu: svshm_string_read.c
       Program „odczytujący” tworzy segment pamięci dzielonej i zestaw  semaforów,  zawierający  jeden  semafor.
       Następnie dołącza obiekt pamięci dzielonej do swojej przestrzeni adresowej i inicjuje wartość semafora na
       1. Na końcu, oczekuje na przyjęcie przez semafor wartości  0;  wówczas  wypisuje  łańcuch,  który  został
       skopiowany do segmentu pamięci dzielonej przez program „zapisujący”.

           /* svshm_string_read.c

              Na licencji GNU General Public License v2 lub późniejszej.
           */
           #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;

               /* Utworzenie pamięci dzielonej i zestawu semaforów, zawierającego
                  jeden semafor. */

               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");

               /* Dołączenie pamięci dzielonej do naszej przestrzeni adresowej. */

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

               /* Zainicjowanie semafora 0 w zestawie, z wartością 1. */

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

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

               /* Oczekiwanie na przyjęcie przez semafor wartości 0. */

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

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

               /* Wypisanie łańcucha z pamięci dzielonej. */

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

               /* Usunięcie pamięci dzielonej i zestawu semaforów. */

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

               exit(EXIT_SUCCESS);
           }

   Kod źródłowy programu: svshm_string_write.c
       Program  „zapisujący”  przyjmuje  trzy  argumenty  w  wierszu polecenia: identyfikatory: segmentu pamięci
       dzielonej i zestawu semaforów utworzone przez program „odczytujący” oraz łańcuch. Dołącza  on  istniejący
       segment  pamięci  dzielonej  do  swojej  przestrzeni  adresowej i zmniejsza wartość semafora na 0, w celu
       poinformowania programu „odczytującego”, że może on teraz sprawdzić zawartość pamięci dzielonej.

           /* svshm_string_write.c

              Na licencji GNU General Public License v2 lub późniejszej.
           */
           #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, "Użycie: %s shmid semid łańcuch\n", argv[0]);
                   exit(EXIT_FAILURE);
               }

               len = strlen(argv[3]) + 1;  /* +1 aby objąć końcowe '\0' */
               if (len > MEM_SIZE) {
                   fprintf(stderr, "Łańcuch jest zbyt długi!\n");
                   exit(EXIT_FAILURE);
               }

               /* Pobranie ID obiektów z wiersza polecenia. */

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

               /* Dołączenie pamięci dzielonej do naszej przestrzeni adresowej
                  i skopiowanie łańcucha (wraz z końcowym bajtem null) do pamięci. */

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

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

               /* Zmniejszenie semafora do 0. */

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

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

               exit(EXIT_SUCCESS);
           }

ZOBACZ TAKŻE

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

TŁUMACZENIE

       Autorami polskiego tłumaczenia niniejszej strony podręcznika są: Rafał Lewczuk <R.Lewczuk@elka.pw.edu.p>,
       Andrzej  Krzysztofowicz  <ankry@green.mf.pg.gda.pl>,  Robert  Luberda <robert@debian.org> i Michał Kułach
       <michal.kulach@gmail.com>

       Niniejsze tłumaczenie jest wolną dokumentacją. Bliższe informacje  o  warunkach  licencji  można  uzyskać
       zapoznając  się  z  GNU General Public License w wersji 3 ⟨https://www.gnu.org/licenses/gpl-3.0.html⟩ lub
       nowszej. Nie przyjmuje się ŻADNEJ ODPOWIEDZIALNOŚCI.

       Błędy w tłumaczeniu  strony  podręcznika  prosimy  zgłaszać  na  adres  listy  dyskusyjnej  ⟨manpages-pl-
       list@lists.sourceforge.net⟩.