Provided by: manpages-pl-dev_0.7-2_all bug

NAZWA

       msgrcv, msgsnd - przekazywanie komunikatów kolejki Systemu V

SKŁADNIA

       #include <sys/types.h>
       #include <sys/ipc.h>
       #include <sys/msg.h>

       int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

       ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
                      int msgflg);

OPIS

       Wywołań  systemowych  msgsnd()  i   msgrcv()  używa  się  do  -  odpowiednio  -  wysyłania
       komunikatów do kolejki komunikatów i  odbierania  komunikatów  z  kolejki  Systemu V.  Aby
       wysłać   komunikat,   proces  wywołujący  musi  mieć  uprawnienie  do  zapisu  na  kolejce
       komunikatów, a aby odebrać komunikat - uprawnienie do odczytu kolejki.

       Parametr msgp jest wskaźnikiem do zdefiniowanej przez proces wywołujący struktury,  której
       ogólna postać wygląda tak:

           struct msgbuf {
               long mtype;       /* typ wiadomości, musi być > 0 */
               char mtext[1];    /* dane wiadomości */
           };

       Pole  mtext  jest tablicą (lub inna strukturą) o rozmiarze określonym przez msgsz, będącym
       nieujemną  liczbą  całkowitą.  Dozwolone  są   komunikaty   o   zerowej   długości   (tzn.
       niezawierające pola mtext). Wartość pola mtype musi być liczbą ściśle dodatnią, która może
       służyć procesowi odbierającemu komunikaty do filtrowania  kolejki  (zobacz  opis  msgrcv()
       poniżej).

   msgsnd()
       Wywołanie systemowe msgsnd() dołącza kopię komunikatu wskazywanego przez msgp do kolejki o
       identyfikatorze określonym przez msqid.

       Gdy w kolejce  jest  wystarczająco  dużo  miejsca,  to  msgsnd()  natychmiast  kończy  się
       pomyślnie.   (Pojemność   kolejki  określona  jest  w  polu  msg_qbytes  struktury  danych
       stowarzyszonej z kolejką. Podczas tworzenia kolejki polu temu  jest  przypisywana  wartość
       początkowa  wynosząca  MSGMNB bajtów, lecz ograniczenie to może zostać zmienione za pomocą
       msgctl(2)). Kolejka komunikatów jest uważana za pełną w jednym z następujących przypadków:

       * Dodanie nowego komunikatu do kolejki spowoduje, że  suma  bajtów  w  kolejki  przekroczy
         maksymalny rozmiar kolejki (pole msg_qbytes).

       * Dodanie  kolejnego  komunikatu  do  kolejki spowoduje, że całkowita liczba komunikatów w
         kolejce przekroczy maksymalny rozmiar kolejki (pole  msg_qbytes).  To  sprawdzenie  jest
         konieczne  aby  zapobiec  umieszczaniu  w  kolejce  nieograniczonej liczby komunikatów o
         zerowej  długości.  Choć  takie  komunikaty  nie  zawierają  danych,  to  wciąż  zajmują
         (zablokowaną) pamięć jądra.

       Jeśli   w  kolejce  obecna  jest  niewystarczająca  ilość  wolnego  miejsca,  to  domyślne
       zachowaniem msgsnd() jest blokada do momentu uzyskania wolnej przestrzeni. Jeśli w  msgflg
       określono IPC_NOWAIT, to zamiast tego wywołanie zwróci błąd EAGAIN.

       Wstrzymane wywołanie msgsnd() może się także nie powieść, jeżeli:

       * kolejka  zostanie  usunięta z systemu - w tym przypadku wywołanie systemowe zgłosi błąd,
         przypisując zmiennej errno wartość EIDRM;

       * zostanie przechwycony sygnał - wtedy wywołanie to powoduje  przypisanie  zmiennej  errno
         wartości  EINTR;  patrz signal(7) (msgsnd() po przerwaniu przez obsługę sygnału nie jest
         nigdy  automatycznie  restartowane,  niezależnie  od  ustawienia  znacznika   SA_RESTART
         podanego podczas ustanawiania funkcji obsługi sygnału).

       Jeśli  operacja  zakończy  się  pomyślnie,  to struktura danych opisująca kolejkę zostanie
       zmodyfikowana w następujący sposób:

              msg_lspid przypisany zostanie identyfikator procesu wykonującego tę operację.

              msg_qnum zostanie zwiększone o 1.

              msg_stime zostanie przypisany bieżący czas.

   msgrcv()
       Wywołanie systemowe msgrcv usuwa komunikat z kolejki określonej przez msqid i umieszcza go
       w buforze wskazywanym przez parametr msgp.

       Parametr msgsz określa maksymalny rozmiar w bajtach pola mtext struktury wskazywanej przez
       parametr msgp. Jeśli dane komunikatu zajmują więcej bajtów niż msgsz, to wynik  zależy  od
       tego,  czy  w  msgflg przekazano znacznik MSG_NOERROR. Jeżeli podano MSG_NOERROR, to tekst
       komunikatu zostanie obcięty (obcięta część  zostanie  utracona);  jeżeli  MSG_NOERROR  nie
       występuje,  to  komunikat  nie  jest  usuwany  z kolejki, a wywołanie systemowe kończy się
       błędem, zwracając wartość -1 i ustawiając errno na E2BIG.

       Jeżeli podano MSG_COPY w msgflg (zob. poniżej), parametr msgtyp określa rodzaj  komunikatu
       w następujący sposób:

       * Jeśli msgtyp jest równy 0, to czytany jest pierwszy komunikat z kolejki.

       * Jeśli  msgtyp ma wartość większą niż 0, to z kolejki odczytywany jest pierwszy komunikat
         o typie msgtyp, chyba że w parametrze msgflg zostanie ustawiony znacznik MSG_EXCEPT,  co
         spowoduje, że z kolejki zostanie odczytany pierwszy komunikat o typie różnym od msgtyp.

       * Jeśli  msgtyp  ma  wartość  mniejszą  niż  0,  to  z kolejki zostanie odczytany pierwszy
         komunikat o najniższym numerze typu, mniejszym lub równym wartości bezwzględnej msgtyp.

       Parametr msgflg jest maską  bitową,  utworzoną  jako  alternatywa  (OR)  zera  lub  więcej
       następujących znaczników:

       IPC_NOWAIT
              Nie  wstrzymuje  pracy  procesu,  jeśli  w kolejce nie ma komunikatów odpowiedniego
              typu. Wywołanie systemowe zwróci wówczas błąd, przypisując zmiennej  errno  wartość
              ENOMSG.

       MSG_COPY (od Linuksa 3.8)
              Nieniszcząco  pobiega  kopię  komunikatu  w  pozycję porządkową w kolejce określoną
              przez msgtyp (komunikaty są pomyślane do numerowania od 0).

              Tę flagę należy podać w połączeniu z IPC_NOWAIT, co skutkuje tym, że jeśli w  danej
              pozycji  nie ma dostępnego komunikatu, to wywołanie natychmiast zwraca błąd ENOMSG.
              Ponieważ zmienia to znaczenie msgtyp w różny  sposób,  MSG_COPY  i  MSG_EXCEPT  nie
              mogą być podane równocześnie w msgflg.

              Flaga  MSG_COPY  została dodana dla zaimplementowania w jądrze funkcji przywracania
              do punktu kontrolnego (checkpoint-restore) i jest dostępna wyłącznie  wtedy,  jeśli
              jądro zbudowano z opcją CONFIG_CHECKPOINT_RESTORE.

       MSG_EXCEPT
              Użyte  z parametrem msgtyp większym od 0, spowoduje odczytanie z kolejki pierwszego
              komunikatu o typie różnym od msgtyp.

       MSG_NOERROR
              Spowoduje obcięcie komunikatu, jeśli jego dane są dłuższe niż msgsz bajtów.

       Jeśli w kolejce nie ma komunikatu spełniającego te  warunki,  a  znacznik  IPC_NOWAIT  nie
       został  ustawiony  w  msgflg,  to  proces  zostanie wstrzymany, dopóki nie nastąpi jedno z
       poniższych zdarzeń:

       * Komunikat odpowiedniego typu zostanie umieszczony w kolejce.

       * Kolejka zostanie usunięta z systemu. W tym przypadku wywołanie  systemowe  zgłosi  błąd,
         przypisując zmiennej errno wartość EIDRM.

       * Proces  wywołujący przechwytuje sygnał. W takim przypadku wywołanie systemowe kończy się
         niepowodzeniem, ustawiając errno na EINTR. (msgrcv() po przerwaniu przez obsługę sygnału
         nie   jest   nigdy  automatycznie  restartowane,  niezależnie  od  ustawienia  znacznika
         SA_RESTART podczas ustanawiania funkcji obsługi sygnału).

       Jeśli operacja zakończy się pomyślnie, to  struktura  danych  opisująca  kolejkę  zostanie
       zmodyfikowana w następujący sposób:

              msg_lrpid przyjmie wartość równą identyfikatorowi wołającego procesu

              msg_qnum zostanie zmniejszone o 1.

              msg_rtime zostanie przypisany bieżący czas.

