Provided by: manpages-pl-dev_20060617-1_all bug

NAZWA

       select,  pselect,  FD_CLR,  FD_ISSET,  FD_SET,  FD_ZERO - synchroniczne
       zwielokratnianie we/wy

SKŁADNIA

       /* Zgodnie z POSIX 1003.1-2001 */
       #include <sys/select.h>

       /* Zgodnie z wcześniejszymi standardami */
       #include <sys/time.h>
       #include <sys/types.h>
       #include <unistd.h>

       int select(int nfds, fd_set *readfds, fd_set *writefds,
                  fd_set *exceptfds, struct timeval *timeout);

       void FD_CLR(int fd, fd_set *set);
       int FD_ISSET(int fd, fd_set *set);
       void FD_SET(int fd, fd_set *set);
       void FD_ZERO(fd_set *set);

       #define _XOPEN_SOURCE 600
       #include <sys/select.h>

       int pselect(int nfds, fd_set *readfds, fd_set *writefds,
                   fd_set *exceptfds, const struct timespec *timeout,
                   const sigset_t *sigmask);

OPIS

       select()  i  pselect()  umożliwiają  programowi   monitorowanie   wielu
       deskryptorów  plików  i  oczekiwanie  aż  jeden lub więcej deskryptorów
       będzie "gotowy" na wykonanie pewnej klasy operacji wejścia/wyjścia (np.
       możliwy  odczyt).  Deskryptor  pliku  jest  uważany  za  gotowy, jeżeli
       możliwe  jest  wykonanie  odpowiadającej  operacji  (np.  read(2))  bez
       blokowania.

       Funkcjonalność  funkcji  select()  i  pselect()  jest identyczna, jeśli
       pominąć trzy różnice:

       (i)    Funkcja select() używa czasu parametru timeout, który jest  typu
              struct  timeval  (z  sekundami  i  mikrosekundami),  podczas gdy
              pselect()  używa   typu   struct   timespec   (z   sekundami   i
              nanosekundami).

       (ii)   Funkcja   select()   może  aktualizować  parametr  timeout,  aby
              wskazać, jak dużo czasu minęło. Funkcja  pselect()  nie  zmienia
              tego parametru.

       (iii)  Funkcja  select()  nie  przykmuje  parametru sigmask i zachowuje
              się, jak pselect() wywołane z NULL sigmask.

       Podglądane są  trzy  niezależne  zestawy  deskryptorów.  Te,  które  są
       wymienione  w  readfds będą obserwowane w celu dowiedzenia się, czy nie
       ma  tam  jakichś  znaków  dostępnych  do  czytania   (dokładniej,   aby
       dowiedzieć  się,  czy read nie spowoduje zablokowania, deskryptor pliku
       jest również przygotowany na koniec pliku).  Deskryptory  wymienione  w
       writefds  będą  obserwowane  w  celu  dowiedzenia  się,  czy  zapis nie
       spowoduje  blokady,  a  deskryptory   wymienione   w   exceptfds   będą
       obserwowane  w  celu  dowiedzenia się, czy nie ma na nich wyjątku. Przy
       wyjściu, zbiory te są modyfikowane,  wskazując,  które  z  deskryptorów
       zmieniły  status.  Każdy z tych trzech zbiorów deskryptorów plików może
       być przekazany jako NULL, jeżeli dla żadnego deskryptora  pliku  na  ma
       potrzeby obserwowania odpowiedniej klasy zdarzeń.

       Do  obsługi tych zbiorów udostępnione są cztery makra: FD_ZERO() czyści
       zbiór.  FD_SET()  i  FD_CLR()  dodają  lub  usuwają  ze  zbioru  podany
       deskryptor.  FD_ISSET()  sprawdza,  czy deskryptor jest częścią zbioru.
       Jest to przydatne po zakończeniu select().

       nfds jest najwyższym numerem deskryptora z  wszystkich  trzech  zbiorów
       plus 1.

       timeout  jest  górną  granicą  czasu,  który upłynie przed zakończeniem
       działania  funkcji  select().  Gdy  przyjmie  wartość  zero,   select()
       zakończy  pracę  natychmiast. (Jest to przydatne w uwspólnianiu). Jeśli
       timeout jest równe NULL (brak czasu  przeterminowania),  select()  może
       blokować w nieskończoność.

       sigmask  jest  wskaźnikiem  do  maski sygnałów (zobacz sigprocmask(2)).
       Jeśli nie jest równe NULL,  to  pselect()  najpierw  zastępuje  bieżącą
       maskę  sygnałów  maską  wskazywaną  przez sigmask, a następnie wywołuje
       funkcję `select' i ponownie odtwarza oryginalną maskę sygnałów.

       Poza  różnicą  w  precyzji  argumentu  timeout,  następujące  wywołanie
       pselect():

           ready = pselect(nfds, &readfds, &writefds, &exceptfds,
                           timeout, &sigmask);

       jest odpowiednikiem niepodzielnego wykonania następujących funkcji:

           sigset_t origmask;

           sigprocmask(SIG_SETMASK, &sigmask, &origmask);
           ready = select(nfds, &readfds, &writefds, &exceptfds, timeout);
           sigprocmask(SIG_SETMASK, &origmask, NULL);

       Idea  pselect()  polega  na tym, że gdy chce się oczekiwać na zdarzenie
       będące sygnałem lub czymś na deskryptorze pliku, potrzebny jest atomowy
       test zapobiegający sytuacjom wyścigu. (Przypuśćmy, że procedura obsługi
       sygnału ustawia globalny znacznik i  kończy  działanie.  Wówczas,  test
       tego  znacznika globalnego, po którym następuje wywołanie select() może
       wisieć w nieskończoność, gdyby sygnał przybył  natychmiast  po  teście,
       ale  przed  wywołaniem.  Inaczej  mówiąc, pselect zezwala na, najpierw,
       zablokowanie sygnałów, następnie obsłużenie dostarczonych sygnałów, aby
       wreszcie wywołać pselect() z pożądanym sigmask, unikając wyścigu).

   Przeterminowanie
       Struktury  czasu,  których to dotyczy, są zdefiniowane w <sys/time.h> i
       wyglądają następująco

         struct timeval {
             long    tv_sec;         /* sekundy */
             long    tv_usec;        /* mikrosekundy */
         };

       i

         struct timespec {
             long    tv_sec;         /* sekundy */
             long    tv_nsec;        /* nanosekundy */
         };

       (Jednakże odnośnie wersji POSIX 1003.1-2001 zobacz poniżej).

       Niektóre  programy  wywołują  select()  z  wszystkimi  trzema  zbiorami
       pustymi,  z  n  równym  zeru  i  niezerowym  timeout.  Jest  to całkiem
       przenośny sposób pauzowania z dokładnością subsekundową.

       Pod Linuksem funkcja select() modyfikuje  timeout,  aby  odzwierciedlić
       ilość  nieprzespanego  czasu;  większość  innych implementacji tego nie
       robi (POSIX.1-2001 dopuszcza oba te zachowania). Powoduje to  problemy,
       zarówno  gdy kod linuksowy odczytujący timeout zostanie przeniesiony na
       inne systemy operacyjne, jak i  gdy  kod  przeniesiony  pod  Linuksa  z
       innych  systemów  używa  ponownie struct timeval dla wielu select()ów w
       pętli,  bez  powtórnej  inicjacji.  Należy   traktować   timeout   jako
       niezdefiniowany po zakończeniu select().

WARTOŚĆ ZWRACANA

       Po   pomyślnym   zakończeniu,  select()  i  pselect()  zwracają  liczbę
       deskryptorów w zbiorach deskryptorów (to jest  całkowitę  liczbę  bitów
       ustawioną  w  readfds, writefds, exceptfds). Może ona być zerowa, jeśli
       nastąpi przeterminowanie, nim coś ciekawego  się  zdarzy.  Po  błędzie,
       zwracane  jest  -1 i odpowiednio ustawiane errno; zbiory deskryptorów i
       timeout stają się niezdefiniowane,  więc  nie  należy  polegać  na  ich
       zawartości.

BŁĘDY

       EBADF  W jednym ze zbiorów przekazano niepoprawny deskryptor pliku (Być
              może deskryptor ten został już zamknięty  lub  wystąpił  na  nim
              inny błąd).

       EINTR  Przechwycono sygnał.

       EINVAL nfds jest ujemne lub wartość timeout jest nieprawidłowa.

       ENOMEM nie można było przydzielić pamięci dla wewnętrznych tablic.

PRZYKŁAD

       #include <stdio.h>
       #include <sys/time.h>
       #include <sys/types.h>
       #include <unistd.h>

       int
       main(void) {
           fd_set rfds;
           struct timeval tv;
           int retval;

           /* Obserwacja stdin (fd 0) i sprawdzanie kiedy ma wejście. */
           FD_ZERO(&rfds);
           FD_SET(0, &rfds);

           /* Czekanie nie dłużej niż 5 sekund. */
           tv.tv_sec = 5;
           tv.tv_usec = 0;

           retval = select(1, &rfds, NULL, NULL, &tv);
           /* Nie należy już polegać na wartości tv! */

           if (retval == -1)
               perror("select()");
           else if (retval)
               printf("Dane są już dostępne.\n");
               /* FD_ISSET(0, &rfds) będzie prawdziwy. */
           else
               printf("Brak danych w ciągu 5 sekund.\n");

           return 0;
       }

ZGODNE Z

       BSD  4.4  (funkcja  select()  pojawiła  się  pierwotnie  w  BSD 4.2). W
       ogólności przenośne  do/z  systemów  nie-BSD  wspierających  sklonowaną
       warstwę  gniazd  BSD  (włączając  warianty Systemu V). Jednakże, należy
       zauważyć, że warianty Systemu V zasadniczo  ustawiają  zmienną  timeout
       przed zakończeniem, ale wariant BSD tego nie robi.

       pselect()  jest  zdefiniowany  w  IEEE  Std 1003.1g-2000 (POSIX.1g) i w
       POSIX 1003.1-2001.

UWAGI

       fd_set jest buforem o stałym rozmiarze. Wykonanie FD_CLR() lub FD_SET()
       z  ujemną  wartością  fd  albo z wartością większą lub równą FD_SETSIZE
       spowoduje zachowanie niezdefiniowane. Ponadto POSIX wymaga, by  fd  był
       prawidłowym deskryptorem pliku.

       Odnośnie używanych typów, klasyczna sytuacja polega na tym, że oba pola
       struktury timeval są typu long (jak pokazano powyżej), a sama struktura
       jest  zdefiniowana  w  <sys/time.h>.  W POSIX 1003.1-2001 sytuacja jest
       następująca

              struct timeval {
                  time_t         tv_sec;     /* sekundy */
                  suseconds_t    tv_usec;    /* mikrosekundy */
              };

       przy czym struktura jest zdefiniowana w <sys/select.h>, a typy time_t i
       suseconds_t zdefiniowano w <sys/types.h>.

       Odnośnie  do  prototypów,  klasyczna  sytuacja  polega  na  tym, że dla
       select() należy włączyć <time.h>. Sytuacja z POSIX  1003.1-2001  polega
       na  tym,  że  dla  select()  i pselect() należy włączyć <sys/select.h>.
       libc4 i libc5 nie zawierają pliku nagłówkowego <sys/select.h>; w  glibc
       2.0 i późniejszymi ten plik nagłówkowy istnieje. W glibc 2.0 udostępnia
       on bezwarunkowo  błędny  prototyp  dla  pselect().  W  glibc  2.1-2.2.1
       udostępnia  on pselect(), jeżeli zdefiniowane jest _GNU_SOURCE. W glibc
       2.2.2-2.2.4   udostępnia   go   natomiast,   gdy   zdefiniowane    jest
       _XOPEN_SOURCE  i ma wartość 600 lub większą. Niewątpliwie, począwszy od
       POSIX 1003.1-2001 plik ten powinien udostępniać prototyp standardowo.

WERSJE

       pselect() został dodany do jadra Linuksa 2.6.16.

       Wcześniej  pselect()  był  emulowany  w  glibc  (patrz  również   BŁĘDY
       IMPLEMENTACJI).

UWAGI LINUKSOWE

       Wywołanie systemowa pselect() pod Linuksem modyfikuje argument timeout.
       Jednakże funkcja glibc ukrywa to zachowanie przez użycie dla  argumentu
       timeout   lokalnej  zmiennej,  która  jest  przekazywana  do  wywołania
       systemowego. Dlatego pselect() z glibc nie zmienia  argumentu  timeout,
       co jest zachowaniem wymaganym przez POSIX.1-2001.

BŁĘDY IMPLEMENTACJI

       Glibc 2.0 dostarczała wersję pselect(), która nie przyjmowała argumentu
       sigmask.

       Od  wersji  2.1  glibc  dostarczał  emulację  pselect(),   która   była
       zaimplementowana  przy  użyciu sigprocmask(2) i select(). Implementacja
       ta pozostaje  podatna  na  wiele  błędów  wyścigów  (race  conditions),
       których uniknięcie stanowiło ideę funkcji pselect(). W systemach, które
       nie mają pselect() niezawodne (i  bardziej  przenośne)  przechwytywanie
       sygnałów  można  osiągnąć,  używając  triku  potoku  do  siebie  (gdzie
       procedura obsługi sygnału zapisuje bajt do potoku, którego drugi koniec
       jest monitorowany przez select() w głównym programie).

       Pod  Linuksem  select()  może raportować deskryptory plików gniazd jako
       "dostępne  do  czytania",  podczas   gdy   kolejne   czytania   zostaną
       zablokowane.  Może to się zdarzyć na przykład wtedy, gdy dane nadeszły,
       ale podczas sprawdzania okazało się,  że  mają  złą  sumę  kontrolną  i
       zostały  odrzucone.  Mogą  wystąpić  także  inne  sytuacje,  w  których
       deskryptor pliku jest błędnie raportowany jako gotowy. Dlatego używanie
       O_NONBLOCK  na  gniazdach,  które  nie  powinny  się  blokować może być
       bezpieczniejsze.

ZOBACZ TAKŻE

       Samouczek z dyskusją i przykładami znajduje się w select_tut(2).

       Rzeczy w nieokreślony sposób powiązane z tym można znaleźć w accept(2),
       connect(2),   poll(2),   read(2),   recv(2),  send(2),  sigprocmask(2),
       write(2), epoll(7), feature_test_macros(7)