WARTOŚĆ ZWRACANA

       W  przypadku  niepowodzenia  obydwa wywołania zwrócą -1 i przypiszą zmiennej errno wartość
       określającą rodzaj błędu. W przeciwnym przypadku, msgsnd() zwróci  0,  a  msgrvc()  zwróci
       liczbę bajtów skopiowanych z kolejki do tablicy mtext.

BŁĘDY

       Jeśli  wywołanie  msgsnd() się nie powiedzie, to zmienna errno przyjmie jedną z poniższych
       wartości:

       EACCES Proces wywołujący nie ma prawa do zapisu danej  kolejki  komunikatów,  ani  nie  ma
              ustawionego atrybutu  CAP_IPC_OWNER.

       EAGAIN Komunikat  nie  może  zostać  wysłany  z powodu ograniczenia msg_qbytes dotyczącego
              kolejki, a nie przekazano znacznika IPC_NOWAIT w parametrze mgsflg.

       EFAULT Adres wskazywany przez msgp jest niedostępny.

       EIDRM  Kolejka komunikatów została usunięta.

       EINTR  Podczas oczekiwania na zwolnienie miejsca w kolejce, proces przechwycił sygnał.

       EINVAL Niewłaściwa wartość msqid, mtype (powinna być  dodatnia)  lub  msgsz  (powinna  być
              większa lub równa 0 i mniejsza lub równa MSGMAX).

       ENOMEM Brak w systemie pamięci na skopiowanie komunikatu wskazywanego przez msgp.

       Jeśli  wywołanie msgrcv() się nie powiedzie, to zmiennej errno zostanie przypisana jedna z
       poniższych wartości:

       E2BIG  Tekst komunikatu jest dłuższy niż msgsz i nie  ustawiono  znacznika  MSG_NOERROR  w
              parametrze msgflg.

       EACCES Proces  wywołujący  nie  ma  prawa do odczytu danej kolejki komunikatów, ani nie ma
              ustawionego atrybutu CAP_IPC_OWNER.

       EFAULT Adres wskazywany przez msgp jest niedostępny.

       EIDRM  Proces oczekiwał na komunikat, ale w międzyczasie kolejka została usunięta.

       EINTR  Proces przechwycił  sygnał  podczas  oczekiwania  na  odebranie  komunikatu;  patrz
              signal(7).

       EINVAL msqid był niepoprawny lub msgsz był mniejszy od 0.

       EINVAL (od Linuksa 3.14)
              msgflg określono jako MSG_COPY, ale nie IPC_NOWAIT.

       EINVAL (od Linuksa 3.14)
              msgflg określono jako MSG_COPY i MSG_EXCEPT.

       ENOMSG Znacznik  IPC_NOWAIT  został  przekazany  w msgflg, ale w kolejce nie ma komunikatu
              żądanego typu.

       ENOMSG IPC_NOWAIT i MSG_COPY zostały określone w  msgflg,  a  kolejka  zawiera  mniej  niż
              msgtyp komunikatów.

       ENOSYS (od Linuksa 3.8)
              MSG_COPY  zostało  określone  w  msgflg,  a  jądro zostało skonfigurowane bez opcji
              CONFIG_CHECKPOINT_RESTORE.

ZGODNE Z

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

       Znaczniki MSG_EXCEPT i MSG_COPY są charakterystyczne  dla  Linuksa,  ich  definicje  można
       pobrać przez zdefiniowane makra testującego funkcje _GNU_SOURCE.

UWAGI

       Dołączenie  <sys/types.h>  i  <sys/ipc.h>  nie jest wymagane na Linuksie ani przez żadną z
       wersji  POSIX.  Jednak  niektóre  stare  implementacje  wymagają  dołączenia  tych  plików
       nagłówkowych,  SVID również dokumentuje ich dołączenie. Aplikacje które mają być przenośne
       na tego typu stare systemy mogą wymagać dołączenia omawianych plików nagłówkowych.

       Parametr msgp jest deklarowany jako struct msgbuf * w glibc 2.0 i glibc 2.1. W glibc 2.2 i
       późniejszych jest deklarowany jako void *, zgodnie z wymaganiami SUSv2 i SUSv3.

       Wywołania msgsnd() dotyczą następujące ograniczenia systemowe:

       MSGMAX Maksymalny  rozmiar  tekstu  komunikatu, w bajtach: (domyślna wartość: 8192 bajty).
              Pod  Linuksem  ten   limit   można   odczytać   i   modyfikować,   używając   pliku
              /proc/sys/kernel/msgmax.

       MSGMNB Maksymalna  liczba  bajtów  która  może  być przechowywana  w  kolejce  komunikatów
              (domyślna wartość: 16384 bajtów). Pod Linuksem można ten limit odczytać i  zmienić,
              używając  pliku /proc/sys/kernel/msgmnb. Proces uprzywilejowany (w Linuksie: proces
              z przywilejem CAP_SYS_RESOURCE) może zwiększyć  rozmiar  kolejki  komunikatów  poza
              MSGMNB za pomocą operacji IPC_SET msgctl(2).

       W   tej   implementacji   nie  ma  jawnego  systemowego  ograniczenia  liczby  komunikatów
       przechowywanych w kolejce (MSGTQL) i na rozmiar  obszaru  (w  bajtach)  przeznaczonego  na
       komunikaty (MSGPOOL).

BŁĘDY

       W  Linuksie  3.13  i wcześniejszych, jeśli msgrcv() było wywołane ze znacznikiem MSG_COPY,
       lecz bez IPC_NOWAIT, a kolejka komunikatów zawierała  mniej  niż  msgtyp  komunikatów,  to
       wywołanie było zablokowane aż do zapisania kolejnego komunikatu do kolejki. W tym momencie
       wywołanie zwracało kopię komunikatu bez względu na to czy komunikat był w pozycji  msgtyp.
       Błąd ten został naprawiony w jądrze Linux 3.14.

       Podanie zarówno w msgflg zarówno MSG_COPY jak i MSC_EXCEPT jest błędem logicznym (ponieważ
       oba te znaczniki wymagają innej interpretacji msgtyp). W Linuksie 3.13 błąd  ten  nie  był
       diagnozowany przez msgsrv(). Zostało to naprawione w jądrze Linux 3.14.

PRZYKŁAD

       Program poniżej demonstruje użycie msgsnd() i msgrcv().

       Przykładowy  program  jest  początkowo  uruchomiony  z  opcją  -s, aby wysłać komunikat, a
       następnie ponownie z opcją -r, aby otrzymać komunikat.

       Poniższa sesja powłoki pokazuje przykładowy przebieg programu:

           $ ./a.out -s
           sent: a message at Wed Mar  4 16:25:45 2015

           $ ./a.out -r
           message received: a message at Wed Mar  4 16:25:45 2015

   Źródło programu

       #include <stdio.h>
       #include <stdlib.h>
       #include <string.h>
       #include <time.h>
       #include <unistd.h>
       #include <errno.h>
       #include <sys/types.h>
       #include <sys/ipc.h>
       #include <sys/msg.h>

       struct msgbuf {
           long mtype;
           char mtext[80];
       };

       static void
       usage(char *prog_name, char *msg)
       {
           if (msg != NULL)
               fputs(msg, stderr);

           fprintf(stderr, "Uzycie: %s [opcje]\n", nazwa_prog);
           fprintf(stderr, "Opcje:\n");
           fprintf(stderr, "-s        wysyła komunikat przez msgsnd()\n");
           fprintf(stderr, "-r        odczytuje komunikat przez msgrcv()\n");
           fprintf(stderr, "-t        typ komunikatu (domyślnie: 1)\n");
           fprintf(stderr, "-k        klucz kolejki komunikatu (domyślnie: 1234)\n");
           exit(EXIT_FAILURE);
       }

       static void
       send_msg(int qid, int msgtype)
       {
           struct msgbuf msg;
           time_t t;

           msg.mtype = msgtype;

           time(&t);
           snprintf(msg.mtext, sizeof(msg.mtext), "wiadomość o %s",
                   ctime(&t));

           if (msgsnd(qid, (void *) &msg, sizeof(msg.mtext),
                       IPC_NOWAIT) == -1) {
               perror("błąd msgsnd");
               exit(EXIT_FAILURE);
           }
           printf("wysłano: %s\n", msg.mtext);
       }

       static void
       get_msg(int qid, int msgtype)
       {
           struct msgbuf msg;

           if (msgrcv(qid, (void *) &msg, sizeof(msg.mtext), msgtype,
                      MSG_NOERROR | IPC_NOWAIT) == -1) {
               if (errno != ENOMSG) {
                   perror("msgrcv");
                   exit(EXIT_FAILURE);
               }
               printf("Brak komunikatu dostępnego dla msgrcv()\n");
           } else
               printf("komunikat otrzymano: %s\n", msg.mtext);
       }

       int
       main(int argc, char *argv[])
       {
           int qid, opt;
           int mode = 0;               /* 1 = wysłanie, 2 = otrzymanie */
           int msgtype = 1;
           int msgkey = 1234;

           while ((opt = getopt(argc, argv, "srt:k:")) != -1) {
               switch (opt) {
               case 's':
                   mode = 1;
                   break;
               case 'r':
                   mode = 2;
                   break;
               case 't':
                   msgtype = atoi(optarg);
                   if (msgtype <= 0)
                       usage(argv[0], "opcja -t musi być większa od 0\n");
                   break;
               case 'k':
                   msgkey = atoi(optarg);
                   break;
               default:
                   usage(argv[0], "Nierozpoznana opcja\n");
               }
           }

           if (mode == 0)
               usage(argv[0], "musi być opcją -s albo -r\n");

           qid = msgget(msgkey, IPC_CREAT | 0666);

           if (qid == -1) {
               perror("msgget");
               exit(EXIT_FAILURE);
           }

           if (mode == 2)
               get_msg(qid, msgtype);
           else
               send_msg(qid, msgtype);

           exit(EXIT_SUCCESS);
       }

ZOBACZ TAKŻE

       msgctl(2), msgget(2), capabilities(7), mq_overview(7), svipc(7)

O STRONIE

       Angielska wersja tej strony  pochodzi  z  wydania  4.07  projektu  Linux  man-pages.  Opis
       projektu,  informacje  dotyczące  zgłaszania błędów, oraz najnowszą wersję oryginału można
       znaleźć pod adresem https://www.kernel.org/doc/man-pages/.

TŁUMACZENIE

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

       Polskie tłumaczenie jest częścią projektu manpages-pl; uwagi, pomoc, zgłaszanie błędów  na
       stronie   http://sourceforge.net/projects/manpages-pl/.   Jest   zgodne   z  wersją   4.07
       oryginału.